a.out/i386 support on amd64 kernels

Kostik Belousov kostikbel at gmail.com
Wed Jul 28 15:42:39 UTC 2010


Hi,
today is definitely not the April 1, but waiting for the date
would be too long. Please find below the patch that adds support
for executing old FreeBSD binaries on amd64. By old I mean:
- support for i386 a.out image activator;
- support for lcall 7,0 system call entry;
- bunch of the compat syscalls that I found neccessary to run
  ls(1) from FreeBSD 1.0 CD;
- signal delivery and sigreturn compat bits (untested).

The lcall entry is somewhat tricky to implement on amd64, since
call gates do not disable interrupts, and entry sequence must
do swapgs atomically. I ended up with another trampoline to
translate lcall to int 0x80 in the userspace.

If you are going to try the patch, you would need to set
sysctl security.bsd.map_at_zero to 1, and kldload aout.
Do not forget to regenerate syscall tables in compat/freebsd32
after patching. Kernel config should include COMPAT_FREEBSD32
and COMPAT_43 options.

diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index a218ff2..dba5163 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -295,6 +295,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;
+	td->td_pcb->pcb_full_iret = 1;
+	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)
@@ -391,7 +494,7 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	}
 
 	regs->tf_rsp = (uintptr_t)sfp;
-	regs->tf_rip = FREEBSD32_PS_STRINGS - sz_freebsd4_ia32_sigcode;
+	regs->tf_rip = p->p_sysent->sv_psstrings - sz_freebsd4_ia32_sigcode;
 	regs->tf_rflags &= ~(PSL_T | PSL_D);
 	regs->tf_cs = _ucode32sel;
 	regs->tf_ss = _udatasel;
@@ -429,6 +532,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);
@@ -512,7 +621,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	}
 
 	regs->tf_rsp = (uintptr_t)sfp;
-	regs->tf_rip = FREEBSD32_PS_STRINGS - *(p->p_sysent->sv_szsigcode);
+	regs->tf_rip = p->p_sysent->sv_psstrings - *(p->p_sysent->sv_szsigcode);
 	regs->tf_rflags &= ~(PSL_T | PSL_D);
 	regs->tf_cs = _ucode32sel;
 	regs->tf_ss = _udatasel;
@@ -533,6 +642,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);
+	td->td_pcb->pcb_full_iret = 1;
+	return (EJUSTRETURN);
+}
+#endif
+
 #ifdef COMPAT_FREEBSD4
 /*
  * MPSAFE
@@ -720,6 +887,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 6a649ae..0fd9016 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"
 #include "opt_ktrace.h"
@@ -82,7 +83,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)
 
@@ -202,3 +213,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.h b/sys/compat/freebsd32/freebsd32.h
index aad550e..eebaae6 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -157,6 +157,24 @@ struct stat32 {
 	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
 };
 
+struct ostat32 {
+	__uint16_t st_dev;
+	ino_t	st_ino;
+	mode_t	st_mode;
+	nlink_t	st_nlink;
+	__uint16_t st_uid;
+	__uint16_t st_gid;
+	__uint16_t st_rdev;
+	__int32_t st_size;
+	struct timespec32 st_atim;
+	struct timespec32 st_mtim;
+	struct timespec32 st_ctim;
+	__int32_t st_blksize;
+	__int32_t st_blocks;
+	u_int32_t st_flags;
+	__uint32_t st_gen;
+};
+
 struct jail32_v0 {
 	u_int32_t	version;
 	uint32_t	path;
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 3dfed77..c1bcc30 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1451,6 +1451,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)
@@ -1614,8 +1637,9 @@ freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
 }
 
 static void
-copy_stat( struct stat *in, struct stat32 *out)
+copy_stat(struct stat *in, struct stat32 *out)
 {
+
 	CP(*in, *out, st_dev);
 	CP(*in, *out, st_ino);
 	CP(*in, *out, st_mode);
@@ -1631,8 +1655,32 @@ copy_stat( struct stat *in, struct stat32 *out)
 	CP(*in, *out, st_blksize);
 	CP(*in, *out, st_flags);
 	CP(*in, *out, st_gen);
+	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)
 {
@@ -1648,6 +1696,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)
 {
@@ -1663,6 +1728,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)
 {
@@ -1693,9 +1775,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)
 {
@@ -2537,7 +2633,8 @@ freebsd32_copyout_strings(struct image_params *imgp)
 		execpath_len = strlen(imgp->execpath) + 1;
 	else
 		execpath_len = 0;
-	arginfo = (struct freebsd32_ps_strings *)FREEBSD32_PS_STRINGS;
+	arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent->
+	    sv_psstrings;
 	szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
 	destp =	(caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
 		roundup(execpath_len, sizeof(char *)) -
@@ -2636,4 +2733,3 @@ freebsd32_copyout_strings(struct image_params *imgp)
 
 	return ((register_t *)stack_base);
 }
-
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 4f1fc28..1457a4f 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 ostat *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 ostat *ub); }
 63	AUE_NULL	OBSOL	ogetkerninfo
-64	AUE_NULL	OBSOL	ogetpagesize
+64	AUE_NULL	COMPAT|NOPROTO	{ int getpagesize(void); } getpagesize \
+				    getpagesize_args int
 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 717ae74..e282a9b 100644
--- a/sys/compat/ia32/ia32_signal.h
+++ b/sys/compat/ia32/ia32_signal.h
@@ -109,7 +109,7 @@ struct ia32_ucontext4 {
 };
 #endif
 
-#ifdef COMPAT_FREEBSD3
+#ifdef COMPAT_43
 struct ia32_sigcontext3 {
 	u_int32_t	sc_onstack;
 	u_int32_t	sc_mask;
@@ -162,7 +162,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;
@@ -183,8 +183,13 @@ 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);
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index d7ac5d0..36a4927 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;
@@ -198,7 +196,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 d91bfde..f5b1412 100644
--- a/sys/compat/ia32/ia32_util.h
+++ b/sys/compat/ia32/ia32_util.h
@@ -51,3 +51,4 @@
 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);
diff --git a/sys/conf/options b/sys/conf/options
index 9563cc8..d81edb4 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -66,6 +66,7 @@ AUDIT		opt_global.h
 CODA_COMPAT_5	opt_coda.h
 COMPAT_43	opt_compat.h
 COMPAT_43TTY	opt_compat.h
+COMPAT_FREEBSD3	opt_compat.h
 COMPAT_FREEBSD4	opt_compat.h
 COMPAT_FREEBSD5	opt_compat.h
 COMPAT_FREEBSD6	opt_compat.h
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
index 6710135..42745e0 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,30 +93,68 @@ 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,
 };
 
+#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;
@@ -174,7 +222,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 4fd9dfa..068a966 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 d033a34..d1e389b 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -498,6 +498,7 @@ _snc=		snc
 
 .if ${MACHINE_ARCH} == "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 7524cf5..d1da39b 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -51,6 +51,7 @@ struct kevent_copyops;
 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);
@@ -141,6 +142,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,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-amd64/attachments/20100728/3ff41af7/attachment.pgp


More information about the freebsd-amd64 mailing list