mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									07037db5d4
								
							
						
					
					
						commit
						e2c0cdfba7
					
				
					 27 changed files with 1687 additions and 0 deletions
				
			
		
							
								
								
									
										26
									
								
								arch/riscv/include/asm/mmu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								arch/riscv/include/asm/mmu.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										118
									
								
								arch/riscv/include/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								arch/riscv/include/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										102
									
								
								arch/riscv/include/asm/syscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								arch/riscv/include/asm/syscall.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										16
									
								
								arch/riscv/include/asm/unistd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								arch/riscv/include/asm/unistd.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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>
 | 
			
		||||
							
								
								
									
										41
									
								
								arch/riscv/include/asm/vdso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								arch/riscv/include/asm/vdso.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										27
									
								
								arch/riscv/include/uapi/asm/Kbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/riscv/include/uapi/asm/Kbuild
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										24
									
								
								arch/riscv/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										25
									
								
								arch/riscv/include/uapi/asm/bitsperlong.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/riscv/include/uapi/asm/bitsperlong.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										23
									
								
								arch/riscv/include/uapi/asm/byteorder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								arch/riscv/include/uapi/asm/byteorder.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										83
									
								
								arch/riscv/include/uapi/asm/elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								arch/riscv/include/uapi/asm/elf.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										36
									
								
								arch/riscv/include/uapi/asm/hwcap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								arch/riscv/include/uapi/asm/hwcap.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										90
									
								
								arch/riscv/include/uapi/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								arch/riscv/include/uapi/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										30
									
								
								arch/riscv/include/uapi/asm/sigcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								arch/riscv/include/uapi/asm/sigcontext.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										24
									
								
								arch/riscv/include/uapi/asm/siginfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/include/uapi/asm/siginfo.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										45
									
								
								arch/riscv/include/uapi/asm/ucontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								arch/riscv/include/uapi/asm/ucontext.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										61
									
								
								arch/riscv/kernel/cpufeature.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								arch/riscv/kernel/cpufeature.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										217
									
								
								arch/riscv/kernel/module.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								arch/riscv/kernel/module.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								arch/riscv/kernel/ptrace.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								arch/riscv/kernel/ptrace.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								arch/riscv/kernel/riscv_ksyms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								arch/riscv/kernel/riscv_ksyms.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
							
								
								
									
										292
									
								
								arch/riscv/kernel/signal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								arch/riscv/kernel/signal.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								arch/riscv/kernel/sys_riscv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								arch/riscv/kernel/sys_riscv.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
							
								
								
									
										25
									
								
								arch/riscv/kernel/syscall_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/riscv/kernel/syscall_table.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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>
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										2
									
								
								arch/riscv/kernel/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								arch/riscv/kernel/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
vdso.lds
 | 
			
		||||
*.tmp
 | 
			
		||||
							
								
								
									
										63
									
								
								arch/riscv/kernel/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								arch/riscv/kernel/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										24
									
								
								arch/riscv/kernel/vdso/rt_sigreturn.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/kernel/vdso/rt_sigreturn.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
							
								
								
									
										27
									
								
								arch/riscv/kernel/vdso/vdso.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/riscv/kernel/vdso/vdso.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										77
									
								
								arch/riscv/kernel/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								arch/riscv/kernel/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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: *;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in a new issue