Implement vsyscall hack. Prior to 2.13 glibc uses vsyscall
instead of vdso. An upcoming linux_base-c6 needs it. Differential Revision: https://reviews.freebsd.org/D1090 Reviewed by: kib, trasz MFC after: 1 week
This commit is contained in:
parent
f7b2f01ed0
commit
e706df7b9a
@ -80,6 +80,7 @@ struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
|
||||
|
||||
|
@ -322,6 +322,13 @@ trap(struct trapframe *frame)
|
||||
break;
|
||||
|
||||
case T_PAGEFLT: /* page fault */
|
||||
/*
|
||||
* Emulator can take care about this trap?
|
||||
*/
|
||||
if (*p->p_sysent->sv_trap != NULL &&
|
||||
(*p->p_sysent->sv_trap)(td) == 0)
|
||||
goto userout;
|
||||
|
||||
addr = frame->tf_addr;
|
||||
i = trap_pfault(frame, TRUE);
|
||||
if (i == -1)
|
||||
|
@ -129,6 +129,7 @@ static void linux_set_syscall_retval(struct thread *td, int error);
|
||||
static int linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
|
||||
static void linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
||||
u_long stack);
|
||||
static int linux_vsyscall(struct thread *td);
|
||||
|
||||
/*
|
||||
* Linux syscalls return negative errno's, we do positive and map them
|
||||
@ -746,6 +747,53 @@ exec_linux_imgact_try(struct image_params *imgp)
|
||||
return(error);
|
||||
}
|
||||
|
||||
#define LINUX_VSYSCALL_START (-10UL << 20)
|
||||
#define LINUX_VSYSCALL_SZ 1024
|
||||
|
||||
const unsigned long linux_vsyscall_vector[] = {
|
||||
LINUX_SYS_gettimeofday,
|
||||
LINUX_SYS_linux_time,
|
||||
/* getcpu not implemented */
|
||||
};
|
||||
|
||||
static int
|
||||
linux_vsyscall(struct thread *td)
|
||||
{
|
||||
struct trapframe *frame;
|
||||
uint64_t retqaddr;
|
||||
int code, traced;
|
||||
int error;
|
||||
|
||||
frame = td->td_frame;
|
||||
|
||||
/* Check %rip for vsyscall area */
|
||||
if (__predict_true(frame->tf_rip < LINUX_VSYSCALL_START))
|
||||
return (EINVAL);
|
||||
if ((frame->tf_rip & (LINUX_VSYSCALL_SZ - 1)) != 0)
|
||||
return (EINVAL);
|
||||
code = (frame->tf_rip - LINUX_VSYSCALL_START) / LINUX_VSYSCALL_SZ;
|
||||
if (code >= nitems(linux_vsyscall_vector))
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* vsyscall called as callq *(%rax), so we must
|
||||
* use return address from %rsp and also fixup %rsp
|
||||
*/
|
||||
error = copyin((void *)frame->tf_rsp, &retqaddr, sizeof(retqaddr));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
frame->tf_rip = retqaddr;
|
||||
frame->tf_rax = linux_vsyscall_vector[code];
|
||||
frame->tf_rsp += 8;
|
||||
|
||||
traced = (frame->tf_flags & PSL_T);
|
||||
|
||||
amd64_syscall(td, traced);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct sysentvec elf_linux_sysvec = {
|
||||
.sv_size = LINUX_SYS_MAXSYSCALL,
|
||||
.sv_table = linux_sysent,
|
||||
@ -778,7 +826,8 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_base = SHAREDPAGE,
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = linux_vsyscall,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1040,6 +1040,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -86,6 +86,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -87,6 +87,8 @@ static struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_shared_page_base = SHAREDPAGE,
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
|
||||
|
||||
|
@ -134,6 +134,7 @@ struct sysentvec ia32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);
|
||||
|
||||
|
@ -194,6 +194,7 @@ struct sysentvec svr4_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
const char svr4_emul_path[] = "/compat/svr4";
|
||||
|
@ -87,6 +87,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -90,6 +90,7 @@ struct sysentvec ibcs2_svr3_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -985,6 +985,7 @@ struct sysentvec linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
|
||||
|
||||
@ -1021,6 +1022,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -97,6 +97,7 @@ struct sysentvec aout_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
#elif defined(__amd64__)
|
||||
|
@ -414,6 +414,7 @@ struct sysentvec null_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -81,6 +81,7 @@ struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static Elf64_Brandinfo freebsd_brand_info = {
|
||||
@ -135,6 +136,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo freebsd_brand_info = {
|
||||
|
@ -104,6 +104,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_syscallnames = freebsd32_syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -106,6 +106,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -85,6 +85,7 @@ struct sysentvec elf64_freebsd_sysvec_v1 = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf64_sysvec_v1, &elf64_freebsd_sysvec_v1);
|
||||
|
||||
|
@ -85,6 +85,7 @@ static struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static Elf64_Brandinfo freebsd_brand_info = {
|
||||
|
@ -129,6 +129,7 @@ struct sysentvec {
|
||||
void *sv_shared_page_obj;
|
||||
void (*sv_schedtail)(struct thread *);
|
||||
void (*sv_thread_detach)(struct thread *);
|
||||
int (*sv_trap)(struct thread *);
|
||||
};
|
||||
|
||||
#define SV_ILP32 0x000100 /* 32-bit executable. */
|
||||
|
Loading…
Reference in New Issue
Block a user