summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2016-01-16 07:56:49 +0000
committerdchagin <dchagin@FreeBSD.org>2016-01-16 07:56:49 +0000
commited08737097eb396742e2825609c2449687d3a944 (patch)
tree502e9d93bdb2080378407e3c95c46d902a53c2d3 /sys
parentfaf7d1b1b8f0ca18354d8d3cf1ac6d387581008e (diff)
downloadFreeBSD-src-ed08737097eb396742e2825609c2449687d3a944.zip
FreeBSD-src-ed08737097eb396742e2825609c2449687d3a944.tar.gz
MFC r293613:
Implement vsyscall hack. Prior to 2.13 glibc uses vsyscall instead of vdso. An upcoming linux_base-c6 needs it.
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/elf_machdep.c1
-rw-r--r--sys/amd64/amd64/trap.c7
-rw-r--r--sys/amd64/linux/linux_sysvec.c51
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c1
-rw-r--r--sys/arm/arm/elf_machdep.c1
-rw-r--r--sys/compat/ia32/ia32_sysvec.c1
-rw-r--r--sys/compat/svr4/svr4_sysvec.c1
-rw-r--r--sys/i386/i386/elf_machdep.c1
-rw-r--r--sys/i386/ibcs2/ibcs2_sysvec.c1
-rw-r--r--sys/i386/linux/linux_sysvec.c2
-rw-r--r--sys/kern/imgact_aout.c1
-rw-r--r--sys/kern/init_main.c1
-rw-r--r--sys/mips/mips/elf_machdep.c2
-rw-r--r--sys/mips/mips/freebsd32_machdep.c1
-rw-r--r--sys/powerpc/powerpc/elf32_machdep.c1
-rw-r--r--sys/powerpc/powerpc/elf64_machdep.c1
-rw-r--r--sys/sparc64/sparc64/elf_machdep.c1
-rw-r--r--sys/sys/sysent.h1
18 files changed, 75 insertions, 1 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index d961f09..d7c9fef 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -83,6 +83,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);
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 3ecfabe..218c8cf 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -327,6 +327,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)
diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index 37c1b69..d53a266 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -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,
@@ -781,7 +829,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
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 250e16b..8f722aa 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -1043,6 +1043,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
diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c
index 8472858..55d4a41 100644
--- a/sys/arm/arm/elf_machdep.c
+++ b/sys/arm/arm/elf_machdep.c
@@ -80,6 +80,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 = {
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 206935a..d2870ce 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -140,6 +140,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);
diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c
index 125a7d8..8b339c8 100644
--- a/sys/compat/svr4/svr4_sysvec.c
+++ b/sys/compat/svr4/svr4_sysvec.c
@@ -197,6 +197,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";
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index 81d6e35..29a8885 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -89,6 +89,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);
diff --git a/sys/i386/ibcs2/ibcs2_sysvec.c b/sys/i386/ibcs2/ibcs2_sysvec.c
index 16507ee..372e5ea 100644
--- a/sys/i386/ibcs2/ibcs2_sysvec.c
+++ b/sys/i386/ibcs2/ibcs2_sysvec.c
@@ -90,6 +90,7 @@ struct sysentvec ibcs2_svr3_sysvec = {
.sv_syscallnames = NULL,
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
+ .sv_trap = NULL,
};
static int
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 7c980ce..df5441b 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -988,6 +988,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);
@@ -1027,6 +1028,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
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
index edd5f5f..553dc04 100644
--- a/sys/kern/imgact_aout.c
+++ b/sys/kern/imgact_aout.c
@@ -100,6 +100,7 @@ struct sysentvec aout_sysvec = {
.sv_syscallnames = syscallnames,
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
+ .sv_trap = NULL,
};
#elif defined(__amd64__)
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 6cb5017..201680a 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -415,6 +415,7 @@ struct sysentvec null_sysvec = {
.sv_syscallnames = NULL,
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
+ .sv_trap = NULL,
};
/*
diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c
index 626b5f8..db50a73 100644
--- a/sys/mips/mips/elf_machdep.c
+++ b/sys/mips/mips/elf_machdep.c
@@ -84,6 +84,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 = {
@@ -141,6 +142,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 = {
diff --git a/sys/mips/mips/freebsd32_machdep.c b/sys/mips/mips/freebsd32_machdep.c
index 5303420..87fda42 100644
--- a/sys/mips/mips/freebsd32_machdep.c
+++ b/sys/mips/mips/freebsd32_machdep.c
@@ -107,6 +107,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);
diff --git a/sys/powerpc/powerpc/elf32_machdep.c b/sys/powerpc/powerpc/elf32_machdep.c
index e8d563a..6b3a9af 100644
--- a/sys/powerpc/powerpc/elf32_machdep.c
+++ b/sys/powerpc/powerpc/elf32_machdep.c
@@ -108,6 +108,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);
diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c
index 4324266..d871e54 100644
--- a/sys/powerpc/powerpc/elf64_machdep.c
+++ b/sys/powerpc/powerpc/elf64_machdep.c
@@ -84,6 +84,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);
diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c
index 0dab76d..6ddbd98 100644
--- a/sys/sparc64/sparc64/elf_machdep.c
+++ b/sys/sparc64/sparc64/elf_machdep.c
@@ -88,6 +88,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 = {
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index a93d552..8436ba3 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -131,6 +131,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
OpenPOWER on IntegriCloud