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 = ≻
+ 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