Commit dc927a20 authored by Michael Holzheu's avatar Michael Holzheu Committed by Pavel Emelyanov

s390:criu/arch/s390: Add s390 parts to criu

Reviewed-by: 's avatarAlice Frosi <alice@linux.vnet.ibm.com>
Signed-off-by: 's avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Reviewed-by: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 343b5f53
builtin-name := crtools.built-in.o
ccflags-y += -iquote $(obj)/include
ccflags-y += -iquote criu/include -iquote include
ccflags-y += $(COMPEL_UAPI_INCLUDES)
ldflags-y += -r
obj-y += cpu.o
obj-y += crtools.o
obj-y += sigframe.o
#undef LOG_PREFIX
#define LOG_PREFIX "cpu: "
#include <sys/auxv.h>
#include <errno.h>
#include "asm/types.h"
#include "cr_options.h"
#include "image.h"
#include "util.h"
#include "log.h"
#include "cpu.h"
#include "protobuf.h"
#include "images/cpuinfo.pb-c.h"
static compel_cpuinfo_t rt_cpuinfo;
static const char *hwcap_str1[64] = {
"HWCAP_S390_ESAN3",
"HWCAP_S390_ZARCH",
"HWCAP_S390_STFLE",
"HWCAP_S390_MSA",
"HWCAP_S390_LDISP",
"HWCAP_S390_EIMM",
"HWCAP_S390_DFP",
"HWCAP_S390_HPAGE",
"HWCAP_S390_ETF3EH",
"HWCAP_S390_HIGH_GPRS",
"HWCAP_S390_TE",
"HWCAP_S390_VXRS",
"HWCAP_S390_VXRS_BCD",
"HWCAP_S390_VXRS_EXT",
};
static const char *hwcap_str2[64] = { };
static const char **hwcap_str[2] = { hwcap_str1, hwcap_str2 };
static void print_hwcaps(const char *msg, unsigned long hwcap[2])
{
int nr, cap;
pr_debug("%s: Capabilities: %016lx %016lx\n", msg, hwcap[0], hwcap[1]);
for (nr = 0; nr < 2; nr++) {
for (cap = 0; cap < 64; cap++) {
if (!(hwcap[nr] & (1 << cap)))
continue;
if (hwcap_str[nr][cap])
pr_debug("%s\n", hwcap_str[nr][cap]);
else
pr_debug("Capability %d/0x%x\n", nr, 1 << cap);
}
}
}
int cpu_init(void)
{
int ret;
ret = compel_cpuid(&rt_cpuinfo);
print_hwcaps("Host (init)", rt_cpuinfo.hwcap);
return ret;
}
int cpu_dump_cpuinfo(void)
{
CpuinfoS390Entry cpu_s390_info = CPUINFO_S390_ENTRY__INIT;
CpuinfoS390Entry *cpu_s390_info_ptr = &cpu_s390_info;
CpuinfoEntry cpu_info = CPUINFO_ENTRY__INIT;
struct cr_img *img;
int ret = -1;
img = open_image(CR_FD_CPUINFO, O_DUMP);
if (!img)
return -1;
cpu_info.s390_entry = &cpu_s390_info_ptr;
cpu_info.n_s390_entry = 1;
cpu_s390_info.n_hwcap = 2;
cpu_s390_info.hwcap = rt_cpuinfo.hwcap;
ret = pb_write_one(img, &cpu_info, PB_CPUINFO);
close_image(img);
return ret;
}
int cpu_validate_cpuinfo(void)
{
CpuinfoS390Entry *cpu_s390_entry;
CpuinfoEntry *cpu_info;
struct cr_img *img;
int cap, nr, ret;
img = open_image(CR_FD_CPUINFO, O_RSTR);
if (!img)
return -1;
ret = 0;
if (pb_read_one(img, &cpu_info, PB_CPUINFO) < 0)
goto error;
if (cpu_info->n_s390_entry != 1) {
pr_err("No S390 related entry in image");
goto error;
}
cpu_s390_entry = cpu_info->s390_entry[0];
if (cpu_s390_entry->n_hwcap != 2) {
pr_err("Hardware capabilities information missing\n");
ret = -1;
goto error;
}
print_hwcaps("Host", rt_cpuinfo.hwcap);
print_hwcaps("Image", cpu_s390_entry->hwcap);
for (nr = 0; nr < 2; nr++) {
for (cap = 0; cap < 64; cap++) {
if (!(cpu_s390_entry->hwcap[nr] & (1 << cap)))
continue;
if (rt_cpuinfo.hwcap[nr] & (1 << cap))
continue;
if (hwcap_str[nr][cap])
pr_err("CPU Feature %s not supported on host\n",
hwcap_str[nr][cap]);
else
pr_err("CPU Feature %d/%x not supported on host\n",
nr, 1 << cap);
ret = -1;
}
}
if (ret == -1)
pr_err("See also: /usr/include/bits/hwcap.h\n");
error:
close_image(img);
return ret;
}
int cpuinfo_dump(void)
{
if (cpu_init())
return -1;
if (cpu_dump_cpuinfo())
return -1;
return 0;
}
int cpuinfo_check(void)
{
if (cpu_init())
return 1;
if (cpu_validate_cpuinfo())
return 1;
return 0;
}
#include <string.h>
#include <unistd.h>
#include <elf.h>
#include <sys/user.h>
#include <asm/unistd.h>
#include <sys/uio.h>
#include "types.h"
#include <compel/asm/fpu.h>
#include "asm/restorer.h"
#include "asm/dump.h"
#include "cr_options.h"
#include "common/compiler.h"
#include <compel/ptrace.h>
#include "parasite-syscall.h"
#include "log.h"
#include "util.h"
#include "cpu.h"
#include <compel/compel.h>
#include "protobuf.h"
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"
/*
* Print general purpose and access registers
*/
static void print_core_gpregs(const char *msg, UserS390RegsEntry *gpregs)
{
int i;
pr_debug("%s: General purpose registers\n", msg);
pr_debug(" psw %016lx %016lx\n",
gpregs->psw_mask, gpregs->psw_addr);
pr_debug(" orig_gpr2 %016lx\n", gpregs->orig_gpr2);
for (i = 0; i < 16; i++)
pr_debug(" g%02d %016lx\n", i, gpregs->gprs[i]);
for (i = 0; i < 16; i++)
pr_debug(" a%02d %08x\n", i, gpregs->acrs[i]);
}
/*
* Print floating point and vector registers
*/
static void print_core_fp_regs(const char *msg, CoreEntry *core)
{
UserS390VxrsHighEntry *vxrs_high;
UserS390VxrsLowEntry *vxrs_low;
UserS390FpregsEntry *fpregs;
int i;
vxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high;
vxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low;
fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs;
pr_debug("%s: Floating point registers\n", msg);
pr_debug(" fpc %08x\n", fpregs->fpc);
for (i = 0; i < 16; i++)
pr_debug(" f%02d %016lx\n", i, fpregs->fprs[i]);
if (!vxrs_low) {
pr_debug(" No VXRS\n");
return;
}
for (i = 0; i < 16; i++)
pr_debug(" vx_low%02d %016lx\n", i, vxrs_low->regs[i]);
for (i = 0; i < 32; i += 2)
pr_debug(" vx_high%02d %016lx %016lx\n", i / 2,
vxrs_high->regs[i], vxrs_high->regs[i + 1]);
}
/*
* Allocate VxrsLow registers
*/
static UserS390VxrsLowEntry *allocate_vxrs_low_regs(void)
{
UserS390VxrsLowEntry *vxrs_low;
vxrs_low = xmalloc(sizeof(*vxrs_low));
if (!vxrs_low)
return NULL;
user_s390_vxrs_low_entry__init(vxrs_low);
vxrs_low->n_regs = 16;
vxrs_low->regs = xzalloc(16 * sizeof(uint64_t));
if (!vxrs_low->regs)
goto fail_free_vxrs_low;
return vxrs_low;
fail_free_vxrs_low:
xfree(vxrs_low);
return NULL;
}
/*
* Free VxrsLow registers
*/
static void free_vxrs_low_regs(UserS390VxrsLowEntry *vxrs_low)
{
if (vxrs_low) {
xfree(vxrs_low->regs);
xfree(vxrs_low);
}
}
/*
* Allocate VxrsHigh registers
*/
static UserS390VxrsHighEntry *allocate_vxrs_high_regs(void)
{
UserS390VxrsHighEntry *vxrs_high;
vxrs_high = xmalloc(sizeof(*vxrs_high));
if (!vxrs_high)
return NULL;
user_s390_vxrs_high_entry__init(vxrs_high);
vxrs_high->n_regs = 32;
vxrs_high->regs = xzalloc(32 * sizeof(uint64_t));
if (!vxrs_high->regs)
goto fail_free_vxrs_high;
return vxrs_high;
fail_free_vxrs_high:
xfree(vxrs_high);
return NULL;
}
/*
* Free VxrsHigh registers
*/
static void free_vxrs_high_regs(UserS390VxrsHighEntry *vxrs_high)
{
if (vxrs_high) {
xfree(vxrs_high->regs);
xfree(vxrs_high);
}
}
/*
* Copy internal structures into Google Protocol Buffers
*/
int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
{
UserS390VxrsHighEntry *vxrs_high;
UserS390VxrsLowEntry *vxrs_low;
UserS390FpregsEntry *fpregs;
UserS390RegsEntry *gpregs;
CoreEntry *core = arg;
gpregs = CORE_THREAD_ARCH_INFO(core)->gpregs;
fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs;
/* Vector registers */
if (f->flags & USER_FPREGS_VXRS) {
vxrs_low = allocate_vxrs_low_regs();
if (!vxrs_low)
return -1;
vxrs_high = allocate_vxrs_high_regs();
if (!vxrs_high) {
free_vxrs_low_regs(vxrs_low);
return -1;
}
memcpy(vxrs_low->regs, &f->vxrs_low, sizeof(f->vxrs_low));
memcpy(vxrs_high->regs, &f->vxrs_high, sizeof(f->vxrs_high));
CORE_THREAD_ARCH_INFO(core)->vxrs_low = vxrs_low;
CORE_THREAD_ARCH_INFO(core)->vxrs_high = vxrs_high;
}
/* General purpose registers */
memcpy(gpregs->gprs, u->prstatus.gprs, sizeof(u->prstatus.gprs));
gpregs->psw_mask = u->prstatus.psw.mask;
gpregs->psw_addr = u->prstatus.psw.addr;
/* Access registers */
memcpy(gpregs->acrs, u->prstatus.acrs, sizeof(u->prstatus.acrs));
/* System call */
gpregs->system_call = u->system_call;
/* Floating point registers */
fpregs->fpc = f->prfpreg.fpc;
memcpy(fpregs->fprs, f->prfpreg.fprs, sizeof(f->prfpreg.fprs));
return 0;
}
/*
* Copy general and access registers to signal frame
*/
int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *src)
{
_sigregs *dst = &f->uc.uc_mcontext;
dst->regs.psw.mask = src->psw_mask;
dst->regs.psw.addr = src->psw_addr;
memcpy(dst->regs.gprs, src->gprs, sizeof(dst->regs.gprs));
memcpy(dst->regs.acrs, src->acrs, sizeof(dst->regs.acrs));
print_core_gpregs("restore_gpregs_regs", src);
return 0;
}
/*
* Copy floating point and vector registers to mcontext
*/
int restore_fpu(struct rt_sigframe *f, CoreEntry *core)
{
UserS390VxrsHighEntry *vxrs_high;
UserS390VxrsLowEntry *vxrs_low;
UserS390FpregsEntry *fpregs;
_sigregs *dst = &f->uc.uc_mcontext;
_sigregs_ext *dst_ext = &f->uc.uc_mcontext_ext;
fpregs = CORE_THREAD_ARCH_INFO(core)->fpregs;
vxrs_high = CORE_THREAD_ARCH_INFO(core)->vxrs_high;
vxrs_low = CORE_THREAD_ARCH_INFO(core)->vxrs_low;
dst->fpregs.fpc = fpregs->fpc;
memcpy(dst->fpregs.fprs, fpregs->fprs, sizeof(dst->fpregs.fprs));
if (vxrs_low) {
memcpy(&dst_ext->vxrs_low, vxrs_low->regs,
sizeof(dst_ext->vxrs_low));
memcpy(&dst_ext->vxrs_high, vxrs_high->regs,
sizeof(dst_ext->vxrs_high));
}
print_core_fp_regs("restore_fp_regs", core);
return 0;
}
/*
* Allocate floating point registers
*/
static UserS390FpregsEntry *allocate_fp_regs(void)
{
UserS390FpregsEntry *fpregs;
fpregs = xmalloc(sizeof(*fpregs));
if (!fpregs)
return NULL;
user_s390_fpregs_entry__init(fpregs);
fpregs->n_fprs = 16;
fpregs->fprs = xzalloc(16 * sizeof(uint64_t));
if (!fpregs->fprs)
goto fail_free_fpregs;
return fpregs;
fail_free_fpregs:
xfree(fpregs);
return NULL;
}
/*
* Free floating point registers
*/
static void free_fp_regs(UserS390FpregsEntry *fpregs)
{
xfree(fpregs->fprs);
xfree(fpregs);
}
/*
* Allocate general purpose and access registers
*/
static UserS390RegsEntry *allocate_gp_regs(void)
{
UserS390RegsEntry *gpregs;
gpregs = xmalloc(sizeof(*gpregs));
if (!gpregs)
return NULL;
user_s390_regs_entry__init(gpregs);
gpregs->n_gprs = 16;
gpregs->gprs = xzalloc(16 * sizeof(uint64_t));
if (!gpregs->gprs)
goto fail_free_gpregs;
gpregs->n_acrs = 16;
gpregs->acrs = xzalloc(16 * sizeof(uint32_t));
if (!gpregs->acrs)
goto fail_free_gprs;
return gpregs;
fail_free_gprs:
xfree(gpregs->gprs);
fail_free_gpregs:
xfree(gpregs);
return NULL;
}
/*
* Free general purpose and access registers
*/
static void free_gp_regs(UserS390RegsEntry *gpregs)
{
xfree(gpregs->gprs);
xfree(gpregs->acrs);
xfree(gpregs);
}
/*
* Allocate thread info
*/
int arch_alloc_thread_info(CoreEntry *core)
{
ThreadInfoS390 *ti_s390;
ti_s390 = xmalloc(sizeof(*ti_s390));
if (!ti_s390)
return -1;
thread_info_s390__init(ti_s390);
ti_s390->gpregs = allocate_gp_regs();
if (!ti_s390->gpregs)
goto fail_free_ti_s390;
ti_s390->fpregs = allocate_fp_regs();
if (!ti_s390->fpregs)
goto fail_free_gp_regs;
CORE_THREAD_ARCH_INFO(core) = ti_s390;
return 0;
fail_free_gp_regs:
free_gp_regs(ti_s390->gpregs);
fail_free_ti_s390:
xfree(ti_s390);
return -1;
}
/*
* Free thread info
*/
void arch_free_thread_info(CoreEntry *core)
{
if (!CORE_THREAD_ARCH_INFO(core))
return;
free_gp_regs(CORE_THREAD_ARCH_INFO(core)->gpregs);
free_fp_regs(CORE_THREAD_ARCH_INFO(core)->fpregs);
free_vxrs_low_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_low);
free_vxrs_high_regs(CORE_THREAD_ARCH_INFO(core)->vxrs_high);
xfree(CORE_THREAD_ARCH_INFO(core));
CORE_THREAD_ARCH_INFO(core) = NULL;
}
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f);
int arch_alloc_thread_info(CoreEntry *core);
void arch_free_thread_info(CoreEntry *core);
static inline void core_put_tls(CoreEntry *core, tls_t tls) { }
#define get_task_futex_robust_list_compat(pid, info) -1
#endif
#ifndef __CR_ASM_INT_H__
#define __CR_ASM_INT_H__
#include "asm-generic/int.h"
#endif /* __CR_ASM_INT_H__ */
#ifndef __CR_ASM_PARASITE_SYSCALL_H__
#define __CR_ASM_PARASITE_SYSCALL_H__
struct parasite_ctl;
#endif
#ifndef __ASM_PARASITE_H__
#define __ASM_PARASITE_H__
/* TLS is accessed through %a01, which is already processed */
static inline void arch_get_tls(tls_t *ptls) { (void)ptls; }
#endif
#ifndef __CR_ASM_RESTORE_H__
#define __CR_ASM_RESTORE_H__
#include "asm/restorer.h"
#include "images/core.pb-c.h"
/*
* Load stack to %r15, return address in %r14 and argument 1 into %r2
*/
#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start, \
task_args) \
asm volatile( \
"lgr %%r15,%0\n" \
"lgr %%r14,%1\n" \
"lgr %%r2,%2\n" \
"basr %%r14,%%r14\n" \
: \
: "d" (new_sp), \
"d"((unsigned long)restore_task_exec_start), \
"d" (task_args) \
: "2", "14", "15", "memory")
/* There is nothing to do since TLS is accessed through %a01 */
#define core_get_tls(pcore, ptls)
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
#endif
#ifndef __CR_ASM_RESTORER_H__
#define __CR_ASM_RESTORER_H__
#include <asm/ptrace.h>
#include <asm/types.h>
#include "asm/types.h"
#include "sigframe.h"
/*
* Clone trampoline - see glibc sysdeps/unix/sysv/linux/s390/s390-64/clone.S
*/
#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, \
thread_args, clone_restore_fn) \
asm volatile( \
"lgr %%r0,%6\n" /* Save thread_args in %r0 */ \
"lgr %%r1,%5\n" /* Save clone_restore_fn in %r1 */ \
"lgr %%r2,%2\n" /* Parm 1: new_sp (child stack) */ \
"lgr %%r3,%1\n" /* Parm 2: clone_flags */ \
"lgr %%r4,%3\n" /* Parm 3: &parent_tid */ \
"lgr %%r5,%4\n" /* Parm 4: &thread_args[i].pid */ \
"lghi %%r6,0\n" /* Parm 5: tls = 0 */ \
"svc "__stringify(__NR_clone)"\n" \
"ltgr %0,%%r2\n" /* Set and check "ret" */ \
"jnz 0f\n" /* ret != 0: Continue caller */ \
"lgr %%r2,%%r0\n" /* Parm 1: &thread_args */ \
"aghi %%r15,-160\n" /* Prepare stack frame */ \
"xc 0(8,%%r15),0(%%r15)\n" \
"basr %%r14,%%r1\n" /* Jump to clone_restore_fn() */ \
"j .+2\n" /* BUG(): Force PGM check */ \
"0:\n" /* Continue caller */ \
: "=d"(ret) \
: "d"(clone_flags), \
"a"(new_sp), \
"d"(&parent_tid), \
"d"(&thread_args[i].pid), \
"d"(clone_restore_fn), \
"d"(&thread_args[i]) \
: "0", "1", "2", "3", "4", "5", "6", "cc", "memory")
#define kdat_compatible_cr() 0
int restore_gpregs(struct rt_sigframe *f, UserS390RegsEntry *r);
int restore_nonsigframe_gpregs(UserS390RegsEntry *r);
unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg);
unsigned long sys_mmap(void *addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd,
unsigned long offset);
static inline void restore_tls(tls_t *ptls) { (void)ptls; }
static inline void *alloc_compat_syscall_stack(void) { return NULL; }
static inline void free_compat_syscall_stack(void *stack32) { }
static inline int arch_compat_rt_sigaction(void *stack, int sig, void *act)
{
return -1;
}
static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len)
{
return -1;
}
#endif /*__CR_ASM_RESTORER_H__*/
#ifndef _UAPI_S390_TYPES_H
#define _UAPI_S390_TYPES_H
#include <stdbool.h>
#include <signal.h>
#include "images/core.pb-c.h"
#include "page.h"
#include "bitops.h"
#include "asm/int.h"
#include <compel/plugins/std/asm/syscall-types.h>
typedef UserS390RegsEntry UserRegsEntry;
#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__S390
#define core_is_compat(core) false
#define CORE_THREAD_ARCH_INFO(core) core->ti_s390
static inline u64 encode_pointer(void *p) { return (u64) p; }
static inline void *decode_pointer(u64 v) { return (void *) v; }
/*
* See also:
* * arch/s390/include/uapi/asm/auxvec.h
* * include/linux/auxvec.h
*/
#define AT_VECTOR_SIZE_BASE 20
#define AT_VECTOR_SIZE_ARCH 1
#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1))
typedef uint64_t auxv_t;
typedef uint64_t tls_t;
#endif /* _UAPI_S390_TYPES_H */
#ifndef __CR_ASM_VDSO_H__
#define __CR_ASM_VDSO_H__
#include "asm/int.h"
#include "asm-generic/vdso.h"
/*
* This is a minimal amount of symbols
* we should support at the moment.
*/
#define VDSO_SYMBOL_MAX 4
/*
* This definition is used in pie/util-vdso.c to initialize the vdso symbol
* name string table 'vdso_symbols'
*/
#define ARCH_VDSO_SYMBOLS \
"__kernel_gettimeofday", \
"__kernel_clock_gettime", \
"__kernel_clock_getres", \
"__kernel_getcpu"
#endif /* __CR_ASM_VDSO_H__ */
#include <unistd.h>
#include "restorer.h"
#include "asm/restorer.h"
#include <compel/asm/fpu.h>
#include <compel/plugins/std/syscall.h>
#include "log.h"
/*
* All registers are restored by sigreturn - nothing to do here
*/
int restore_nonsigframe_gpregs(UserS390RegsEntry *r)
{
return 0;
}
/*
* Call underlying ipc system call for shmat
*/
unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg)
{
unsigned long raddr;
int ret;
ret = sys_ipc(21 /*SHMAT */,
shmid, /* first */
shmflg, /* second */
(unsigned long)&raddr, /* third */
shmaddr, /* ptr */
0 /* fifth not used */);
if (ret)
raddr = (unsigned long) ret;
return raddr;
}
#include <stdlib.h>
#include <stdint.h>
#include "asm/sigframe.h"
#include "asm/types.h"
#include "log.h"
/*
* Nothing to do since we don't have any pointers to adjust
* in the signal frame.
*
* - sigframe : Pointer to local signal frame
* - rsigframe: Pointer to remote signal frame of inferior
*/
int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe)
{
return 0;
}
#include <unistd.h>
#include "asm/types.h"
#include <compel/plugins/std/string.h>
#include <compel/plugins/std/syscall.h>
#include "parasite-vdso.h"
#include "log.h"
#include "common/bug.h"
#ifdef LOG_PREFIX
# undef LOG_PREFIX
#endif
#define LOG_PREFIX "vdso: "
/*
* Trampoline instruction sequence
*/
typedef struct {
u8 larl[6]; /* Load relative address of imm64 */
u8 lg[6]; /* Load %r1 with imm64 */
u8 br[2]; /* Branch to %r1 */
u64 addr; /* Jump address */
u32 guards; /* Guard bytes */
} __packed jmp_t;
/*
* Trampoline template: Use %r1 to jump
*/
jmp_t jmp = {
/* larl %r1,e (addr) */
.larl = {0xc0, 0x10, 0x00, 0x00, 0x00, 0x07},
/* lg %r1,0(%r1) */
.lg = {0xe3, 0x10, 0x10, 0x00, 0x00, 0x04},
/* br %r1 */
.br = {0x07, 0xf1},
.guards = 0xcccccccc,
};
/*
* Insert trampoline code into old vdso entry points to
* jump to new vdso functions.
*/
int vdso_redirect_calls(unsigned long base_to, unsigned long base_from,
struct vdso_symtable *to, struct vdso_symtable *from,
bool __always_unused compat_vdso)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(to->symbols); i++) {
if (vdso_symbol_empty(&from->symbols[i]))
continue;
pr_debug("jmp: %s: %lx/%lx -> %lx/%lx (index %d)\n",
from->symbols[i].name, base_from,
from->symbols[i].offset,
base_to, to->symbols[i].offset, i);
jmp.addr = base_to + to->symbols[i].offset;
memcpy((void *)(base_from + from->symbols[i].offset), &jmp,
sizeof(jmp));
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment