2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 18:07:57 +00:00

compel: add riscv64 support

Co-authored-by: Yixue Zhao <felicitia2010@gmail.com>
Co-authored-by: stove <stove@rivosinc.com>
Signed-off-by: Haorong Lu <ancientmodern4@gmail.com>
---
- rebased
- added a membarrier() to syscall table (fix authored by Cryolitia PukNgae)
Signed-off-by: PukNgae Cryolitia <Cryolitia@gmail.com>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
This commit is contained in:
Haorong Lu 2023-08-01 11:58:26 -07:00 committed by Andrei Vagin
parent 0d2d23b6d0
commit 7fd95a509d
31 changed files with 1141 additions and 3 deletions

View File

@ -19,7 +19,7 @@ endif
# #
# Supported Architectures # Supported Architectures
ifneq ($(filter-out x86 arm aarch64 ppc64 s390 mips loongarch64,$(ARCH)),) ifneq ($(filter-out x86 arm aarch64 ppc64 s390 mips loongarch64 riscv64,$(ARCH)),)
$(error "The architecture $(ARCH) isn't supported") $(error "The architecture $(ARCH) isn't supported")
endif endif
@ -84,6 +84,10 @@ ifeq ($(ARCH),loongarch64)
DEFINES := -DCONFIG_LOONGARCH64 DEFINES := -DCONFIG_LOONGARCH64
endif endif
ifeq ($(ARCH),riscv64)
DEFINES := -DCONFIG_RISCV64
endif
# #
# CFLAGS_PIE: # CFLAGS_PIE:
# #

View File

@ -32,8 +32,8 @@ ifeq ($(ARCH),x86)
lib-y += arch/$(ARCH)/src/lib/thread_area.o lib-y += arch/$(ARCH)/src/lib/thread_area.o
endif endif
# handle_elf() has no support of ELF relocations on ARM (yet?) # handle_elf() has no support of ELF relocations on ARM and RISCV64 (yet?)
ifneq ($(filter arm aarch64 loongarch64,$(ARCH)),) ifneq ($(filter arm aarch64 loongarch64 riscv64,$(ARCH)),)
CFLAGS += -DNO_RELOCS CFLAGS += -DNO_RELOCS
HOSTCFLAGS += -DNO_RELOCS HOSTCFLAGS += -DNO_RELOCS
endif endif

View File

@ -0,0 +1,35 @@
#ifndef __ASM_PROLOGUE_H__
#define __ASM_PROLOGUE_H__
#ifndef __ASSEMBLY__
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define sys_recv(sockfd, ubuf, size, flags) sys_recvfrom(sockfd, ubuf, size, flags, NULL, NULL)
typedef struct prologue_init_args {
struct sockaddr_un ctl_sock_addr;
unsigned int ctl_sock_addr_len;
unsigned int arg_s;
void *arg_p;
void *sigframe;
} prologue_init_args_t;
#endif /* __ASSEMBLY__ */
/*
* Reserve enough space for sigframe.
*
* FIXME It is rather should be taken from sigframe header.
*/
#define PROLOGUE_SGFRAME_SIZE 4096
#define PROLOGUE_INIT_ARGS_SIZE 1024
#endif /* __ASM_PROLOGUE_H__ */

View File

@ -0,0 +1,28 @@
#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__
#define COMPEL_ARCH_SYSCALL_TYPES_H__
#define SA_RESTORER 0x04000000
typedef void rt_signalfn_t(int, siginfo_t *, void *);
typedef rt_signalfn_t *rt_sighandler_t;
typedef void rt_restorefn_t(void);
typedef rt_restorefn_t *rt_sigrestore_t;
#define _KNSIG 64 // number of signals
#define _NSIG_BPW 64 // number of signals per word
#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW)
typedef struct {
unsigned long sig[_KNSIG_WORDS];
} k_rtsigset_t;
typedef struct {
rt_sighandler_t rt_sa_handler;
unsigned long rt_sa_flags;
rt_sigrestore_t rt_sa_restorer;
k_rtsigset_t rt_sa_mask;
} rt_sigaction_t;
#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */

View File

@ -0,0 +1,4 @@
#ifndef __COMPEL_ARCH_FEATURES_H
#define __COMPEL_ARCH_FEATURES_H
#endif /* __COMPEL_ARCH_FEATURES_H */

View File

@ -0,0 +1,7 @@
#include "common/asm/linkage.h"
.section .head.text, "ax"
ENTRY(__export_parasite_head_start)
jal parasite_service
ebreak
END(__export_parasite_head_start)

View File

@ -0,0 +1,59 @@
ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/
asflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/
sys-types := $(obj)/include/uapi/std/syscall-types.h
sys-codes := $(obj)/include/uapi/std/syscall-codes.h
sys-proto := $(obj)/include/uapi/std/syscall.h
sys-def := $(PLUGIN_ARCH_DIR)/std/syscalls/syscall.def
sys-asm-common-name := std/syscalls/syscall-common.S
sys-asm-common := $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name)
sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h
sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c
sys-gen := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-syscalls.pl
sys-gen-tbl := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-sys-exec-tbl.pl
sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S
std-lib-y += $(sys-asm:.S=).o
ifeq ($(ARCH),arm)
arch_bits := 32
else
arch_bits := 64
endif
sys-exec-tbl := sys-exec-tbl.c
$(sys-asm) $(sys-types) $(sys-codes) $(sys-proto): $(sys-gen) $(sys-def) $(sys-asm-common) $(sys-asm-types)
$(E) " GEN " $@
$(Q) perl \
$(sys-gen) \
$(sys-def) \
$(sys-codes) \
$(sys-proto) \
$(sys-asm) \
$(sys-asm-common-name) \
$(sys-types) \
$(arch_bits)
$(sys-asm:.S=).o: $(sys-asm)
$(sys-exec-tbl): $(sys-gen-tbl) $(sys-def)
$(E) " GEN " $@
$(Q) perl \
$(sys-gen-tbl) \
$(sys-def) \
$(sys-exec-tbl) \
$(arch_bits)
$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h
$(call msg-gen, $@)
$(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types)
$(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.S $(obj)/include/uapi/std/syscall-aux.S
$(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.h $(obj)/include/uapi/std/syscall-aux.h
std-headers-deps += $(sys-asm) $(sys-codes) $(sys-proto) $(sys-asm-types) $(sys-codes)
mrproper-y += $(std-headers-deps)
mrproper-y += $(obj)/include/uapi/std/syscall-aux.S
mrproper-y += $(obj)/include/uapi/std/syscall-aux.h

View File

@ -0,0 +1,43 @@
#!/usr/bin/perl
use strict;
use warnings;
my $in = $ARGV[0];
my $tblout = $ARGV[1];
my $bits = $ARGV[2];
my $code = "code$bits";
open TBLOUT, ">", $tblout or die $!;
open IN, "<", $in or die $!;
print TBLOUT "/* Autogenerated, don't edit */\n";
print TBLOUT "static struct syscall_exec_desc sc_exec_table[] = {\n";
for (<IN>) {
if ($_ =~ /\#/) {
next;
}
my $sys_name;
my $sys_num;
if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$sys_name = $+{alias};
} elsif (/(?<name>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$sys_name = $+{name};
} else {
unlink $tblout;
die "Invalid syscall definition file: invalid entry $_\n";
}
$sys_num = $+{$code};
if ($sys_num ne "!") {
print TBLOUT "SYSCALL($sys_name, $sys_num)\n";
}
}
print TBLOUT " { }, /* terminator */";
print TBLOUT "};"

View File

@ -0,0 +1,99 @@
#!/usr/bin/perl
use strict;
use warnings;
my $in = $ARGV[0];
my $codesout = $ARGV[1];
my $codes = $ARGV[1];
$codes =~ s/.*include\/uapi\//compel\/plugins\//g;
my $protosout = $ARGV[2];
my $protos = $ARGV[2];
$protos =~ s/.*include\/uapi\//compel\/plugins\//g;
my $asmout = $ARGV[3];
my $asmcommon = $ARGV[4];
my $prototypes = $ARGV[5];
$prototypes =~ s/.*include\/uapi\//compel\/plugins\//g;
my $bits = $ARGV[6];
my $codesdef = $codes;
$codesdef =~ tr/.\-\//_/;
my $protosdef = $protos;
$protosdef =~ tr/.\-\//_/;
my $code = "code$bits";
my $need_aux = 0;
unlink $codesout;
unlink $protosout;
unlink $asmout;
open CODESOUT, ">", $codesout or die $!;
open PROTOSOUT, ">", $protosout or die $!;
open ASMOUT, ">", $asmout or die $!;
open IN, "<", $in or die $!;
print CODESOUT <<"END";
/* Autogenerated, don't edit */
#ifndef $codesdef
#define $codesdef
END
print PROTOSOUT <<"END";
/* Autogenerated, don't edit */
#ifndef $protosdef
#define $protosdef
#include <$prototypes>
#include <$codes>
END
print ASMOUT <<"END";
/* Autogenerated, don't edit */
#include <$codes>
#include "$asmcommon"
END
for (<IN>) {
if ($_ =~ /\#/) {
next;
}
my $code_macro;
my $sys_macro;
my $sys_name;
if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$code_macro = "__NR_$+{name}";
$sys_macro = "SYS_$+{name}";
$sys_name = "sys_$+{alias}";
} elsif (/(?<name>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$code_macro = "__NR_$+{name}";
$sys_macro = "SYS_$+{name}";
$sys_name = "sys_$+{name}";
} else {
unlink $codesout;
unlink $protosout;
unlink $asmout;
die "Invalid syscall definition file: invalid entry $_\n";
}
if ($+{$code} ne "!") {
print CODESOUT "#ifndef $code_macro\n#define $code_macro $+{$code}\n#endif\n";
print CODESOUT "#ifndef $sys_macro\n#define $sys_macro $code_macro\n#endif\n";
print ASMOUT "syscall $sys_name, $code_macro\n";
} else {
$need_aux = 1;
}
print PROTOSOUT "extern long $sys_name($+{args});\n";
}
if ($need_aux == 1) {
print ASMOUT "#include <compel/plugins/std/syscall-aux.S>\n";
print CODESOUT "#include <compel/plugins/std/syscall-aux.h>\n";
}
print CODESOUT "#endif /* $codesdef */";
print PROTOSOUT "#endif /* $protosdef */";

View File

@ -0,0 +1,37 @@
/**
* This source contains emulation of syscalls
* that are not implemented in the riscv64 Linux kernel
*/
ENTRY(sys_open)
add a3, x0, a2
add a2, x0, a1
add a1, x0, a0
addi a0, x0, -100
j sys_openat
END(sys_open)
ENTRY(sys_mkdir)
add a3,x0, a2
add a2, x0, a1
add a1, x0, a0
addi a0, x0, -100
j sys_mkdirat
END(sys_mkdir)
ENTRY(sys_rmdir)
addi a2, x0, 0x200 // flags = AT_REMOVEDIR
add a1, x0, a0
addi a0, x0, -100
j sys_unlinkat
END(sys_rmdir)
ENTRY(sys_unlink)
addi a2, x0, 0 // flags = 0
add a1, x0, a0
addi a0, x0, -100
j sys_unlinkat
END(sys_unlink)

View File

@ -0,0 +1,3 @@
#ifndef __NR_openat
#define __NR_openat 56
#endif

View File

@ -0,0 +1,17 @@
#include "common/asm/linkage.h"
syscall_common:
ecall
ret
.macro syscall name, nr
ENTRY(\name)
li a7, \nr
j syscall_common
END(\name)
.endm
ENTRY(__cr_restore_rt)
li a7, __NR_rt_sigreturn
ecall
END(__cr_restore_rt)

View File

@ -0,0 +1,125 @@
#
# System calls table, please make sure the table consists of only the syscalls
# really used somewhere in the project.
#
# The template is (name and arguments are optional if you need only __NR_x
# defined, but no real entry point in syscalls lib).
#
# name/alias code64 code32 arguments
# -----------------------------------------------------------------------
#
read 63 3 (int fd, void *buf, unsigned long count)
write 64 4 (int fd, const void *buf, unsigned long count)
open ! 5 (const char *filename, unsigned long flags, unsigned long mode)
close 57 6 (int fd)
lseek 62 19 (int fd, unsigned long offset, unsigned long origin)
mmap 222 ! (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset)
mprotect 226 125 (const void *addr, unsigned long len, unsigned long prot)
munmap 215 91 (void *addr, unsigned long len)
brk 214 45 (void *addr)
rt_sigaction sigaction 134 174 (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize)
rt_sigprocmask sigprocmask 135 175 (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize)
rt_sigreturn 139 173 (void)
ioctl 29 54 (unsigned int fd, unsigned int cmd, unsigned long arg)
pread64 67 180 (unsigned int fd, char *buf, size_t count, loff_t pos)
ptrace 117 26 (long request, pid_t pid, void *addr, void *data)
mremap 216 163 (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flag, unsigned long new_addr)
mincore 232 219 (void *addr, unsigned long size, unsigned char *vec)
madvise 233 220 (unsigned long start, size_t len, int behavior)
shmat 196 305 (int shmid, void *shmaddr, int shmflag)
pause 1061 29 (void)
nanosleep 101 162 (struct timespec *req, struct timespec *rem)
getitimer 102 105 (int which, const struct itimerval *val)
setitimer 103 104 (int which, const struct itimerval *val, struct itimerval *old)
getpid 172 20 (void)
socket 198 281 (int domain, int type, int protocol)
connect 203 283 (int sockfd, struct sockaddr *addr, int addrlen)
sendto 206 290 (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len)
recvfrom 207 292 (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len)
sendmsg 211 296 (int sockfd, const struct msghdr *msg, int flags)
recvmsg 212 297 (int sockfd, struct msghdr *msg, int flags)
shutdown 210 293 (int sockfd, int how)
bind 235 282 (int sockfd, const struct sockaddr *addr, int addrlen)
setsockopt 208 294 (int sockfd, int level, int optname, const void *optval, socklen_t optlen)
getsockopt 209 295 (int sockfd, int level, int optname, const void *optval, socklen_t *optlen)
clone 220 120 (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid)
exit 93 1 (unsigned long error_code)
wait4 260 114 (int pid, int *status, int options, struct rusage *ru)
waitid 95 280 (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru)
kill 129 37 (long pid, int sig)
fcntl 25 55 (int fd, int type, long arg)
flock 32 143 (int fd, unsigned long cmd)
mkdir ! 39 (const char *name, int mode)
rmdir ! 40 (const char *name)
unlink ! 10 (char *pathname)
readlinkat 78 332 (int fd, const char *path, char *buf, int bufsize)
umask 166 60 (int mask)
getgroups 158 205 (int gsize, unsigned int *groups)
setgroups 159 206 (int gsize, unsigned int *groups)
setresuid 147 164 (int uid, int euid, int suid)
getresuid 148 165 (int *uid, int *euid, int *suid)
setresgid 149 170 (int gid, int egid, int sgid)
getresgid 150 171 (int *gid, int *egid, int *sgid)
getpgid 155 132 (pid_t pid)
setfsuid 151 138 (int fsuid)
setfsgid 152 139 (int fsgid)
getsid 156 147 (void)
capget 90 184 (struct cap_header *h, struct cap_data *d)
capset 91 185 (struct cap_header *h, struct cap_data *d)
rt_sigqueueinfo 138 178 (pid_t pid, int sig, siginfo_t *info)
setpriority 140 97 (int which, int who, int nice)
sched_setscheduler 119 156 (int pid, int policy, struct sched_param *p)
sigaltstack 132 186 (const void *uss, void *uoss)
personality 92 136 (unsigned int personality)
prctl 167 172 (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
arch_prctl ! 17 (int option, unsigned long addr)
setrlimit 164 75 (int resource, struct krlimit *rlim)
mount 40 21 (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data)
umount2 39 52 (char *name, int flags)
gettid 178 224 (void)
futex 98 240 (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3)
set_tid_address 96 256 (int *tid_addr)
restart_syscall 128 0 (void)
timer_create 107 257 (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id)
timer_settime 110 258 (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting)
timer_gettime 108 259 (int timer_id, const struct itimerspec *setting)
timer_getoverrun 109 260 (int timer_id)
timer_delete 111 261 (kernel_timer_t timer_id)
clock_gettime 113 263 (const clockid_t which_clock, const struct timespec *tp)
exit_group 94 248 (int error_code)
set_robust_list 99 338 (struct robust_list_head *head, size_t len)
get_robust_list 100 339 (int pid, struct robust_list_head **head_ptr, size_t *len_ptr)
signalfd4 74 355 (int fd, k_rtsigset_t *mask, size_t sizemask, int flags)
rt_tgsigqueueinfo 240 363 (pid_t tgid, pid_t pid, int sig, siginfo_t *info)
vmsplice 75 343 (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags)
timerfd_settime 86 353 (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr)
fanotify_init 262 367 (unsigned int flags, unsigned int event_f_flags)
fanotify_mark 263 368 (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname)
open_by_handle_at 265 371 (int mountdirfd, struct file_handle *handle, int flags)
setns 268 375 (int fd, int nstype)
kcmp 272 378 (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2)
openat 56 322 (int dirfd, const char *pathname, int flags, mode_t mode)
mkdirat 34 323 (int dirfd, const char *pathname, mode_t mode)
unlinkat 35 328 (int dirfd, const char *pathname, int flags)
memfd_create 279 385 (const char *name, unsigned int flags)
io_setup 0 243 (unsigned nr_events, aio_context_t *ctx)
io_submit 2 246 (aio_context_t ctx_id, long nr, struct iocb **iocbpp)
io_getevents 4 245 (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo)
seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs)
gettimeofday 169 78 (struct timeval *tv, struct timezone *tz)
preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h)
userfaultfd 282 388 (int flags)
fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len)
cacheflush ! 983042 (void *start, void *end, int flags)
ppoll 73 336 (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize)
fsopen 430 430 (char *fsname, unsigned int flags)
fsconfig 431 431 (int fd, unsigned int cmd, const char *key, const char *value, int aux)
fsmount 432 432 (int fd, unsigned int flags, unsigned int attr_flags)
clone3 435 435 (struct clone_args *uargs, size_t size)
pidfd_open 434 434 (pid_t pid, unsigned int flags)
pidfd_getfd 438 438 (int pidfd, int targetfd, unsigned int flags)
rseq 293 293 (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
move_mount 429 429 (int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, int flags)
open_tree 428 428 (int dirfd, const char *pathname, unsigned int flags)
openat2 437 437 (int dirfd, char *pathname, struct open_how *how, size_t size)
membarrier 283 283 (int cmd, unsigned int flags, int cpu_id)

View File

@ -0,0 +1,112 @@
/* Autogenerated, don't edit */
#include <compel/plugins/std/syscall-codes.h>
#include "std/syscalls/syscall-common.S"
syscall sys_read, __NR_read
syscall sys_write, __NR_write
syscall sys_close, __NR_close
syscall sys_lseek, __NR_lseek
syscall sys_mmap, __NR_mmap
syscall sys_mprotect, __NR_mprotect
syscall sys_munmap, __NR_munmap
syscall sys_brk, __NR_brk
syscall sys_sigaction, __NR_rt_sigaction
syscall sys_sigprocmask, __NR_rt_sigprocmask
syscall sys_rt_sigreturn, __NR_rt_sigreturn
syscall sys_ioctl, __NR_ioctl
syscall sys_pread64, __NR_pread64
syscall sys_ptrace, __NR_ptrace
syscall sys_mremap, __NR_mremap
syscall sys_mincore, __NR_mincore
syscall sys_madvise, __NR_madvise
syscall sys_shmat, __NR_shmat
syscall sys_pause, __NR_pause
syscall sys_nanosleep, __NR_nanosleep
syscall sys_getitimer, __NR_getitimer
syscall sys_setitimer, __NR_setitimer
syscall sys_getpid, __NR_getpid
syscall sys_socket, __NR_socket
syscall sys_connect, __NR_connect
syscall sys_sendto, __NR_sendto
syscall sys_recvfrom, __NR_recvfrom
syscall sys_sendmsg, __NR_sendmsg
syscall sys_recvmsg, __NR_recvmsg
syscall sys_shutdown, __NR_shutdown
syscall sys_bind, __NR_bind
syscall sys_setsockopt, __NR_setsockopt
syscall sys_getsockopt, __NR_getsockopt
syscall sys_clone, __NR_clone
syscall sys_exit, __NR_exit
syscall sys_wait4, __NR_wait4
syscall sys_waitid, __NR_waitid
syscall sys_kill, __NR_kill
syscall sys_fcntl, __NR_fcntl
syscall sys_flock, __NR_flock
syscall sys_readlinkat, __NR_readlinkat
syscall sys_umask, __NR_umask
syscall sys_getgroups, __NR_getgroups
syscall sys_setgroups, __NR_setgroups
syscall sys_setresuid, __NR_setresuid
syscall sys_getresuid, __NR_getresuid
syscall sys_setresgid, __NR_setresgid
syscall sys_getresgid, __NR_getresgid
syscall sys_getpgid, __NR_getpgid
syscall sys_setfsuid, __NR_setfsuid
syscall sys_setfsgid, __NR_setfsgid
syscall sys_getsid, __NR_getsid
syscall sys_capget, __NR_capget
syscall sys_capset, __NR_capset
syscall sys_rt_sigqueueinfo, __NR_rt_sigqueueinfo
syscall sys_setpriority, __NR_setpriority
syscall sys_sched_setscheduler, __NR_sched_setscheduler
syscall sys_sigaltstack, __NR_sigaltstack
syscall sys_personality, __NR_personality
syscall sys_prctl, __NR_prctl
syscall sys_setrlimit, __NR_setrlimit
syscall sys_mount, __NR_mount
syscall sys_umount2, __NR_umount2
syscall sys_gettid, __NR_gettid
syscall sys_futex, __NR_futex
syscall sys_set_tid_address, __NR_set_tid_address
syscall sys_restart_syscall, __NR_restart_syscall
syscall sys_timer_create, __NR_timer_create
syscall sys_timer_settime, __NR_timer_settime
syscall sys_timer_gettime, __NR_timer_gettime
syscall sys_timer_getoverrun, __NR_timer_getoverrun
syscall sys_timer_delete, __NR_timer_delete
syscall sys_clock_gettime, __NR_clock_gettime
syscall sys_exit_group, __NR_exit_group
syscall sys_set_robust_list, __NR_set_robust_list
syscall sys_get_robust_list, __NR_get_robust_list
syscall sys_signalfd4, __NR_signalfd4
syscall sys_rt_tgsigqueueinfo, __NR_rt_tgsigqueueinfo
syscall sys_vmsplice, __NR_vmsplice
syscall sys_timerfd_settime, __NR_timerfd_settime
syscall sys_fanotify_init, __NR_fanotify_init
syscall sys_fanotify_mark, __NR_fanotify_mark
syscall sys_open_by_handle_at, __NR_open_by_handle_at
syscall sys_setns, __NR_setns
syscall sys_kcmp, __NR_kcmp
syscall sys_openat, __NR_openat
syscall sys_mkdirat, __NR_mkdirat
syscall sys_unlinkat, __NR_unlinkat
syscall sys_memfd_create, __NR_memfd_create
syscall sys_io_setup, __NR_io_setup
syscall sys_io_submit, __NR_io_submit
syscall sys_io_getevents, __NR_io_getevents
syscall sys_seccomp, __NR_seccomp
syscall sys_gettimeofday, __NR_gettimeofday
syscall sys_preadv_raw, __NR_preadv_raw
syscall sys_userfaultfd, __NR_userfaultfd
syscall sys_fallocate, __NR_fallocate
syscall sys_ppoll, __NR_ppoll
syscall sys_fsopen, __NR_fsopen
syscall sys_fsconfig, __NR_fsconfig
syscall sys_fsmount, __NR_fsmount
syscall sys_clone3, __NR_clone3
syscall sys_pidfd_open, __NR_pidfd_open
syscall sys_pidfd_getfd, __NR_pidfd_getfd
syscall sys_rseq, __NR_rseq
syscall sys_move_mount, __NR_move_mount
syscall sys_open_tree, __NR_open_tree
syscall sys_openat2, __NR_openat2
#include <compel/plugins/std/syscall-aux.S>

View File

@ -0,0 +1,32 @@
OUTPUT_ARCH(riscv)
EXTERN(__export_parasite_head_start)
SECTIONS
{
.crblob 0x0 : {
*(.head.text)
ASSERT(DEFINED(__export_parasite_head_start),
"Symbol __export_parasite_head_start is missing");
*(.text*)
. = ALIGN(32);
*(.data*)
. = ALIGN(32);
*(.rodata*)
. = ALIGN(32);
*(.bss*)
. = ALIGN(32);
*(.got*)
. = ALIGN(32);
*(.toc*)
. = ALIGN(32);
} =0x00000000,
/DISCARD/ : {
*(.debug*)
*(.comment*)
*(.note*)
*(.group*)
*(.eh_frame*)
*(*)
}
}

View File

@ -0,0 +1,78 @@
#include <string.h>
#include <stdbool.h>
#include "compel-cpu.h"
#include "common/bitops.h"
#include "log.h"
#undef LOG_PREFIX
#define LOG_PREFIX "cpu: "
static compel_cpuinfo_t rt_info;
static void fetch_rt_cpuinfo(void)
{
static bool rt_info_done = false;
if (!rt_info_done) {
compel_cpuid(&rt_info);
rt_info_done = true;
}
}
void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
}
void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
}
int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
return 0;
}
int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
return 0;
}
int compel_cpuid(compel_cpuinfo_t *info)
{
return 0;
}
bool compel_cpu_has_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_test_cpu_cap(&rt_info, feature);
}
bool compel_fpu_has_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_test_fpu_cap(&rt_info, feature);
}
uint32_t compel_fpu_feature_size(unsigned int feature)
{
fetch_rt_cpuinfo();
return 0;
}
uint32_t compel_fpu_feature_offset(unsigned int feature)
{
fetch_rt_cpuinfo();
return 0;
}
void compel_cpu_clear_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_clear_cpu_cap(&rt_info, feature);
}
void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c)
{
fetch_rt_cpuinfo();
memcpy(c, &rt_info, sizeof(rt_info));
}

View File

@ -0,0 +1 @@
handle-elf.c

View File

@ -0,0 +1,32 @@
#include <string.h>
#include <errno.h>
#include "handle-elf.h"
#include "piegen.h"
#include "log.h"
static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, /* clang-format */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char __maybe_unused elf_ident_64_be[EI_NIDENT] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, /* clang-format */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
int handle_binary(void *mem, size_t size)
{
const unsigned char *elf_ident =
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
elf_ident_64_le;
#else
elf_ident_64_be;
#endif
if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0)
return handle_elf_riscv64(mem, size);
pr_err("Unsupported Elf format detected\n");
return -EINVAL;
}

View File

@ -0,0 +1,12 @@
#ifndef COMPEL_HANDLE_ELF_H__
#define COMPEL_HANDLE_ELF_H__
#include "elf64-types.h"
#define __handle_elf handle_elf_riscv64
#define ELF_RISCV
#define arch_is_machine_supported(e_machine) (e_machine == EM_RISCV)
extern int handle_elf_riscv64(void *mem, size_t size);
#endif /* COMPEL_HANDLE_ELF_H__ */

View File

@ -0,0 +1,8 @@
#ifndef __COMPEL_SYSCALL_H__
#define __COMPEL_SYSCALL_H__
#define __NR(syscall, compat) \
({ \
(void)compat; \
__NR_##syscall; \
})
#endif

View File

@ -0,0 +1,15 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View File

@ -0,0 +1,7 @@
#ifndef UAPI_COMPEL_ASM_CPU_H__
#define UAPI_COMPEL_ASM_CPU_H__
typedef struct {
} compel_cpuinfo_t;
#endif /* UAPI_COMPEL_ASM_CPU_H__ */

View File

@ -0,0 +1,4 @@
#ifndef __CR_ASM_FPU_H__
#define __CR_ASM_FPU_H__
#endif /* __CR_ASM_FPU_H__ */

View File

@ -0,0 +1,52 @@
#ifndef UAPI_COMPEL_ASM_TYPES_H__
#define UAPI_COMPEL_ASM_TYPES_H__
#include <stdint.h>
#include <signal.h>
#include <sys/mman.h>
#include <asm/ptrace.h>
#define SIGMAX 64
#define SIGMAX_OLD 31
/*
* Copied from the Linux kernel header arch/riscv/include/uapi/asm/ptrace.h
*
* A thread RISC-V CPU context
*/
typedef struct user_regs_struct user_regs_struct_t;
typedef struct __riscv_d_ext_state user_fpregs_struct_t;
#define __compel_arch_fetch_thread_area(tid, th) 0
#define compel_arch_fetch_thread_area(tctl) 0
#define compel_arch_get_tls_task(ctl, tls)
#define compel_arch_get_tls_thread(tctl, tls)
#define REG_RES(registers) ((uint64_t)(registers).a0)
#define REG_IP(registers) ((uint64_t)(registers).pc)
#define SET_REG_IP(registers, val) ((registers).pc = (val))
/*
* REG_SP is also defined in riscv64-linux-gnu/include/sys/ucontext.h
* with a different meaning, and it's not used in CRIU. So we have to
* undefine it here.
*/
#ifdef REG_SP
#undef REG_SP
#endif
#define REG_SP(registers) ((uint64_t)((registers).sp))
#define REG_SYSCALL_NR(registers) ((uint64_t)(registers).a7)
#define user_regs_native(pregs) true
#define ARCH_SI_TRAP TRAP_BRKPT
#define __NR(syscall, compat) \
({ \
(void)compat; \
__NR_##syscall; \
})
#endif /* UAPI_COMPEL_ASM_TYPES_H__ */

View File

@ -0,0 +1,26 @@
#ifndef COMPEL_RELOCATIONS_H__
#define COMPEL_RELOCATIONS_H__
#include <stdint.h>
static inline uint32_t riscv_b_imm(uint32_t val)
{
return (val & 0x00001000) << 19 | (val & 0x000007e0) << 20 | (val & 0x0000001e) << 7 | (val & 0x00000800) >> 4;
}
static inline uint32_t riscv_i_imm(uint32_t val)
{
return val << 20;
}
static inline uint32_t riscv_u_imm(uint32_t val)
{
return val & 0xfffff000;
}
static inline uint32_t riscv_j_imm(uint32_t val)
{
return (val & 0x00100000) << 11 | (val & 0x000007fe) << 20 | (val & 0x00000800) << 9 | (val & 0x000ff000);
}
#endif /* COMPEL_RELOCATIONS_H__ */

View File

@ -0,0 +1,4 @@
#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__
#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__
#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */

View File

@ -0,0 +1,68 @@
#ifndef UAPI_COMPEL_ASM_SIGFRAME_H__
#define UAPI_COMPEL_ASM_SIGFRAME_H__
#include <sys/ucontext.h>
#include <stdint.h>
#include <signal.h>
/* Copied from the kernel header arch/riscv/include/uapi/asm/sigcontext.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;
// /*
// * 4K + 128 reserved for vector state and future expansion.
// * This space is enough to store the vector context whose VLENB
// * is less or equal to 128.
// * (The size of the vector context is 4144 byte as VLENB is 128)
// */
// __u8 __reserved[4224] __attribute__((__aligned__(16)));
// };
#define rt_sigcontext sigcontext
#include <compel/sigframe-common.h>
/* Copied from the kernel source arch/riscv/kernel/signal.c */
struct rt_sigframe {
siginfo_t info;
ucontext_t uc; //ucontext_t structure holds the user context, e.g., the signal mask, GP regs
};
/*
generates inline assembly code for triggering the rt_sigreturn system call.
used to return from a signal handler back to the normal execution flow of the process.
*/
/* clang-format off */
#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \
asm volatile( \
"mv sp, %0\n" \
"li a7, "__stringify(__NR_rt_sigreturn)" \n" \
"ecall\n" \
: \
: "r"(new_sp) \
: "a7", "memory")
/* clang-format on */
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc)
#define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)(rt_sigframe)->uc.uc_mcontext.__gregs[REG_PC])
#define RT_SIGFRAME_HAS_FPU(rt_sigframe) 1
#define RT_SIGFRAME_OFFSET(rt_sigframe) 0
// #define RT_SIGFRAME_SIGCONTEXT(rt_sigframe) ((struct cr_sigcontext *)&(rt_sigframe)->uc.uc_mcontext)
// #define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct sigcontext *)&(RT_SIGFRAME_SIGCONTEXT(rt_sigframe)->__reserved))
// #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd)
#define rt_sigframe_erase_sigset(sigframe) \
memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) // erase the signal mask
#define rt_sigframe_copy_sigset(sigframe, from) \
memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t)) // copy the signal mask
#endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */

View File

@ -0,0 +1,222 @@
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/elf.h>
#include <compel/plugins/std/syscall-codes.h>
#include "common/page.h"
#include "uapi/compel/asm/infect-types.h"
#include "log.h"
#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
unsigned __page_size = 0;
unsigned __page_shift = 0;
/*
* Injected syscall instruction
*/
const char code_syscall[] = {
0x73, 0x00, 0x00, 0x00, /* ecall */
0x73, 0x00, 0x10, 0x00 /* ebreak */
};
static const int code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long));
static inline void __always_unused __check_code_syscall(void)
{
BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE);
BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
}
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
sigframe->uc.uc_mcontext.__gregs[0] = regs->pc;
sigframe->uc.uc_mcontext.__gregs[1] = regs->ra;
sigframe->uc.uc_mcontext.__gregs[2] = regs->sp;
sigframe->uc.uc_mcontext.__gregs[3] = regs->gp;
sigframe->uc.uc_mcontext.__gregs[4] = regs->tp;
sigframe->uc.uc_mcontext.__gregs[5] = regs->t0;
sigframe->uc.uc_mcontext.__gregs[6] = regs->t1;
sigframe->uc.uc_mcontext.__gregs[7] = regs->t2;
sigframe->uc.uc_mcontext.__gregs[8] = regs->s0;
sigframe->uc.uc_mcontext.__gregs[9] = regs->s1;
sigframe->uc.uc_mcontext.__gregs[10] = regs->a0;
sigframe->uc.uc_mcontext.__gregs[11] = regs->a1;
sigframe->uc.uc_mcontext.__gregs[12] = regs->a2;
sigframe->uc.uc_mcontext.__gregs[13] = regs->a3;
sigframe->uc.uc_mcontext.__gregs[14] = regs->a4;
sigframe->uc.uc_mcontext.__gregs[15] = regs->a5;
sigframe->uc.uc_mcontext.__gregs[16] = regs->a6;
sigframe->uc.uc_mcontext.__gregs[17] = regs->a7;
sigframe->uc.uc_mcontext.__gregs[18] = regs->s2;
sigframe->uc.uc_mcontext.__gregs[19] = regs->s3;
sigframe->uc.uc_mcontext.__gregs[20] = regs->s4;
sigframe->uc.uc_mcontext.__gregs[21] = regs->s5;
sigframe->uc.uc_mcontext.__gregs[22] = regs->s6;
sigframe->uc.uc_mcontext.__gregs[23] = regs->s7;
sigframe->uc.uc_mcontext.__gregs[24] = regs->s8;
sigframe->uc.uc_mcontext.__gregs[25] = regs->s9;
sigframe->uc.uc_mcontext.__gregs[26] = regs->s10;
sigframe->uc.uc_mcontext.__gregs[27] = regs->s11;
sigframe->uc.uc_mcontext.__gregs[28] = regs->t3;
sigframe->uc.uc_mcontext.__gregs[29] = regs->t4;
sigframe->uc.uc_mcontext.__gregs[30] = regs->t5;
sigframe->uc.uc_mcontext.__gregs[31] = regs->t6;
memcpy(sigframe->uc.uc_mcontext.__fpregs.__d.__f, fpregs->f, sizeof(fpregs->f));
sigframe->uc.uc_mcontext.__fpregs.__d.__fcsr = fpregs->fcsr;
return 0;
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe)
{
return 0;
}
int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *ext_regs, save_regs_t save,
void *arg, __maybe_unused unsigned long flags)
{
user_fpregs_struct_t tmp, *fpsimd = ext_regs ? ext_regs : &tmp;
struct iovec iov;
int ret = -1;
pr_info("Dumping FPU registers for %d\n", pid);
iov.iov_base = fpsimd;
iov.iov_len = sizeof(*fpsimd);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
pr_perror("Failed to obtain FPU registers for %d", pid);
return -1;
}
ret = save(arg, regs, fpsimd);
return ret;
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)
{
struct iovec iov;
pr_info("Restoring GP/FPU registers for %d\n", pid);
iov.iov_base = ext_regs;
iov.iov_len = sizeof(*ext_regs);
if (ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov)) {
pr_perror("Failed to set FPU registers for %d", pid);
return -1;
}
return 0;
}
int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
{
user_regs_struct_t regs = ctl->orig.regs;
int err;
regs.a7 = (unsigned long)nr;
regs.a0 = arg1;
regs.a1 = arg2;
regs.a2 = arg3;
regs.a3 = arg4;
regs.a4 = arg5;
regs.a5 = arg6;
regs.a6 = 0;
err = compel_execute_syscall(ctl, &regs, code_syscall);
*ret = regs.a0;
return err;
}
/*
* Calling the mmap system call in the context of the target (victim) process using the compel_syscall function.
* Used during the infection process to allocate memory for the parasite code.
*/
void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
long map;
int err;
err = compel_syscall(ctl, __NR_mmap, &map, (unsigned long)addr, length, prot, flags, fd, offset);
if (err < 0 || (long)map < 0)
map = 0;
return (void *)map;
}
void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs)
{
regs->pc = new_ip;
if (stack)
regs->sp = (unsigned long)stack;
}
bool arch_can_dump_task(struct parasite_ctl *ctl)
{
/*
* TODO: Add proper check here.
*/
return true;
}
/*
* Fetch the signal alternate stack (sigaltstack),
* sas is a separate memory area for the signal handler to run on,
* avoiding potential issues with the main process stack
*/
int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s)
{
long ret;
int err;
err = compel_syscall(ctl, __NR_sigaltstack, &ret, 0, (unsigned long)&s->uc.uc_stack, 0, 0, 0, 0);
return err ? err : ret;
}
/*
* Task size is the maximum virtual address space size that a process can occupy in the memory
* Refer to linux kernel arch/riscv/include/asm/pgtable.h,
* task size is:
* - 0x9fc00000 (~2.5GB) for RV32.
* - 0x4000000000 ( 256GB) for RV64 using SV39 mmu
* - 0x800000000000 ( 128TB) for RV64 using SV48 mmu
*
* Note that PGDIR_SIZE must evenly divide TASK_SIZE since "RISC-V
* Instruction Set Manual Volume II: Privileged Architecture" states that
* "load and store effective addresses, which are 64bits, must have bits
* 6348 all equal to bit 47, or else a page-fault exception will occur."
*/
#define TASK_SIZE 0x800000000000UL // hardcoded for SV48 MMU
unsigned long compel_task_size(void)
{
return TASK_SIZE;
}
/*
* Get task registers (overwrites weak function)
*/
int ptrace_get_regs(int pid, user_regs_struct_t *regs)
{
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(user_regs_struct_t);
return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
}
/*
* Set task registers (overwrites weak function)
*/
int ptrace_set_regs(int pid, user_regs_struct_t *regs)
{
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(user_regs_struct_t);
return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
}

View File

@ -60,6 +60,9 @@ static const flags_t flags = {
#elif defined CONFIG_LOONGARCH64 #elif defined CONFIG_LOONGARCH64
.arch = "loongarch64", .arch = "loongarch64",
.cflags = COMPEL_CFLAGS_PIE, .cflags = COMPEL_CFLAGS_PIE,
#elif defined CONFIG_RISCV64
.arch = "riscv64",
.cflags = COMPEL_CFLAGS_PIE,
#else #else
#error "CONFIG_<ARCH> not defined, or unsupported ARCH" #error "CONFIG_<ARCH> not defined, or unsupported ARCH"
#endif #endif

View File

@ -21,6 +21,7 @@ ARCH ?= $(shell echo $(SUBARCH) | sed \
-e s/mips.*/mips/ \ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ \ -e s/sh[234].*/sh/ \
-e s/aarch64.*/aarch64/ \ -e s/aarch64.*/aarch64/ \
-e s/riscv64.*/riscv64/ \
-e s/loongarch64.*/loongarch64/) -e s/loongarch64.*/loongarch64/)
export SUBARCH ARCH export SUBARCH ARCH