summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2011-04-01 11:16:29 +0000
committerkib <kib@FreeBSD.org>2011-04-01 11:16:29 +0000
commit7c2eaa21fe792c26e223a2f36a4f5c00fdaf52d8 (patch)
tree601aa0131bd58a0facc71b1b7c7b138597686fbe
parent6d6007bc145d7665435f03f2ff2043e14240d09e (diff)
downloadFreeBSD-src-7c2eaa21fe792c26e223a2f36a4f5c00fdaf52d8.zip
FreeBSD-src-7c2eaa21fe792c26e223a2f36a4f5c00fdaf52d8.tar.gz
Add support for executing the FreeBSD 1/i386 a.out binaries on amd64.
In particular: - implement compat shims for old stat(2) variants and ogetdirentries(2); - implement delivery of signals with ancient stack frame layout and corresponding sigreturn(2); - implement old getpagesize(2); - provide a user-mode trampoline and LDT call gate for lcall $7,$0; - port a.out image activator and connect it to the build as a module on amd64. The changes are hidden under COMPAT_43. MFC after: 1 month
-rw-r--r--sys/amd64/ia32/ia32_misc.c11
-rw-r--r--sys/amd64/ia32/ia32_signal.c170
-rw-r--r--sys/amd64/ia32/ia32_sigtramp.S37
-rw-r--r--sys/amd64/ia32/ia32_syscall.c53
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c100
-rw-r--r--sys/compat/freebsd32/syscalls.master18
-rw-r--r--sys/compat/ia32/ia32_genassym.c3
-rw-r--r--sys/compat/ia32/ia32_signal.h13
-rw-r--r--sys/compat/ia32/ia32_sysvec.c6
-rw-r--r--sys/compat/ia32/ia32_util.h1
-rw-r--r--sys/ia64/ia32/ia32_misc.c11
-rw-r--r--sys/ia64/ia32/ia32_signal.c9
-rw-r--r--sys/kern/imgact_aout.c83
-rw-r--r--sys/kern/vfs_syscalls.c25
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/sys/syscallsubr.h3
16 files changed, 504 insertions, 40 deletions
diff --git a/sys/amd64/ia32/ia32_misc.c b/sys/amd64/ia32/ia32_misc.c
index 2fa1972..5a8a721 100644
--- a/sys/amd64/ia32/ia32_misc.c
+++ b/sys/amd64/ia32/ia32_misc.c
@@ -69,3 +69,14 @@ freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
return (sysarch(td, &uap1));
}
}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_getpagesize(struct thread *td,
+ struct ofreebsd32_getpagesize_args *uap)
+{
+
+ td->td_retval[0] = IA32_PAGE_SIZE;
+ return (0);
+}
+#endif
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 29dd01f..2f41870 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -300,6 +300,109 @@ freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
* frame pointer, it returns to the user
* specified pc, psl.
*/
+
+#ifdef COMPAT_43
+static void
+ia32_osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct ia32_sigframe3 sf, *fp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ struct trapframe *regs;
+ int sig;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ sig = ksi->ksi_signo;
+ psp = p->p_sigacts;
+ mtx_assert(&psp->ps_mtx, MA_OWNED);
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_rsp);
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct ia32_sigframe3 *)(td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size - sizeof(sf));
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ } else
+ fp = (struct ia32_sigframe3 *)regs->tf_rsp - 1;
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
+ if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_arg2 = (register_t)&fp->sf_siginfo;
+ sf.sf_siginfo.si_signo = sig;
+ sf.sf_siginfo.si_code = ksi->ksi_code;
+ sf.sf_ah = (uintptr_t)catcher;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_arg2 = ksi->ksi_code;
+ sf.sf_addr = (register_t)ksi->ksi_addr;
+ sf.sf_ah = (uintptr_t)catcher;
+ }
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(p);
+
+ /* Save most if not all of trap frame. */
+ sf.sf_siginfo.si_sc.sc_eax = regs->tf_rax;
+ sf.sf_siginfo.si_sc.sc_ebx = regs->tf_rbx;
+ sf.sf_siginfo.si_sc.sc_ecx = regs->tf_rcx;
+ sf.sf_siginfo.si_sc.sc_edx = regs->tf_rdx;
+ sf.sf_siginfo.si_sc.sc_esi = regs->tf_rsi;
+ sf.sf_siginfo.si_sc.sc_edi = regs->tf_rdi;
+ sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs;
+ sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds;
+ sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss;
+ sf.sf_siginfo.si_sc.sc_es = regs->tf_es;
+ sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs;
+ sf.sf_siginfo.si_sc.sc_gs = regs->tf_gs;
+ sf.sf_siginfo.si_sc.sc_isp = regs->tf_rsp;
+
+ /* Build the signal context to be used by osigreturn(). */
+ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0;
+ SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask);
+ sf.sf_siginfo.si_sc.sc_esp = regs->tf_rsp;
+ sf.sf_siginfo.si_sc.sc_ebp = regs->tf_rbp;
+ sf.sf_siginfo.si_sc.sc_eip = regs->tf_rip;
+ sf.sf_siginfo.si_sc.sc_eflags = regs->tf_rflags;
+ sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
+ sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, fp, sizeof(*fp)) != 0) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_rsp = (uintptr_t)fp;
+ regs->tf_rip = p->p_sysent->sv_psstrings - sz_ia32_osigcode;
+ regs->tf_rflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucode32sel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+#endif
+
#ifdef COMPAT_FREEBSD4
static void
freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
@@ -441,6 +544,12 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
return;
}
#endif
+#ifdef COMPAT_43
+ if (SIGISMEMBER(psp->ps_osigset, sig)) {
+ ia32_osendsig(catcher, ksi, mask);
+ return;
+ }
+#endif
mtx_assert(&psp->ps_mtx, MA_OWNED);
regs = td->td_frame;
oonstack = sigonstack(regs->tf_rsp);
@@ -547,6 +656,64 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
* make sure that the user has not modified the
* state to gain improper privileges.
*/
+
+#ifdef COMPAT_43
+int
+ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
+{
+ struct ia32_sigcontext3 sc, *scp;
+ struct trapframe *regs;
+ int eflags, error;
+ ksiginfo_t ksi;
+
+ regs = td->td_frame;
+ error = copyin(uap->sigcntxp, &sc, sizeof(sc));
+ if (error != 0)
+ return (error);
+ scp = &sc;
+ eflags = scp->sc_eflags;
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
+ return (EINVAL);
+ }
+ if (!CS_SECURE(scp->sc_cs)) {
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_trapno = T_PROTFLT;
+ ksi.ksi_addr = (void *)regs->tf_rip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+ regs->tf_ds = scp->sc_ds;
+ regs->tf_es = scp->sc_es;
+ regs->tf_fs = scp->sc_fs;
+ regs->tf_gs = scp->sc_gs;
+
+ regs->tf_rax = scp->sc_eax;
+ regs->tf_rbx = scp->sc_ebx;
+ regs->tf_rcx = scp->sc_ecx;
+ regs->tf_rdx = scp->sc_edx;
+ regs->tf_rsi = scp->sc_esi;
+ regs->tf_rdi = scp->sc_edi;
+ regs->tf_cs = scp->sc_cs;
+ regs->tf_ss = scp->sc_ss;
+ regs->tf_rbp = scp->sc_ebp;
+ regs->tf_rsp = scp->sc_esp;
+ regs->tf_rip = scp->sc_eip;
+ regs->tf_rflags = eflags;
+
+ if (scp->sc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+
+ kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
+ SIGPROCMASK_OLD);
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ return (EJUSTRETURN);
+}
+#endif
+
#ifdef COMPAT_FREEBSD4
/*
* MPSAFE
@@ -734,6 +901,9 @@ ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
user_ldt_free(td);
else
mtx_unlock(&dt_lock);
+#ifdef COMPAT_43
+ setup_lcall_gate();
+#endif
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
diff --git a/sys/amd64/ia32/ia32_sigtramp.S b/sys/amd64/ia32/ia32_sigtramp.S
index 9455169..7d64470 100644
--- a/sys/amd64/ia32/ia32_sigtramp.S
+++ b/sys/amd64/ia32/ia32_sigtramp.S
@@ -66,6 +66,35 @@ freebsd4_ia32_sigcode:
jmp 1b
#endif
+#ifdef COMPAT_43
+ ALIGN_TEXT
+ia32_osigcode:
+ calll *IA32_SIGF_HANDLER(%esp)/* call signal handler */
+ leal IA32_SIGF_SC(%esp),%eax /* get sigcontext */
+ pushl %eax
+ movl $103,%eax /* 3.x SYS_sigreturn */
+ pushl %eax /* junk to fake return addr. */
+ int $0x80 /* enter kernel with args */
+1:
+ jmp 1b
+
+
+ ALIGN_TEXT
+lcall_tramp:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl 0x24(%ebp) /* arg 6 */
+ pushl 0x20(%ebp)
+ pushl 0x1c(%ebp)
+ pushl 0x18(%ebp)
+ pushl 0x14(%ebp)
+ pushl 0x10(%ebp) /* arg 1 */
+ pushl 0xc(%ebp) /* gap */
+ int $0x80
+ leave
+ lretl
+#endif
+
ALIGN_TEXT
esigcode:
@@ -78,3 +107,11 @@ sz_ia32_sigcode:
sz_freebsd4_ia32_sigcode:
.long esigcode-freebsd4_ia32_sigcode
#endif
+#ifdef COMPAT_43
+ .globl sz_ia32_osigcode
+sz_ia32_osigcode:
+ .long esigcode-ia32_osigcode
+ .globl sz_lcall_tramp
+sz_lcall_tramp:
+ .long esigcode-lcall_tramp
+#endif
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index 9a3488e..0b46dae 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
*/
#include "opt_clock.h"
+#include "opt_compat.h"
#include "opt_cpu.h"
#include "opt_isa.h"
@@ -78,7 +79,17 @@ __FBSDID("$FreeBSD$");
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
+#include <compat/freebsd32/freebsd32_signal.h>
#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/ia32/ia32_signal.h>
+#include <machine/psl.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
#define IDTVEC(name) __CONCAT(X,name)
@@ -198,3 +209,45 @@ ia32_syscall_disable(void *dummy)
SYSINIT(ia32_syscall, SI_SUB_EXEC, SI_ORDER_ANY, ia32_syscall_enable, NULL);
SYSUNINIT(ia32_syscall, SI_SUB_EXEC, SI_ORDER_ANY, ia32_syscall_disable, NULL);
+
+#ifdef COMPAT_43
+int
+setup_lcall_gate(void)
+{
+ struct i386_ldt_args uap;
+ struct user_segment_descriptor descs[2];
+ struct gate_descriptor *ssd;
+ uint32_t lcall_addr;
+ int error;
+
+ bzero(&uap, sizeof(uap));
+ uap.start = 0;
+ uap.num = 2;
+
+ /*
+ * This is the easiest way to cut the space for system
+ * descriptor in ldt. Manually adjust the descriptor type to
+ * the call gate later.
+ */
+ bzero(&descs[0], sizeof(descs));
+ descs[0].sd_type = SDT_SYSNULL;
+ descs[1].sd_type = SDT_SYSNULL;
+ error = amd64_set_ldt(curthread, &uap, descs);
+ if (error != 0)
+ return (error);
+
+ lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp;
+ mtx_lock(&dt_lock);
+ ssd = (struct gate_descriptor *)(curproc->p_md.md_ldt->ldt_base);
+ bzero(ssd, sizeof(*ssd));
+ ssd->gd_looffset = lcall_addr;
+ ssd->gd_hioffset = lcall_addr >> 16;
+ ssd->gd_selector = _ucode32sel;
+ ssd->gd_type = SDT_SYSCGT;
+ ssd->gd_dpl = SEL_UPL;
+ ssd->gd_p = 1;
+ mtx_unlock(&dt_lock);
+
+ return (0);
+}
+#endif
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index e751147..5772c0e 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1454,6 +1454,29 @@ freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
return (ftruncate(td, &ap));
}
+#ifdef COMPAT_43
+int
+ofreebsd32_getdirentries(struct thread *td,
+ struct ofreebsd32_getdirentries_args *uap)
+{
+ struct ogetdirentries_args ap;
+ int error;
+ long loff;
+ int32_t loff_cut;
+
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ error = kern_ogetdirentries(td, &ap, &loff);
+ if (error == 0) {
+ loff_cut = loff;
+ error = copyout(&loff_cut, uap->basep, sizeof(int32_t));
+ }
+ return (error);
+}
+#endif
+
int
freebsd32_getdirentries(struct thread *td,
struct freebsd32_getdirentries_args *uap)
@@ -1638,6 +1661,29 @@ copy_stat(struct stat *in, struct stat32 *out)
TS_CP(*in, *out, st_birthtim);
}
+#ifdef COMPAT_43
+static void
+copy_ostat(struct stat *in, struct ostat32 *out)
+{
+
+ CP(*in, *out, st_dev);
+ CP(*in, *out, st_ino);
+ CP(*in, *out, st_mode);
+ CP(*in, *out, st_nlink);
+ CP(*in, *out, st_uid);
+ CP(*in, *out, st_gid);
+ CP(*in, *out, st_rdev);
+ CP(*in, *out, st_size);
+ TS_CP(*in, *out, st_atim);
+ TS_CP(*in, *out, st_mtim);
+ TS_CP(*in, *out, st_ctim);
+ CP(*in, *out, st_blksize);
+ CP(*in, *out, st_blocks);
+ CP(*in, *out, st_flags);
+ CP(*in, *out, st_gen);
+}
+#endif
+
int
freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
{
@@ -1653,6 +1699,23 @@ freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
return (error);
}
+#ifdef COMPAT_43
+int
+ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap)
+{
+ struct stat sb;
+ struct ostat32 sb32;
+ int error;
+
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error)
+ return (error);
+ copy_ostat(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+#endif
+
int
freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
{
@@ -1668,6 +1731,23 @@ freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
return (error);
}
+#ifdef COMPAT_43
+int
+ofreebsd32_fstat(struct thread *td, struct ofreebsd32_fstat_args *uap)
+{
+ struct stat ub;
+ struct ostat32 ub32;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &ub);
+ if (error)
+ return (error);
+ copy_ostat(&ub, &ub32);
+ error = copyout(&ub32, uap->ub, sizeof(ub32));
+ return (error);
+}
+#endif
+
int
freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap)
{
@@ -1698,9 +1778,23 @@ freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
return (error);
}
-/*
- * MPSAFE
- */
+#ifdef COMPAT_43
+int
+ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
+{
+ struct stat sb;
+ struct ostat32 sb32;
+ int error;
+
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error)
+ return (error);
+ copy_ostat(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+#endif
+
int
freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
{
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 8a4cadf..da42133 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -117,9 +117,11 @@
35 AUE_FCHFLAGS NOPROTO { int fchflags(int fd, int flags); }
36 AUE_SYNC NOPROTO { int sync(void); }
37 AUE_KILL NOPROTO { int kill(int pid, int signum); }
-38 AUE_STAT UNIMPL ostat
+38 AUE_STAT COMPAT { int freebsd32_stat(char *path, \
+ struct ostat32 *ub); }
39 AUE_GETPPID NOPROTO { pid_t getppid(void); }
-40 AUE_LSTAT UNIMPL olstat
+40 AUE_LSTAT COMPAT { int freebsd32_lstat(char *path, \
+ struct ostat *ub); }
41 AUE_DUP NOPROTO { int dup(u_int fd); }
42 AUE_PIPE NOPROTO { int pipe(void); }
43 AUE_GETEGID NOPROTO { gid_t getegid(void); }
@@ -153,9 +155,11 @@
60 AUE_UMASK NOPROTO { int umask(int newmask); } umask \
umask_args int
61 AUE_CHROOT NOPROTO { int chroot(char *path); }
-62 AUE_FSTAT OBSOL ofstat
+62 AUE_FSTAT COMPAT { int freebsd32_fstat(int fd, \
+ struct ostat32 *ub); }
63 AUE_NULL OBSOL ogetkerninfo
-64 AUE_NULL OBSOL ogetpagesize
+64 AUE_NULL COMPAT { int freebsd32_getpagesize( \
+ int32_t dummy); }
65 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \
int flags); }
66 AUE_VFORK NOPROTO { int vfork(void); }
@@ -210,7 +214,8 @@
100 AUE_GETPRIORITY NOPROTO { int getpriority(int which, int who); }
101 AUE_NULL OBSOL osend
102 AUE_NULL OBSOL orecv
-103 AUE_NULL OBSOL osigreturn
+103 AUE_NULL COMPAT { int freebsd32_sigreturn( \
+ struct ia32_sigcontext3 *sigcntxp); }
104 AUE_BIND NOPROTO { int bind(int s, caddr_t name, \
int namelen); }
105 AUE_SETSOCKOPT NOPROTO { int setsockopt(int s, int level, \
@@ -292,7 +297,8 @@
; 155 is initialized by the NFS code, if present.
; XXX this is a problem!!!
155 AUE_NFS_SVC UNIMPL nfssvc
-156 AUE_GETDIRENTRIES OBSOL ogetdirentries
+156 AUE_GETDIRENTRIES COMPAT { int freebsd32_getdirentries(int fd, \
+ char *buf, u_int count, uint32_t *basep); }
157 AUE_STATFS COMPAT4 { int freebsd32_statfs(char *path, \
struct statfs32 *buf); }
158 AUE_FSTATFS COMPAT4 { int freebsd32_fstatfs(int fd, \
diff --git a/sys/compat/ia32/ia32_genassym.c b/sys/compat/ia32/ia32_genassym.c
index 84fb648..5462a8b 100644
--- a/sys/compat/ia32/ia32_genassym.c
+++ b/sys/compat/ia32/ia32_genassym.c
@@ -13,6 +13,9 @@ __FBSDID("$FreeBSD$");
ASSYM(IA32_SIGF_HANDLER, offsetof(struct ia32_sigframe, sf_ah));
ASSYM(IA32_SIGF_UC, offsetof(struct ia32_sigframe, sf_uc));
+#ifdef COMPAT_43
+ASSYM(IA32_SIGF_SC, offsetof(struct ia32_sigframe3, sf_siginfo.si_sc));
+#endif
ASSYM(IA32_UC_GS, offsetof(struct ia32_ucontext, uc_mcontext.mc_gs));
ASSYM(IA32_UC_FS, offsetof(struct ia32_ucontext, uc_mcontext.mc_fs));
ASSYM(IA32_UC_ES, offsetof(struct ia32_ucontext, uc_mcontext.mc_es));
diff --git a/sys/compat/ia32/ia32_signal.h b/sys/compat/ia32/ia32_signal.h
index 757e384..0c54caf 100644
--- a/sys/compat/ia32/ia32_signal.h
+++ b/sys/compat/ia32/ia32_signal.h
@@ -112,7 +112,7 @@ struct ia32_ucontext4 {
};
#endif
-#ifdef COMPAT_FREEBSD3
+#ifdef COMPAT_43
struct ia32_sigcontext3 {
u_int32_t sc_onstack;
u_int32_t sc_mask;
@@ -165,7 +165,7 @@ struct ia32_sigframe {
struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
};
-#ifdef COMPAT_FREEBSD3
+#ifdef COMPAT_43
struct ia32_siginfo3 {
struct ia32_sigcontext3 si_sc;
int si_signo;
@@ -186,10 +186,15 @@ struct ksiginfo;
struct image_params;
extern char ia32_sigcode[];
extern char freebsd4_ia32_sigcode[];
+extern char ia32_osigcode[];
+extern char lcall_tramp;
extern int sz_ia32_sigcode;
extern int sz_freebsd4_ia32_sigcode;
-extern void ia32_sendsig(sig_t, struct ksiginfo *, sigset_t *);
-extern void ia32_setregs(struct thread *td, struct image_params *imgp,
+extern int sz_ia32_osigcode;
+extern int sz_lcall_tramp;
+void ia32_sendsig(sig_t, struct ksiginfo *, sigset_t *);
+void ia32_setregs(struct thread *td, struct image_params *imgp,
u_long stack);
+int setup_lcall_gate(void);
#endif
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index a7790ef..c7edac4 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -95,14 +95,12 @@ CTASSERT(sizeof(struct ia32_sigframe4) == 408);
extern const char *freebsd32_syscallnames[];
-static void ia32_fixlimit(struct rlimit *rl, int which);
-
SYSCTL_NODE(_compat, OID_AUTO, ia32, CTLFLAG_RW, 0, "ia32 mode");
static u_long ia32_maxdsiz = IA32_MAXDSIZ;
SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxdsiz, CTLFLAG_RW, &ia32_maxdsiz, 0, "");
TUNABLE_ULONG("compat.ia32.maxdsiz", &ia32_maxdsiz);
-static u_long ia32_maxssiz = IA32_MAXSSIZ;
+u_long ia32_maxssiz = IA32_MAXSSIZ;
SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxssiz, CTLFLAG_RW, &ia32_maxssiz, 0, "");
TUNABLE_ULONG("compat.ia32.maxssiz", &ia32_maxssiz);
static u_long ia32_maxvmem = IA32_MAXVMEM;
@@ -206,7 +204,7 @@ elf32_dump_thread(struct thread *td __unused, void *dst __unused,
{
}
-static void
+void
ia32_fixlimit(struct rlimit *rl, int which)
{
diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h
index 4355daa..f153492 100644
--- a/sys/compat/ia32/ia32_util.h
+++ b/sys/compat/ia32/ia32_util.h
@@ -58,5 +58,6 @@
struct syscall_args;
int ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
void ia32_set_syscall_retval(struct thread *, int);
+void ia32_fixlimit(struct rlimit *rl, int which);
#endif
diff --git a/sys/ia64/ia32/ia32_misc.c b/sys/ia64/ia32/ia32_misc.c
index c85e31d..148e31a 100644
--- a/sys/ia64/ia32/ia32_misc.c
+++ b/sys/ia64/ia32/ia32_misc.c
@@ -48,3 +48,14 @@ freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
return (EOPNOTSUPP);
}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_getpagesize(struct thread *td,
+ struct ofreebsd32_getpagesize_args *uap)
+{
+
+ td->td_retval[0] = IA32_PAGE_SIZE;
+ return (0);
+}
+#endif
diff --git a/sys/ia64/ia32/ia32_signal.c b/sys/ia64/ia32/ia32_signal.c
index e41f0af..b8dab90 100644
--- a/sys/ia64/ia32/ia32_signal.c
+++ b/sys/ia64/ia32/ia32_signal.c
@@ -92,6 +92,15 @@ x) */
};
int sz_ia32_sigcode = sizeof(ia32_sigcode);
+#ifdef COMPAT_43
+int
+ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
+{
+
+ return (EOPNOTSUPP);
+}
+#endif
+
/*
* Signal sending has not been implemented on ia64. This causes
* the sigtramp code to not understand the arguments and the application
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
index a783c41..2f168d8 100644
--- a/sys/kern/imgact_aout.c
+++ b/sys/kern/imgact_aout.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/imgact.h>
#include <sys/imgact_aout.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
@@ -52,9 +53,18 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_object.h>
#include <vm/vm_param.h>
+#ifdef __amd64__
+#include <compat/freebsd32/freebsd32_signal.h>
+#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+#include <compat/freebsd32/freebsd32_syscall.h>
+#include <compat/ia32/ia32_signal.h>
+#endif
+
static int exec_aout_imgact(struct image_params *imgp);
static int aout_fixup(register_t **stack_base, struct image_params *imgp);
+#if defined(__i386__)
struct sysentvec aout_sysvec = {
.sv_size = SYS_MAXSYSCALL,
.sv_table = sysent,
@@ -83,31 +93,69 @@ struct sysentvec aout_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
- .sv_flags = SV_ABI_FREEBSD | SV_AOUT |
-#if defined(__i386__)
- SV_IA32 | SV_ILP32
-#else
-#error Choose SV_XXX flags for the platform
-#endif
- ,
+ .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
.sv_schedtail = NULL,
};
+#elif defined(__amd64__)
+
+#define AOUT32_USRSTACK 0xbfc0000
+#define AOUT32_PS_STRINGS \
+ (AOUT32_USRSTACK - sizeof(struct freebsd32_ps_strings))
+
+extern const char *freebsd32_syscallnames[];
+extern u_long ia32_maxssiz;
+
+struct sysentvec aout_sysvec = {
+ .sv_size = FREEBSD32_SYS_MAXSYSCALL,
+ .sv_table = freebsd32_sysent,
+ .sv_mask = 0,
+ .sv_sigsize = 0,
+ .sv_sigtbl = NULL,
+ .sv_errsize = 0,
+ .sv_errtbl = NULL,
+ .sv_transtrap = NULL,
+ .sv_fixup = aout_fixup,
+ .sv_sendsig = ia32_sendsig,
+ .sv_sigcode = ia32_sigcode,
+ .sv_szsigcode = &sz_ia32_sigcode,
+ .sv_prepsyscall = NULL,
+ .sv_name = "FreeBSD a.out",
+ .sv_coredump = NULL,
+ .sv_imgact_try = NULL,
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_pagesize = IA32_PAGE_SIZE,
+ .sv_minuser = 0,
+ .sv_maxuser = AOUT32_USRSTACK,
+ .sv_usrstack = AOUT32_USRSTACK,
+ .sv_psstrings = AOUT32_PS_STRINGS,
+ .sv_stackprot = VM_PROT_ALL,
+ .sv_copyout_strings = freebsd32_copyout_strings,
+ .sv_setregs = ia32_setregs,
+ .sv_fixlimit = ia32_fixlimit,
+ .sv_maxssiz = &ia32_maxssiz,
+ .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32,
+ .sv_set_syscall_retval = ia32_set_syscall_retval,
+ .sv_fetch_syscall_args = ia32_fetch_syscall_args,
+ .sv_syscallnames = freebsd32_syscallnames,
+};
+#else
+#error "Port me"
+#endif
+
static int
-aout_fixup(stack_base, imgp)
- register_t **stack_base;
- struct image_params *imgp;
+aout_fixup(register_t **stack_base, struct image_params *imgp)
{
- return (suword(--(*stack_base), imgp->args->argc));
+ *(char **)stack_base -= sizeof(uint32_t);
+ return (suword(*stack_base, imgp->args->argc));
}
static int
-exec_aout_imgact(imgp)
- struct image_params *imgp;
+exec_aout_imgact(struct image_params *imgp)
{
const struct exec *a_out = (const struct exec *) imgp->image_header;
struct vmspace *vmspace;
@@ -175,7 +223,14 @@ exec_aout_imgact(imgp)
a_out->a_entry >= virtual_offset + a_out->a_text ||
/* text and data size must each be page rounded */
- a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
+ a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK
+
+#ifdef __amd64__
+ ||
+ /* overflows */
+ virtual_offset + a_out->a_text + a_out->a_data + bss_size > UINT_MAX
+#endif
+ )
return (-1);
/* text + data can't exceed file size */
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index fe66591..649339b 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3898,14 +3898,20 @@ struct ogetdirentries_args {
};
#endif
int
-ogetdirentries(td, uap)
- struct thread *td;
- register struct ogetdirentries_args /* {
- int fd;
- char *buf;
- u_int count;
- long *basep;
- } */ *uap;
+ogetdirentries(struct thread *td, struct ogetdirentries_args *uap)
+{
+ long loff;
+ int error;
+
+ error = kern_ogetdirentries(td, uap, &loff);
+ if (error == 0)
+ error = copyout(&loff, uap->basep, sizeof(long));
+ return (error);
+}
+
+int
+kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
+ long *ploff)
{
struct vnode *vp;
struct file *fp;
@@ -4024,9 +4030,10 @@ unionread:
}
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
- error = copyout(&loff, uap->basep, sizeof(long));
fdrop(fp, td);
td->td_retval[0] = uap->count - auio.uio_resid;
+ if (error == 0)
+ *ploff = loff;
return (error);
}
#endif /* COMPAT_43 */
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 6f239dc..8ac1665 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -518,6 +518,7 @@ _snc= snc
.if ${MACHINE_CPUARCH} == "amd64"
_aac= aac
+_aout= aout
_acpi= acpi
.if ${MK_CRYPT} != "no" || defined(ALL_MODULES)
_aesni= aesni
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index d400633..7649f1a 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -52,6 +52,7 @@ struct kld_file_stat;
struct ksiginfo;
struct sendfile_args;
struct thr_param;
+struct ogetdirentries_args;
int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg,
u_int buflen);
@@ -143,6 +144,8 @@ int kern_msgsnd(struct thread *, int, const void *, size_t, int, long);
int kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);
int kern_nanosleep(struct thread *td, struct timespec *rqt,
struct timespec *rmt);
+int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
+ long *ploff);
int kern_open(struct thread *td, char *path, enum uio_seg pathseg,
int flags, int mode);
int kern_openat(struct thread *td, int fd, char *path,
OpenPOWER on IntegriCloud