Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
6d7d1fde2f | |
![]() |
364524131d | |
![]() |
23b58bb197 | |
![]() |
939acda8af | |
![]() |
d233430274 | |
![]() |
32ab296eef | |
![]() |
1882f0cb4b | |
![]() |
a2ba448e6b | |
![]() |
5db1913741 | |
![]() |
9dbbf36224 | |
![]() |
b9d1f49337 | |
![]() |
4cb644d4b0 |
47
README.md
47
README.md
|
@ -3,7 +3,8 @@ only under linux (though BSD support would probably be feasable).
|
||||||
|
|
||||||
### compiling
|
### compiling
|
||||||
|
|
||||||
Configure QEMU for irix/solaris userland emulation and compile:
|
Configure QEMU for irix/solaris userland emulation and compile (see the original
|
||||||
|
QEMU README for further instructions):
|
||||||
|
|
||||||
```
|
```
|
||||||
configure --target-list=irix-linux-user,irixn32-linux-user,irix64-linux-user,solaris-linux-user
|
configure --target-list=irix-linux-user,irixn32-linux-user,irix64-linux-user,solaris-linux-user
|
||||||
|
@ -12,31 +13,10 @@ make && make install
|
||||||
|
|
||||||
### using
|
### using
|
||||||
|
|
||||||
I recommend using binfmt. Prepare some wrapper scripts for each of the qemu
|
I recommend using binfmt. I have prepared some scripts for this which you can
|
||||||
binaries for irix/solaris using this template:
|
obtain from my qemu-irix-helpers repository at github. Adapt the wrapper scripts
|
||||||
|
to your setup and install them somewhere in your executable path. Activate them
|
||||||
```
|
with the binfmt install scripts.
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
ex=$1; shift
|
|
||||||
a0=$1; shift
|
|
||||||
|
|
||||||
export QEMU_RESERVED_VA=1G
|
|
||||||
export QEMU_LD_PREFIX=<target rootfs>
|
|
||||||
export QEMU_SET_ENV=LANG=C
|
|
||||||
|
|
||||||
exec <qemu binary> -0 $a0 $ex "$@"
|
|
||||||
```
|
|
||||||
|
|
||||||
Install the binfmt (replace the QEMU* environment variables by the location of
|
|
||||||
the wrapper scripts):
|
|
||||||
|
|
||||||
```
|
|
||||||
echo :irix:M::'\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00':'\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef':${QEMUIRIX32}:P > /proc/sys/fs/binfmt_misc/register
|
|
||||||
echo :irixn32:M::'\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20':'\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef':${QEMUIRIXN32}:P > /proc/sys/fs/binfmt_misc/register
|
|
||||||
echo :irix64:M::'\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08':'\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff':${QEMUIRIX64}:P > /proc/sys/fs/binfmt_misc/register
|
|
||||||
echo :solaris:M::'\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02':'\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff':${QEMUSOLARIS32}:P > /proc/sys/fs/binfmt_misc/register
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you should be able to directly execute irix/solaris binaries from the shell.
|
Now you should be able to directly execute irix/solaris binaries from the shell.
|
||||||
As a rather simple test, try:
|
As a rather simple test, try:
|
||||||
|
@ -45,4 +25,19 @@ As a rather simple test, try:
|
||||||
<target rootfs>/bin/ls
|
<target rootfs>/bin/ls
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### notes
|
||||||
|
|
||||||
|
IRIX threading uses a local TLS storage area named PRDA which is privately mapped
|
||||||
|
into each thread at address 0x20000. qemu-irix will emulate this behaviour if
|
||||||
|
QEMU_IRIXPRDA is set in the environment. You most probably need to do so for any
|
||||||
|
IRIX software using multithreading. Be aware that this will noticably harm the
|
||||||
|
performance of the emulation since every memory access is checked for PRDA access
|
||||||
|
(AFAIK it isn't possible to emulate this directly on linux or BSD).
|
||||||
|
|
||||||
|
For conveniance I have also extended the handling of QEMU_LD_PREFIX to allow
|
||||||
|
the specification of multiple paths separated by ':'. That way you can keep the
|
||||||
|
target os root separate from additional software. Moreover, for a noticable
|
||||||
|
speed gain at qemu startup, QEMU_LD_PREFIX is not pre-scanned anymore. Instead,
|
||||||
|
it is now caching any directories accessed by the emulated program.
|
||||||
|
|
||||||
send bug reports, fixes etc to Kai-Uwe Bloem (<derkub@gmail.com>)
|
send bug reports, fixes etc to Kai-Uwe Bloem (<derkub@gmail.com>)
|
||||||
|
|
|
@ -6836,6 +6836,7 @@ case "$target_name" in
|
||||||
solaris)
|
solaris)
|
||||||
TARGET_ARCH=sparc
|
TARGET_ARCH=sparc
|
||||||
TARGET_ABI_DIR=solaris
|
TARGET_ABI_DIR=solaris
|
||||||
|
TARGET_BASE_ARCH=sparc
|
||||||
echo "TARGET_ABI_SOLARIS=y" >> $config_target_mak
|
echo "TARGET_ABI_SOLARIS=y" >> $config_target_mak
|
||||||
;;
|
;;
|
||||||
solaris64)
|
solaris64)
|
||||||
|
|
|
@ -2067,6 +2067,8 @@ abi_ulong sgi_map_elf_image(int image_fd, struct elf_phdr *phdr, int phnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mmap_lock();
|
||||||
|
|
||||||
/* The image indicates that it can be loaded anywhere. Find a
|
/* The image indicates that it can be loaded anywhere. Find a
|
||||||
location that can hold the memory space required. If the
|
location that can hold the memory space required. If the
|
||||||
image is pre-linked, LOADDR will be non-zero. Since we do
|
image is pre-linked, LOADDR will be non-zero. Since we do
|
||||||
|
@ -2113,9 +2115,13 @@ abi_ulong sgi_map_elf_image(int image_fd, struct elf_phdr *phdr, int phnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mmap_unlock();
|
||||||
|
|
||||||
return load_bias + phdr[0].p_vaddr;
|
return load_bias + phdr[0].p_vaddr;
|
||||||
|
|
||||||
exit_perror:
|
exit_perror:
|
||||||
|
mmap_unlock();
|
||||||
|
|
||||||
errmsg = strerror(errno);
|
errmsg = strerror(errno);
|
||||||
fprintf(stderr, "error in syssgi elfmap: %s\n", errmsg);
|
fprintf(stderr, "error in syssgi elfmap: %s\n", errmsg);
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
||||||
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
|
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
|
||||||
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
|
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
|
||||||
#ifdef TIOCGPTPEER
|
#if defined TIOCGPTPEER && defined TARGET_TIOCGPTPEER
|
||||||
IOCTL_SPECIAL(TIOCGPTPEER, 0, do_ioctl_tiocgptpeer, TYPE_INT)
|
IOCTL_SPECIAL(TIOCGPTPEER, 0, do_ioctl_tiocgptpeer, TYPE_INT)
|
||||||
#endif
|
#endif
|
||||||
IOCTL(FIOCLEX, 0, TYPE_NULL)
|
IOCTL(FIOCLEX, 0, TYPE_NULL)
|
||||||
|
|
|
@ -258,6 +258,7 @@
|
||||||
/* SGI specific syssgi calls */
|
/* SGI specific syssgi calls */
|
||||||
#define TARGET_NR_syssgi_sysid (1)
|
#define TARGET_NR_syssgi_sysid (1)
|
||||||
#define TARGET_NR_syssgi_elfmap (68)
|
#define TARGET_NR_syssgi_elfmap (68)
|
||||||
|
#define TARGET_NR_syssgi_getprocattr (85)
|
||||||
#define TARGET_NR_syssgi_rldenv (92)
|
#define TARGET_NR_syssgi_rldenv (92)
|
||||||
#define TARGET_NR_syssgi_tosstsave (108)
|
#define TARGET_NR_syssgi_tosstsave (108)
|
||||||
#define TARGET_NR_syssgi_fdhi (109)
|
#define TARGET_NR_syssgi_fdhi (109)
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/swap.h>
|
#include <sys/swap.h>
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
|
#include <linux/sockios.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <sys/timex.h>
|
#include <sys/timex.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -258,15 +259,9 @@ static inline type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,
|
||||||
#define TARGET_NR__llseek TARGET_NR_llseek
|
#define TARGET_NR__llseek TARGET_NR_llseek
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NR_gettid
|
#define __NR_sys_gettid __NR_gettid
|
||||||
_syscall0(int, gettid)
|
_syscall0(int, sys_gettid)
|
||||||
#else
|
|
||||||
/* This is a replacement for the host gettid() and must return a host
|
|
||||||
errno. */
|
|
||||||
static int gettid(void) {
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
|
#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
|
||||||
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
|
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
|
||||||
#endif
|
#endif
|
||||||
|
@ -5787,7 +5782,7 @@ static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TIOCGPTPEER
|
#if defined TIOCGPTPEER && defined TARGET_TIOCGPTPEER
|
||||||
static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
|
static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||||
int fd, int cmd, abi_long arg)
|
int fd, int cmd, abi_long arg)
|
||||||
{
|
{
|
||||||
|
@ -6447,7 +6442,7 @@ static void *clone_func(void *arg)
|
||||||
cpu = ENV_GET_CPU(env);
|
cpu = ENV_GET_CPU(env);
|
||||||
thread_cpu = cpu;
|
thread_cpu = cpu;
|
||||||
ts = (TaskState *)cpu->opaque;
|
ts = (TaskState *)cpu->opaque;
|
||||||
info->tid = gettid();
|
info->tid = sys_gettid();
|
||||||
task_settid(ts);
|
task_settid(ts);
|
||||||
#ifdef TARGET_ABI_IRIX
|
#ifdef TARGET_ABI_IRIX
|
||||||
/* TODO: which fields in the PRDA are filled in by the IRIX kernel? */
|
/* TODO: which fields in the PRDA are filled in by the IRIX kernel? */
|
||||||
|
@ -6609,9 +6604,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
|
||||||
mapping. We can't repeat the spinlock hack used above because
|
mapping. We can't repeat the spinlock hack used above because
|
||||||
the child process gets its own copy of the lock. */
|
the child process gets its own copy of the lock. */
|
||||||
if (flags & CLONE_CHILD_SETTID)
|
if (flags & CLONE_CHILD_SETTID)
|
||||||
put_user_u32(gettid(), child_tidptr);
|
put_user_u32(sys_gettid(), child_tidptr);
|
||||||
if (flags & CLONE_PARENT_SETTID)
|
if (flags & CLONE_PARENT_SETTID)
|
||||||
put_user_u32(gettid(), parent_tidptr);
|
put_user_u32(sys_gettid(), parent_tidptr);
|
||||||
if (flags & CLONE_SETTLS)
|
if (flags & CLONE_SETTLS)
|
||||||
cpu_set_tls (env, newtls);
|
cpu_set_tls (env, newtls);
|
||||||
if (flags & CLONE_CHILD_CLEARTID)
|
if (flags & CLONE_CHILD_CLEARTID)
|
||||||
|
@ -8866,10 +8861,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
#ifdef TARGET_NR_stime /* not on alpha */
|
#ifdef TARGET_NR_stime /* not on alpha */
|
||||||
case TARGET_NR_stime:
|
case TARGET_NR_stime:
|
||||||
{
|
{
|
||||||
time_t host_time;
|
struct timespec ts;
|
||||||
if (get_user_sal(host_time, arg1))
|
ts.tv_nsec = 0;
|
||||||
|
if (get_user_sal(ts.tv_sec, arg1))
|
||||||
goto efault;
|
goto efault;
|
||||||
ret = get_errno(stime(&host_time));
|
ret = get_errno(clock_settime(CLOCK_REALTIME, &ts));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -12588,7 +12584,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_gettid
|
#ifdef TARGET_NR_gettid
|
||||||
case TARGET_NR_gettid:
|
case TARGET_NR_gettid:
|
||||||
ret = get_errno(gettid());
|
ret = get_errno(sys_gettid());
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_readahead
|
#ifdef TARGET_NR_readahead
|
||||||
|
@ -13861,9 +13857,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
if (arg4) {
|
if (arg4) {
|
||||||
if (copy_from_user_timeval(&tv[0], arg4) ||
|
if (copy_from_user_timeval(&tv[0], arg4) ||
|
||||||
copy_from_user_timeval(&tv[1],
|
copy_from_user_timeval(&tv[1],
|
||||||
arg4 + sizeof(struct target_timeval)))
|
arg4 + sizeof(struct target_timeval))) {
|
||||||
unlock_user(p, arg3, 0);
|
unlock_user(p, arg3, 0);
|
||||||
goto efault;
|
goto efault;
|
||||||
|
}
|
||||||
tvp = tv;
|
tvp = tv;
|
||||||
} else {
|
} else {
|
||||||
tvp = NULL;
|
tvp = NULL;
|
||||||
|
@ -14606,6 +14603,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
case TARGET_NR_syssgi_rldenv:
|
case TARGET_NR_syssgi_rldenv:
|
||||||
case TARGET_NR_syssgi_tosstsave:
|
case TARGET_NR_syssgi_tosstsave:
|
||||||
case TARGET_NR_syssgi_fpbcopy:
|
case TARGET_NR_syssgi_fpbcopy:
|
||||||
|
case TARGET_NR_syssgi_getprocattr: /* ? 2nd=string 3rd=result ptr */
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_syssgi_setgroups:
|
case TARGET_NR_syssgi_setgroups:
|
||||||
|
|
|
@ -1622,7 +1622,7 @@ struct target_stat {
|
||||||
abi_long target_st_ctime;
|
abi_long target_st_ctime;
|
||||||
abi_ulong __unused3;
|
abi_ulong __unused3;
|
||||||
abi_int st_blksize;
|
abi_int st_blksize;
|
||||||
int64_t st_blocks;
|
abi_llong st_blocks;
|
||||||
char st_fstype[16];
|
char st_fstype[16];
|
||||||
abi_long __unused4[8];
|
abi_long __unused4[8];
|
||||||
};
|
};
|
||||||
|
@ -1631,14 +1631,14 @@ struct target_stat {
|
||||||
struct target_stat64 {
|
struct target_stat64 {
|
||||||
abi_ulong st_dev;
|
abi_ulong st_dev;
|
||||||
abi_long st_pad1[3];
|
abi_long st_pad1[3];
|
||||||
uint64_t st_ino;
|
abi_ullong st_ino;
|
||||||
abi_uint st_mode;
|
abi_uint st_mode;
|
||||||
abi_uint st_nlink;
|
abi_uint st_nlink;
|
||||||
abi_int st_uid;
|
abi_int st_uid;
|
||||||
abi_int st_gid;
|
abi_int st_gid;
|
||||||
abi_ulong st_rdev;
|
abi_ulong st_rdev;
|
||||||
abi_long st_pad2[2];
|
abi_long st_pad2[2];
|
||||||
int64_t st_size;
|
abi_llong st_size;
|
||||||
abi_long target_st_atime;
|
abi_long target_st_atime;
|
||||||
abi_ulong __unused1;
|
abi_ulong __unused1;
|
||||||
abi_long target_st_mtime;
|
abi_long target_st_mtime;
|
||||||
|
@ -1646,7 +1646,7 @@ struct target_stat64 {
|
||||||
abi_long target_st_ctime;
|
abi_long target_st_ctime;
|
||||||
abi_ulong __unused3;
|
abi_ulong __unused3;
|
||||||
abi_int st_blksize;
|
abi_int st_blksize;
|
||||||
int64_t st_blocks;
|
abi_llong st_blocks;
|
||||||
char st_fstype[16];
|
char st_fstype[16];
|
||||||
abi_long __unused4[8];
|
abi_long __unused4[8];
|
||||||
};
|
};
|
||||||
|
@ -1977,7 +1977,7 @@ struct target_stat {
|
||||||
struct target_stat64 {
|
struct target_stat64 {
|
||||||
uint32_t st_dev;
|
uint32_t st_dev;
|
||||||
abi_long st_pad0[3]; /* Reserved for st_dev expansion */
|
abi_long st_pad0[3]; /* Reserved for st_dev expansion */
|
||||||
uint64_t st_ino;
|
abi_ullong st_ino;
|
||||||
|
|
||||||
uint32_t st_mode;
|
uint32_t st_mode;
|
||||||
uint32_t st_nlink;
|
uint32_t st_nlink;
|
||||||
|
@ -1987,7 +1987,7 @@ struct target_stat64 {
|
||||||
|
|
||||||
uint32_t st_rdev;
|
uint32_t st_rdev;
|
||||||
abi_long st_pad1[2]; /* Reserved for st_rdev expansion */
|
abi_long st_pad1[2]; /* Reserved for st_rdev expansion */
|
||||||
int64_t st_size;
|
abi_llong st_size;
|
||||||
abi_long st_pad2;
|
abi_long st_pad2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2004,7 +2004,7 @@ struct target_stat64 {
|
||||||
abi_long target_st_ctime_nsec;
|
abi_long target_st_ctime_nsec;
|
||||||
|
|
||||||
abi_long st_blksize;
|
abi_long st_blksize;
|
||||||
int64_t st_blocks;
|
abi_llong st_blocks;
|
||||||
char st_fstype[16];
|
char st_fstype[16];
|
||||||
abi_long st_projid;
|
abi_long st_projid;
|
||||||
abi_long st_pad[7];
|
abi_long st_pad[7];
|
||||||
|
|
|
@ -2696,6 +2696,12 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
|
||||||
case INDEX_op_x86_packus_vec:
|
case INDEX_op_x86_packus_vec:
|
||||||
insn = packus_insn[vece];
|
insn = packus_insn[vece];
|
||||||
goto gen_simd;
|
goto gen_simd;
|
||||||
|
#if TCG_TARGET_REG_BITS == 32
|
||||||
|
case INDEX_op_dup2_vec:
|
||||||
|
/* Constraints have already placed both 32-bit inputs in xmm regs. */
|
||||||
|
insn = OPC_PUNPCKLDQ;
|
||||||
|
goto gen_simd;
|
||||||
|
#endif
|
||||||
gen_simd:
|
gen_simd:
|
||||||
tcg_debug_assert(insn != OPC_UD2);
|
tcg_debug_assert(insn != OPC_UD2);
|
||||||
if (type == TCG_TYPE_V256) {
|
if (type == TCG_TYPE_V256) {
|
||||||
|
@ -3045,6 +3051,9 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||||
case INDEX_op_x86_vperm2i128_vec:
|
case INDEX_op_x86_vperm2i128_vec:
|
||||||
case INDEX_op_x86_punpckl_vec:
|
case INDEX_op_x86_punpckl_vec:
|
||||||
case INDEX_op_x86_punpckh_vec:
|
case INDEX_op_x86_punpckh_vec:
|
||||||
|
#if TCG_TARGET_REG_BITS == 32
|
||||||
|
case INDEX_op_dup2_vec:
|
||||||
|
#endif
|
||||||
return &x_x_x;
|
return &x_x_x;
|
||||||
case INDEX_op_dup_vec:
|
case INDEX_op_dup_vec:
|
||||||
case INDEX_op_shli_vec:
|
case INDEX_op_shli_vec:
|
||||||
|
|
Loading…
Reference in New Issue