From 235970053f1664c9e50f45047548417d2e385cf7 Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 10 Mar 2018 17:05:57 +0100 Subject: [PATCH] irix and solaris userland emulation (linux-user targets irix,irixn32,irix64,solaris) --- configure | 39 +- default-configs/irix-linux-user.mak | 1 + default-configs/irix64-linux-user.mak | 1 + default-configs/irixn32-linux-user.mak | 1 + default-configs/solaris-linux-user.mak | 1 + include/elf.h | 2 + linux-user/elfload.c | 147 +- linux-user/errno_defs.h | 153 ++ linux-user/ioctls.h | 14 + linux-user/irix/syscall_nr.h | 355 +++ linux-user/irix/target_cpu.h | 36 + linux-user/irix/target_elf.h | 20 + linux-user/irix/target_signal.h | 66 + linux-user/irix/target_structs.h | 55 + linux-user/irix/target_syscall.h | 30 + linux-user/irix/termbits.h | 260 ++ linux-user/main.c | 482 +++- linux-user/qemu.h | 42 +- linux-user/signal.c | 751 ++++-- linux-user/socket.h | 88 +- linux-user/solaris/syscall_nr.h | 360 +++ linux-user/solaris/target_cpu.h | 44 + linux-user/solaris/target_elf.h | 18 + linux-user/solaris/target_signal.h | 91 + linux-user/solaris/target_structs.h | 63 + linux-user/solaris/target_syscall.h | 24 + linux-user/solaris/termbits.h | 280 +++ linux-user/sparc/target_signal.h | 10 +- linux-user/sparc64/target_signal.h | 10 +- linux-user/strace.c | 96 +- linux-user/strace.list | 81 +- linux-user/syscall.c | 3051 ++++++++++++++++++++---- linux-user/syscall_defs.h | 666 +++++- target/mips/Makefile.objs | 2 +- target/mips/helper.h | 23 + target/mips/irix_helper.c | 164 ++ target/mips/translate.c | 189 +- target/mips/translate_init.c | 2 + target/sparc/cpu.c | 3 +- target/sparc/cpu.h | 5 + util/path.c | 118 +- 41 files changed, 7005 insertions(+), 839 deletions(-) create mode 100644 default-configs/irix-linux-user.mak create mode 100644 default-configs/irix64-linux-user.mak create mode 100644 default-configs/irixn32-linux-user.mak create mode 100644 default-configs/solaris-linux-user.mak create mode 100644 linux-user/irix/syscall_nr.h create mode 100644 linux-user/irix/target_cpu.h create mode 100644 linux-user/irix/target_elf.h create mode 100644 linux-user/irix/target_signal.h create mode 100644 linux-user/irix/target_structs.h create mode 100644 linux-user/irix/target_syscall.h create mode 100644 linux-user/irix/termbits.h create mode 100644 linux-user/solaris/syscall_nr.h create mode 100644 linux-user/solaris/target_cpu.h create mode 100644 linux-user/solaris/target_elf.h create mode 100644 linux-user/solaris/target_signal.h create mode 100644 linux-user/solaris/target_structs.h create mode 100644 linux-user/solaris/target_syscall.h create mode 100644 linux-user/solaris/termbits.h create mode 100644 target/mips/irix_helper.c diff --git a/configure b/configure index f74e1f3b7c..c1be5f3508 100755 --- a/configure +++ b/configure @@ -6669,7 +6669,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|aarch64_be|hppa|lm32|m68k|microblaze|irix|irixn32|irix64|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|solaris|solaris64|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -6746,6 +6746,28 @@ case "$target_name" in TARGET_ARCH=microblaze bflt="yes" ;; + irix) + TARGET_ARCH=mips + TARGET_ABI_DIR=irix + TARGET_BASE_ARCH=mips + echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak + echo "TARGET_ABI_IRIX=y" >> $config_target_mak + ;; + irixn32) + TARGET_ARCH=mips64 + TARGET_ABI_DIR=irix + TARGET_BASE_ARCH=mips + echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak + echo "TARGET_ABI32=y" >> $config_target_mak + echo "TARGET_ABI_IRIX=y" >> $config_target_mak + ;; + irix64) + TARGET_ARCH=mips64 + TARGET_ABI_DIR=irix + TARGET_BASE_ARCH=mips + echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak + echo "TARGET_ABI_IRIX=y" >> $config_target_mak + ;; mips|mipsel) TARGET_ARCH=mips echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak @@ -6811,6 +6833,17 @@ case "$target_name" in TARGET_ARCH=sh4 bflt="yes" ;; + solaris) + TARGET_ARCH=sparc + TARGET_ABI_DIR=solaris + echo "TARGET_ABI_SOLARIS=y" >> $config_target_mak + ;; + solaris64) + TARGET_ARCH=sparc64 + TARGET_ABI_DIR=solaris + TARGET_BASE_ARCH=sparc + echo "TARGET_ABI_SOLARIS=y" >> $config_target_mak + ;; sparc) ;; sparc64) @@ -6961,7 +6994,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do microblaze*) disas_config "MICROBLAZE" ;; - mips*) + irix*|mips*) disas_config "MIPS" ;; moxie*) @@ -6985,7 +7018,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do sh4) disas_config "SH4" ;; - sparc*) + solaris*|sparc*) disas_config "SPARC" ;; xtensa*) diff --git a/default-configs/irix-linux-user.mak b/default-configs/irix-linux-user.mak new file mode 100644 index 0000000000..31df57021e --- /dev/null +++ b/default-configs/irix-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips-linux-user diff --git a/default-configs/irix64-linux-user.mak b/default-configs/irix64-linux-user.mak new file mode 100644 index 0000000000..1598bfcf7d --- /dev/null +++ b/default-configs/irix64-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips64-linux-user diff --git a/default-configs/irixn32-linux-user.mak b/default-configs/irixn32-linux-user.mak new file mode 100644 index 0000000000..5b97919794 --- /dev/null +++ b/default-configs/irixn32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mipsn32-linux-user diff --git a/default-configs/solaris-linux-user.mak b/default-configs/solaris-linux-user.mak new file mode 100644 index 0000000000..9c716d1f92 --- /dev/null +++ b/default-configs/solaris-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for sparc-linux-user diff --git a/include/elf.h b/include/elf.h index c0dc9bb5fd..96bb8206e3 100644 --- a/include/elf.h +++ b/include/elf.h @@ -281,6 +281,8 @@ typedef int64_t Elf64_Sxword; #define AT_L2_CACHESHAPE 36 /* bits 4-7: log2 of line size. */ #define AT_L3_CACHESHAPE 37 /* val&~255: cache size. */ +#define AT_SUN_LDDATA 2016 /* Solaris specific, rld data segment */ + typedef struct dynamic{ Elf32_Sword d_tag; union{ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5fc130cc20..a8b3962f06 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -690,6 +690,15 @@ static inline void init_thread(struct target_pt_regs *regs, } #endif + +#ifdef TARGET_ABI_SOLARIS +#define DLINFO_ARCH_ITEMS 1 +#define ARCH_DLINFO \ + do { \ + NEW_AUX_ENT(AT_SUN_LDDATA, (abi_ulong)(interp_info ? interp_info->start_data : 0)); \ + } while (0) +#endif + #endif #ifdef TARGET_PPC @@ -1606,8 +1615,13 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm, guard = qemu_real_host_page_size; } +#ifdef TARGET_ABI_IRIX + error = target_mmap(0x7fff8000 - size - guard, size + guard, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#else error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif if (error == -1) { perror("mmap stack"); exit(-1); @@ -1799,6 +1813,12 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, info->arg_start = u_argv; info->arg_end = u_argv + argc * n; +#ifdef TARGET_ABI_IRIX +#define NEW_AUX_ENT(id, val) do { \ + put_user_u32(id, u_auxv); u_auxv += n; \ + put_user_ual(val, u_auxv); u_auxv += n; \ + } while(0) +#else /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off */ @@ -1806,6 +1826,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, put_user_ual(id, u_auxv); u_auxv += n; \ put_user_ual(val, u_auxv); u_auxv += n; \ } while(0) +#endif #ifdef ARCH_DLINFO /* @@ -1817,7 +1838,11 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* There must be exactly DLINFO_ITEMS entries here, or the assert * on info->auxv_len will trigger. */ +#ifdef TARGET_ABI_IRIX + NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_bias + info->phdr_offset)); +#else NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff)); +#endif NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE, getpagesize()))); @@ -2016,6 +2041,87 @@ exit_errmsg: } +#ifdef TARGET_ABI_IRIX +/* SGI_ELFMAP: Map ELF sections into the address space. + IMAGE_FD is the open file descriptor for the image. +*/ +abi_ulong sgi_map_elf_image(int image_fd, struct elf_phdr *phdr, int phnum) +{ + abi_ulong load_addr, load_bias, loaddr, hiaddr, error; + int i; + const char *errmsg; + + /* Find the maximum size of the image and allocate an appropriate + amount of memory to handle that. */ + loaddr = -1, hiaddr = 0; + for (i = 0; i < phnum; ++i) { + if (phdr[i].p_type == PT_LOAD) { + abi_ulong a = phdr[i].p_vaddr; + if (a < loaddr) { + loaddr = a; + } + a += phdr[i].p_memsz; + if (a > hiaddr) { + hiaddr = a; + } + } + } + + /* The image indicates that it can be loaded anywhere. Find a + location that can hold the memory space required. If the + image is pre-linked, LOADDR will be non-zero. Since we do + not supply MAP_FIXED here we'll use that address if and + only if it remains available. */ + load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, 0); + if (load_addr == -1) { + goto exit_perror; + } + /* unmap to avoid failure if objects would be loaded into a hole */ + target_munmap(load_addr, hiaddr - loaddr); + load_bias = load_addr - loaddr; + + for (i = 0; i < phnum; i++) { + struct elf_phdr *eppnt = phdr + i; + if (eppnt->p_type == PT_LOAD) { + abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em; + int elf_prot = 0; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + + vaddr = load_bias + eppnt->p_vaddr; + vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); + vaddr_ps = TARGET_ELF_PAGESTART(vaddr); + + error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, + elf_prot, MAP_PRIVATE | MAP_FIXED, + image_fd, eppnt->p_offset - vaddr_po); + if (error == -1) { + goto exit_perror; + } + + vaddr_ef = vaddr + eppnt->p_filesz; + vaddr_em = vaddr + eppnt->p_memsz; + + /* If the load segment requests extra zeros (e.g. bss), map it. */ + if (vaddr_ef < vaddr_em) { + zero_bss(vaddr_ef, vaddr_em, elf_prot); + } + } + } + + return load_bias + phdr[0].p_vaddr; + + exit_perror: + errmsg = strerror(errno); + fprintf(stderr, "error in syssgi elfmap: %s\n", errmsg); + return -ENOEXEC; +} +#endif + /* Load an ELF image into the address space. IMAGE_NAME is the filename of the image, to use in error messages. @@ -2099,6 +2205,8 @@ static void load_elf_image(const char *image_name, int image_fd, if (load_addr == -1) { goto exit_perror; } + /* unmap to avoid failure if objects would be loaded into a hole */ + target_munmap(load_addr, hiaddr - loaddr); } else if (pinterp_name != NULL) { /* This is the main executable. Make sure that the low address does not conflict with MMAP_MIN_ADDR or the @@ -2215,6 +2323,11 @@ static void load_elf_image(const char *image_name, int image_fd, } *pinterp_name = interp_name; } +#ifdef TARGET_ABI_IRIX + else if (eppnt->p_type == PT_PHDR) { + info->phdr_offset = eppnt->p_vaddr; + } +#endif } if (info->end_data == 0) { @@ -2230,6 +2343,17 @@ static void load_elf_image(const char *image_name, int image_fd, mmap_unlock(); close(image_fd); +#ifdef TARGET_ABI_IRIX + /* PRDA hack */ + error = target_mmap(0x200000, TARGET_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, + -1, 0); + if (error == -1) { + goto exit_perror; + } + put_user(getpid(), 0x200e00, target_pid_t); + put_user(getpid(), 0x200e40, target_pid_t); +#endif return; exit_read: @@ -2463,6 +2587,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) struct elfhdr elf_ex; char *elf_interpreter = NULL; char *scratch; + abi_ulong top; info->start_mmap = (abi_ulong)ELF_START_MMAP; @@ -2476,7 +2601,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) /* Do this so that we can load the interpreter, if need be. We will change some of these later */ - bprm->p = setup_arg_pages(bprm, info); + bprm->p = top = setup_arg_pages(bprm, info); scratch = g_new0(char, TARGET_PAGE_SIZE); if (STACK_GROWS_DOWN) { @@ -2507,6 +2632,26 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG)); exit(-1); } +#ifdef TARGET_ABI_IRIX + /* page alignment */ + if (bprm->p % TARGET_PAGE_SIZE) { + int o = bprm->p % TARGET_PAGE_SIZE; + int l = top - bprm->p; + int p = bprm->p - o; + char *ptr = lock_user(VERIFY_WRITE, p, l+o, 0); + if (!ptr) { + fprintf(stderr, "%s: %s\n", bprm->filename, strerror(EFAULT)); + exit(-1); + } + memmove(ptr, ptr+o, l); + unlock_user(ptr, p, 1); + /* adjust pointers by alignment offset */ + bprm->p -= o; + info->file_string -= o; + info->arg_strings -= o; + info->env_strings -= o; + } +#endif if (elf_interpreter) { load_elf_interp(elf_interpreter, &interp_info, bprm->buf); diff --git a/linux-user/errno_defs.h b/linux-user/errno_defs.h index 55fbebda51..e15566c9e1 100644 --- a/linux-user/errno_defs.h +++ b/linux-user/errno_defs.h @@ -4,6 +4,158 @@ * * Taken from asm-generic/errno-base.h and asm-generic/errno.h */ +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS +#define TARGET_EPERM 1 /* Operation not permitted */ +#define TARGET_ENOENT 2 /* No such file or directory */ +#define TARGET_ESRCH 3 /* No such process */ +#define TARGET_EINTR 4 /* Interrupted function call */ +#define TARGET_EIO 5 /* I/O error */ +#define TARGET_ENXIO 6 /* No such device or address */ +#define TARGET_E2BIG 7 /* Arg list too long */ +#define TARGET_ENOEXEC 8 /* Exec format error */ +#define TARGET_EBADF 9 /* Bad file number */ +#define TARGET_ECHILD 10 /* No child processes */ +#define TARGET_EAGAIN 11 /* Resource temporarily unavailable */ +#define TARGET_ENOMEM 12 /* Not enough space */ +#define TARGET_EACCES 13 /* Permission denied */ +#define TARGET_EFAULT 14 /* Bad address */ +#define TARGET_ENOTBLK 15 /* Block device required */ +#define TARGET_EBUSY 16 /* Resource busy */ +#define TARGET_EEXIST 17 /* File exists */ +#define TARGET_EXDEV 18 /* Improper link */ +#define TARGET_ENODEV 19 /* No such device */ +#define TARGET_ENOTDIR 20 /* Not a directory */ +#define TARGET_EISDIR 21 /* Is a directory */ +#define TARGET_EINVAL 22 /* Invalid argument */ +#define TARGET_ENFILE 23 /* File table overflow */ +#define TARGET_EMFILE 24 /* Too many open files */ +#define TARGET_ENOTTY 25 /* Inappropriate I/O control operation */ +#define TARGET_ETXTBSY 26 /* Text file busy */ +#define TARGET_EFBIG 27 /* File too large */ +#define TARGET_ENOSPC 28 /* No space left on device */ +#define TARGET_ESPIPE 29 /* Illegal seek */ +#define TARGET_EROFS 30 /* Read only file system */ +#define TARGET_EMLINK 31 /* Too many links */ +#define TARGET_EPIPE 32 /* Broken pipe */ +#define TARGET_EDOM 33 /* Domain error */ +#define TARGET_ERANGE 34 /* Result too large */ +#define TARGET_ENOMSG 35 /* No message of desired type */ +#define TARGET_EIDRM 36 /* Identifier removed */ +#define TARGET_ECHRNG 37 /* Channel number out of range */ +#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ +#define TARGET_EL3HLT 39 /* Level 3 halted */ +#define TARGET_EL3RST 40 /* Level 3 reset */ +#define TARGET_ELNRNG 41 /* Link number out of range */ +#define TARGET_EUNATCH 42 /* Protocol driver not attached */ +#define TARGET_ENOCSI 43 /* No CSI structure available */ +#define TARGET_EL2HLT 44 /* Level 2 halted */ +#define TARGET_EDEADLK 45 /* Resource deadlock avoided */ +#define TARGET_ENOLCK 46 /* No locks available */ +#define TARGET_ECKPT 47 /* POSIX checkpoint/restart error */ + +/* Convergent Error Returns */ +#define TARGET_EBADE 50 /* invalid exchange */ +#define TARGET_EBADR 51 /* invalid request descriptor */ +#define TARGET_EXFULL 52 /* exchange full */ +#define TARGET_ENOANO 53 /* no anode */ +#define TARGET_EBADRQC 54 /* invalid request code */ +#define TARGET_EBADSLT 55 /* invalid slot */ +#define TARGET_EDEADLOCK 56 /* file locking deadlock error */ + +#define TARGET_EBFONT 57 /* bad font file fmt */ + +/* stream problems */ +#define TARGET_ENOSTR 60 /* Device not a stream */ +#define TARGET_ENODATA 61 /* no data (for no delay io) */ +#define TARGET_ETIME 62 /* timer expired */ +#define TARGET_ENOSR 63 /* out of streams resources */ + +#define TARGET_ENONET 64 /* Machine is not on the network */ +#define TARGET_ENOPKG 65 /* Package not installed */ +#define TARGET_EREMOTE 66 /* The object is remote */ +#define TARGET_ENOLINK 67 /* the link has been severed */ +#define TARGET_EADV 68 /* advertise error */ +#define TARGET_ESRMNT 69 /* srmount error */ + +#define TARGET_ECOMM 70 /* Communication error on send */ +#define TARGET_EPROTO 71 /* Protocol error */ +#define TARGET_EMULTIHOP 74 /* multihop attempted */ +#define TARGET_EBADMSG 77 /* Bad message */ +#define TARGET_ENAMETOOLONG 78 /* Filename too long */ +#define TARGET_EOVERFLOW 79 /* value too large to be stored in data type */ +#define TARGET_ENOTUNIQ 80 /* given log. name not unique */ +#define TARGET_EBADFD 81 /* f.d. invalid for this operation */ +#define TARGET_EREMCHG 82 /* Remote address changed */ + +/* shared library problems */ +#define TARGET_ELIBACC 83 /* Can't access a needed shared lib. */ +#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared lib. */ +#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted. */ +#define TARGET_ELIBMAX 86 /* Attempting to link in too many libs. */ +#define TARGET_ELIBEXEC 87 /* Attempting to exec a shared library. */ +#define TARGET_EILSEQ 88 /* Illegal byte sequence. */ +#define TARGET_ENOSYS 89 /* Function not implemented */ +#define TARGET_ELOOP 90 /* Symbolic link loop */ +#define TARGET_ERESTART 91 /* Restartable system call */ +#define TARGET_ESTRPIPE 92 /* if pipe/FIFO, don't sleep in stream head */ + +#define TARGET_ENOTEMPTY 93 /* Directory not empty */ + +#define TARGET_EUSERS 94 /* Too many users (for UFS) */ + +/* BSD Networking Software */ + /* argument errors */ +#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ +#define TARGET_EDESTADDRREQ 96 /* Destination address required */ +#define TARGET_EMSGSIZE 97 /* Inappropriate message buffer length */ +#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ +#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ +#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ +#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ +#define TARGET_EOPNOTSUPP 122 /* Operation not supported on socket */ +#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ +#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by + protocol family */ +#define TARGET_EADDRINUSE 125 /* Address already in use */ +#define TARGET_EADDRNOTAVAIL 126 /* Can't assign requested address */ + +/* operational errors */ +#define TARGET_ENETDOWN 127 /* Network is down */ +#define TARGET_ENETUNREACH 128 /* Network is unreachable */ +#define TARGET_ENETRESET 129 /* Network dropped connection because + of reset */ +#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ +#define TARGET_ECONNRESET 131 /* Connection reset by peer */ +#define TARGET_ENOBUFS 132 /* No buffer space available */ +#define TARGET_EISCONN 133 /* Socket is already connected */ +#define TARGET_ENOTCONN 134 /* Socket is not connected */ + +/* XENIX has 135 - 142 */ +#define TARGET_ESHUTDOWN 143 /* Can't send after socket shutdown */ +#define TARGET_ETOOMANYREFS 144 /* Too many references: can't splice */ +#define TARGET_ETIMEDOUT 145 /* Connection timed out */ +#define TARGET_ECONNREFUSED 146 /* Connection refused */ +#define TARGET_EHOSTDOWN 147 /* Host is down */ +#define TARGET_EHOSTUNREACH 148 /* No route to host */ + +#define TARGET_EWOULDBLOCK TARGET_EAGAIN + +#define TARGET_EALREADY 149 /* operation already in progress */ +#define TARGET_EINPROGRESS 150 /* operation now in progress */ +/* SUN Network File System */ +#define TARGET_ESTALE 151 /* Stale NFS file handle */ + +/* XENIX error numbers */ +#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ +#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ +#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ +#define TARGET_EISNAM 139 /* Is a named type file */ +#define TARGET_EREMOTEIO 140 /* Remote I/O error */ +#define TARGET_EINIT 141 /* Reserved for future */ +#define TARGET_EREMDEV 142 /* Error 142 */ +#define TARGET_ECANCELED 158 /* AIO operation canceled */ + +#else #define TARGET_EPERM 1 /* Operation not permitted */ #define TARGET_ENOENT 2 /* No such file or directory */ #define TARGET_ESRCH 3 /* No such process */ @@ -142,6 +294,7 @@ #define TARGET_ERFKILL 132 /* Operation not possible due to RF-kill */ #define TARGET_EHWPOISON 133 /* Memory page has hardware error */ +#endif /* QEMU internal, not visible to the guest. This is returned when a * system call should be restarted, to tell the main loop that it diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 586c794639..7dea36d8ee 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -1,5 +1,12 @@ /* emulated ioctl list */ +#ifdef TARGET_ABI_IRIX + IOCTL_MAP(TCNGETS, TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL_MAP(TCNSETS, TCSETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL_MAP(TCNSETSF, TCSETSF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL_MAP(TCNSETSW, TCSETSW, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) +#endif + IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) @@ -55,6 +62,7 @@ IOCTL(TIOCMIWAIT, 0, TYPE_INT) IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct))) +#if !defined(TARGET_ABI_IRIX) && !defined(TARGET_ABI_SOLARIS) IOCTL(KIOCSOUND, 0, TYPE_INT) IOCTL(KDMKTONE, 0, TYPE_INT) IOCTL(KDSETMODE, 0, TYPE_INT) @@ -126,6 +134,7 @@ #ifdef CONFIG_FIEMAP IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, MK_PTR(MK_STRUCT(STRUCT_fiemap))) +#endif #endif IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT)) @@ -175,7 +184,11 @@ IOCTL(SIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) /* pid_t */ IOCTL(SIOCGSTAMP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timeval))) IOCTL(SIOCGSTAMPNS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timespec))) +#ifdef TARGET_ABI_IRIX + IOCTL_MAP(SIOCNREAD, FIONREAD, IOC_R, MK_PTR(TYPE_INT)) +#endif +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS IOCTL(RNDGETENTCNT, IOC_R, MK_PTR(TYPE_INT)) IOCTL(RNDADDTOENTCNT, IOC_W, MK_PTR(TYPE_INT)) IOCTL(RNDZAPENTCNT, 0, TYPE_NULL) @@ -438,6 +451,7 @@ MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt, MK_PTR(MK_STRUCT(STRUCT_rtentry))) +#endif #ifdef TARGET_TIOCSTART IOCTL_IGNORE(TIOCSTART) diff --git a/linux-user/irix/syscall_nr.h b/linux-user/irix/syscall_nr.h new file mode 100644 index 0000000000..76eb3fed9b --- /dev/null +++ b/linux-user/irix/syscall_nr.h @@ -0,0 +1,355 @@ +/* + * IRIX syscalls are in the range from 1000 to 1999. + */ +#define TARGET_NR_Linux 1000 + +/* syscalls as per IRIX /usr/include/sys.s */ +#define TARGET_NR_syscall (0+TARGET_NR_Linux) +#define TARGET_NR_exit (1+TARGET_NR_Linux) +#define TARGET_NR_fork (2+TARGET_NR_Linux) +#define TARGET_NR_read (3+TARGET_NR_Linux) +#define TARGET_NR_write (4+TARGET_NR_Linux) +#define TARGET_NR_open (5+TARGET_NR_Linux) +#define TARGET_NR_close (6+TARGET_NR_Linux) +#define TARGET_NR_creat (8+TARGET_NR_Linux) +#define TARGET_NR_link (9+TARGET_NR_Linux) +#define TARGET_NR_unlink (10+TARGET_NR_Linux) +#define TARGET_NR_execv (11+TARGET_NR_Linux) +#define TARGET_NR_chdir (12+TARGET_NR_Linux) +#define TARGET_NR_time (13+TARGET_NR_Linux) +#define TARGET_NR_chmod (15+TARGET_NR_Linux) +#define TARGET_NR_chown (16+TARGET_NR_Linux) +#define TARGET_NR_brk (17+TARGET_NR_Linux) +#define TARGET_NR_stat (18+TARGET_NR_Linux) +#define TARGET_NR_lseek (19+TARGET_NR_Linux) +#define TARGET_NR_getpid (20+TARGET_NR_Linux) +#define TARGET_NR_mount (21+TARGET_NR_Linux) +#define TARGET_NR_umount (22+TARGET_NR_Linux) +#define TARGET_NR_setuid (23+TARGET_NR_Linux) +#define TARGET_NR_getuid (24+TARGET_NR_Linux) +#define TARGET_NR_stime (25+TARGET_NR_Linux) +#define TARGET_NR_ptrace (26+TARGET_NR_Linux) +#define TARGET_NR_alarm (27+TARGET_NR_Linux) +#define TARGET_NR_pause (29+TARGET_NR_Linux) +#define TARGET_NR_utime (30+TARGET_NR_Linux) +#define TARGET_NR_access (33+TARGET_NR_Linux) +#define TARGET_NR_nice (34+TARGET_NR_Linux) +#define TARGET_NR_statfs (35+TARGET_NR_Linux) +#define TARGET_NR_sync (36+TARGET_NR_Linux) +#define TARGET_NR_kill (37+TARGET_NR_Linux) +#define TARGET_NR_fstatfs (38+TARGET_NR_Linux) +#define TARGET_NR_pgrpsys (39+TARGET_NR_Linux) +#define TARGET_NR_syssgi (40+TARGET_NR_Linux) +#define TARGET_NR_dup (41+TARGET_NR_Linux) +#define TARGET_NR_pipe (42+TARGET_NR_Linux) +#define TARGET_NR_times (43+TARGET_NR_Linux) +#define TARGET_NR_profil (44+TARGET_NR_Linux) +#define TARGET_NR_plock (45+TARGET_NR_Linux) +#define TARGET_NR_setgid (46+TARGET_NR_Linux) +#define TARGET_NR_getgid (47+TARGET_NR_Linux) +#define TARGET_NR_msgsys (49+TARGET_NR_Linux) +#define TARGET_NR_sysmips (50+TARGET_NR_Linux) +#define TARGET_NR_acct (51+TARGET_NR_Linux) +#define TARGET_NR_shmsys (52+TARGET_NR_Linux) +#define TARGET_NR_semsys (53+TARGET_NR_Linux) +#define TARGET_NR_ioctl (54+TARGET_NR_Linux) +#define TARGET_NR_uadmin (55+TARGET_NR_Linux) +#define TARGET_NR_sysmp (56+TARGET_NR_Linux) +#define TARGET_NR_utssyssgi (57+TARGET_NR_Linux) +#define TARGET_NR_execve (59+TARGET_NR_Linux) +#define TARGET_NR_umask (60+TARGET_NR_Linux) +#define TARGET_NR_chroot (61+TARGET_NR_Linux) +#define TARGET_NR_fcntl (62+TARGET_NR_Linux) +#define TARGET_NR_ulimit (63+TARGET_NR_Linux) +#define TARGET_NR_getrlimit64 (75+TARGET_NR_Linux) +#define TARGET_NR_setrlimit64 (76+TARGET_NR_Linux) +#define TARGET_NR_nanosleep (77+TARGET_NR_Linux) +#define TARGET_NR_lseek64 (78+TARGET_NR_Linux) +#define TARGET_NR_rmdir (79+TARGET_NR_Linux) +#define TARGET_NR_mkdir (80+TARGET_NR_Linux) +#define TARGET_NR_getdents (81+TARGET_NR_Linux) +#define TARGET_NR_sginap (82+TARGET_NR_Linux) +#define TARGET_NR_sgikopt (83+TARGET_NR_Linux) +#define TARGET_NR_sysfs (84+TARGET_NR_Linux) +#define TARGET_NR_getmsg (85+TARGET_NR_Linux) +#define TARGET_NR_putmsg (86+TARGET_NR_Linux) +#define TARGET_NR_poll (87+TARGET_NR_Linux) +#define TARGET_NR_sigreturn (88+TARGET_NR_Linux) +#define TARGET_NR_accept (89+TARGET_NR_Linux) +#define TARGET_NR_bind (90+TARGET_NR_Linux) +#define TARGET_NR_connect (91+TARGET_NR_Linux) +#define TARGET_NR_gethostid (92+TARGET_NR_Linux) +#define TARGET_NR_getpeername (93+TARGET_NR_Linux) +#define TARGET_NR_getsockname (94+TARGET_NR_Linux) +#define TARGET_NR_getsockopt (95+TARGET_NR_Linux) +#define TARGET_NR_listen (96+TARGET_NR_Linux) +#define TARGET_NR_recv (97+TARGET_NR_Linux) +#define TARGET_NR_recvfrom (98+TARGET_NR_Linux) +#define TARGET_NR_recvmsg (99+TARGET_NR_Linux) +#define TARGET_NR_select (100+TARGET_NR_Linux) +#define TARGET_NR_send (101+TARGET_NR_Linux) +#define TARGET_NR_sendmsg (102+TARGET_NR_Linux) +#define TARGET_NR_sendto (103+TARGET_NR_Linux) +#define TARGET_NR_sethostid (104+TARGET_NR_Linux) +#define TARGET_NR_setsockopt (105+TARGET_NR_Linux) +#define TARGET_NR_shutdown (106+TARGET_NR_Linux) +#define TARGET_NR_socket (107+TARGET_NR_Linux) +#define TARGET_NR_gethostname (108+TARGET_NR_Linux) +#define TARGET_NR_sethostname (109+TARGET_NR_Linux) +#define TARGET_NR_getdomainname (110+TARGET_NR_Linux) +#define TARGET_NR_setdomainname (111+TARGET_NR_Linux) +#define TARGET_NR_truncate (112+TARGET_NR_Linux) +#define TARGET_NR_ftruncate (113+TARGET_NR_Linux) +#define TARGET_NR_rename (114+TARGET_NR_Linux) +#define TARGET_NR_symlink (115+TARGET_NR_Linux) +#define TARGET_NR_readlink (116+TARGET_NR_Linux) +#define TARGET_NR_nfssvc (119+TARGET_NR_Linux) +#define TARGET_NR_getfh (120+TARGET_NR_Linux) +#define TARGET_NR_async_daemons (121+TARGET_NR_Linux) +#define TARGET_NR_exportfs (122+TARGET_NR_Linux) +#define TARGET_NR_setregid (123+TARGET_NR_Linux) +#define TARGET_NR_setreuid (124+TARGET_NR_Linux) +#define TARGET_NR_getitimer (125+TARGET_NR_Linux) +#define TARGET_NR_setitimer (126+TARGET_NR_Linux) +#define TARGET_NR_adjtime (127+TARGET_NR_Linux) +#define TARGET_NR_gettimeofday (128+TARGET_NR_Linux) +#define TARGET_NR_sproc (129+TARGET_NR_Linux) +#define TARGET_NR_sgiprctl (130+TARGET_NR_Linux) +#define TARGET_NR_procblk (131+TARGET_NR_Linux) +#define TARGET_NR_sprocsp (132+TARGET_NR_Linux) +#define TARGET_NR_mmap (134+TARGET_NR_Linux) +#define TARGET_NR_munmap (135+TARGET_NR_Linux) +#define TARGET_NR_mprotect (136+TARGET_NR_Linux) +#define TARGET_NR_msync (137+TARGET_NR_Linux) +#define TARGET_NR_madvise (138+TARGET_NR_Linux) +#define TARGET_NR_pagelock (139+TARGET_NR_Linux) +#define TARGET_NR_getpagesize (140+TARGET_NR_Linux) +#define TARGET_NR_quotactl (141+TARGET_NR_Linux) +#define TARGET_NR_getpgid (143+TARGET_NR_Linux) +#define TARGET_NR_setpgid (144+TARGET_NR_Linux) +#define TARGET_NR_vhangup (145+TARGET_NR_Linux) +#define TARGET_NR_fsync (146+TARGET_NR_Linux) +#define TARGET_NR_fchdir (147+TARGET_NR_Linux) +#define TARGET_NR_getrlimit (148+TARGET_NR_Linux) +#define TARGET_NR_setrlimit (149+TARGET_NR_Linux) +#define TARGET_NR_cacheflush (150+TARGET_NR_Linux) +#define TARGET_NR_cachectl (151+TARGET_NR_Linux) +#define TARGET_NR_fchown (152+TARGET_NR_Linux) +#define TARGET_NR_fchmod (153+TARGET_NR_Linux) +#define TARGET_NR_socketpair (155+TARGET_NR_Linux) +#define TARGET_NR_sysinfosgi (156+TARGET_NR_Linux) +#define TARGET_NR_uname (157+TARGET_NR_Linux) +#define TARGET_NR_xstat (158+TARGET_NR_Linux) +#define TARGET_NR_lxstat (159+TARGET_NR_Linux) +#define TARGET_NR_fxstat (160+TARGET_NR_Linux) +#define TARGET_NR_xmknod (161+TARGET_NR_Linux) +#define TARGET_NR_sigaction (162+TARGET_NR_Linux) +#define TARGET_NR_sigpending (163+TARGET_NR_Linux) +#define TARGET_NR_sigprocmask (164+TARGET_NR_Linux) +#define TARGET_NR_sigsuspend (165+TARGET_NR_Linux) +#define TARGET_NR_sigpoll (166+TARGET_NR_Linux) +#define TARGET_NR_swapctl (167+TARGET_NR_Linux) +#define TARGET_NR_getcontext (168+TARGET_NR_Linux) +#define TARGET_NR_setcontext (169+TARGET_NR_Linux) +#define TARGET_NR_waitid (170+TARGET_NR_Linux) +#define TARGET_NR_sigstack (171+TARGET_NR_Linux) +#define TARGET_NR_sigaltstack (172+TARGET_NR_Linux) +#define TARGET_NR_sigsendset (173+TARGET_NR_Linux) +#define TARGET_NR_statvfs (174+TARGET_NR_Linux) +#define TARGET_NR_fstatvfs (175+TARGET_NR_Linux) +#define TARGET_NR_getpmsg (176+TARGET_NR_Linux) +#define TARGET_NR_putpmsg (177+TARGET_NR_Linux) +#define TARGET_NR_lchown (178+TARGET_NR_Linux) +#define TARGET_NR_priocntl (179+TARGET_NR_Linux) +#define TARGET_NR_ksigqueue (180+TARGET_NR_Linux) +#define TARGET_NR_readv (181+TARGET_NR_Linux) +#define TARGET_NR_writev (182+TARGET_NR_Linux) +#define TARGET_NR_truncate64 (183+TARGET_NR_Linux) +#define TARGET_NR_ftruncate64 (184+TARGET_NR_Linux) +#define TARGET_NR_mmap64 (185+TARGET_NR_Linux) +#define TARGET_NR_dmi (186+TARGET_NR_Linux) +#define TARGET_NR_pread64 (187+TARGET_NR_Linux) +#define TARGET_NR_pwrite64 (188+TARGET_NR_Linux) +#define TARGET_NR_fdatasync (189+TARGET_NR_Linux) +#define TARGET_NR_sgifastpath (190+TARGET_NR_Linux) +#define TARGET_NR_attr_get (191+TARGET_NR_Linux) +#define TARGET_NR_attr_getf (192+TARGET_NR_Linux) +#define TARGET_NR_attr_set (193+TARGET_NR_Linux) +#define TARGET_NR_attr_setf (194+TARGET_NR_Linux) +#define TARGET_NR_attr_remove (195+TARGET_NR_Linux) +#define TARGET_NR_attr_removef (196+TARGET_NR_Linux) +#define TARGET_NR_attr_list (197+TARGET_NR_Linux) +#define TARGET_NR_attr_listf (198+TARGET_NR_Linux) +#define TARGET_NR_attr_multi (199+TARGET_NR_Linux) +#define TARGET_NR_attr_multif (200+TARGET_NR_Linux) +#define TARGET_NR_statvfs64 (201+TARGET_NR_Linux) +#define TARGET_NR_fstatvfs64 (202+TARGET_NR_Linux) +#define TARGET_NR_getmountid (203+TARGET_NR_Linux) +#define TARGET_NR_nsproc (204+TARGET_NR_Linux) +#define TARGET_NR_getdents64 (205+TARGET_NR_Linux) +#define TARGET_NR_afs_syscall (206+TARGET_NR_Linux) +#define TARGET_NR_ngetdents (207+TARGET_NR_Linux) +#define TARGET_NR_ngetdents64 (208+TARGET_NR_Linux) +#define TARGET_NR_sgi_sesmgr (209+TARGET_NR_Linux) +#define TARGET_NR_pidsprocsp (210+TARGET_NR_Linux) +#define TARGET_NR_rexec (211+TARGET_NR_Linux) +#define TARGET_NR_timer_create (212+TARGET_NR_Linux) +#define TARGET_NR_timer_delete (213+TARGET_NR_Linux) +#define TARGET_NR_timer_settime (214+TARGET_NR_Linux) +#define TARGET_NR_timer_gettime (215+TARGET_NR_Linux) +#define TARGET_NR_timer_getoverrun (216+TARGET_NR_Linux) +#define TARGET_NR_sched_rr_get_interval (217+TARGET_NR_Linux) +#define TARGET_NR_sched_yield (218+TARGET_NR_Linux) +#define TARGET_NR_sched_getscheduler (219+TARGET_NR_Linux) +#define TARGET_NR_sched_setscheduler (220+TARGET_NR_Linux) +#define TARGET_NR_sched_getparam (221+TARGET_NR_Linux) +#define TARGET_NR_sched_setparam (222+TARGET_NR_Linux) +#define TARGET_NR_usync_cntl (223+TARGET_NR_Linux) +#define TARGET_NR_psema_cntl (224+TARGET_NR_Linux) +#define TARGET_NR_restartreturn (225+TARGET_NR_Linux) +#define TARGET_NR_sysget (226+TARGET_NR_Linux) +#define TARGET_NR_xpg4_recvmsg (227+TARGET_NR_Linux) +#define TARGET_NR_umfscall (228+TARGET_NR_Linux) +#define TARGET_NR_nsproctid (229+TARGET_NR_Linux) +#define TARGET_NR_rexec_complete (230+TARGET_NR_Linux) +#define TARGET_NR_xpg4_sigaltstack (231+TARGET_NR_Linux) +#define TARGET_NR_xpg4_select (232+TARGET_NR_Linux) +#define TARGET_NR_xpg4_setregid (233+TARGET_NR_Linux) +#define TARGET_NR_linkfollow (234+TARGET_NR_Linux) + + +/* msgsys(cmd, ...), same as solaris... */ +#define TARGET_NR_msgsys_msgget 0 +#define TARGET_NR_msgsys_msgctl 1 +#define TARGET_NR_msgsys_msgrcv 2 +#define TARGET_NR_msgsys_msgsnd 3 + + +/* shmsys(cmd, ...), same as solaris... */ +#define TARGET_NR_shmsys_shmat 0 +#define TARGET_NR_shmsys_shmctl 1 +#define TARGET_NR_shmsys_shmdt 2 +#define TARGET_NR_shmsys_shmget 3 + + +/* semsys(cmd, ...), same as solaris... */ +#define TARGET_NR_semsys_semctl 0 +#define TARGET_NR_semsys_semget 1 +#define TARGET_NR_semsys_semop 2 + + +/* pgrpsys(cmd), same as solaris... */ +#define TARGET_NR_pgrpsys_getpgrp 0 +#define TARGET_NR_pgrpsys_setpgrp 1 + + +/* syssgi(cmd, ...) */ +#define TARGET_NR_syssgi_setsid (20) +#define TARGET_NR_syssgi_setpgid (21) +#define TARGET_NR_syssgi_sysconf (22) +#define TARGET_NR_syssgi_pathconf (23) +#define TARGET_NR_syssgi_setgroups (40) +#define TARGET_NR_syssgi_getgroups (41) +#define TARGET_NR_syssgi_settimeofday (52) +#define TARGET_NR_syssgi_rusage (56) +#define TARGET_NR_syssgi_sigaltstack (60) +#define TARGET_NR_syssgi_getpgid (64) +#define TARGET_NR_syssgi_getsid (65) +/* SGI specific syssgi calls */ +#define TARGET_NR_syssgi_sysid (1) +#define TARGET_NR_syssgi_elfmap (68) +#define TARGET_NR_syssgi_rldenv (92) +#define TARGET_NR_syssgi_tosstsave (108) +#define TARGET_NR_syssgi_fdhi (109) +#define TARGET_NR_syssgi_fpbcopy (129) +#define TARGET_NR_syssgi_getust (130) + + +/* syssgi(sysconf, cmd, ...) */ +#define TARGET_NR_sysconf_childmax (2) +#define TARGET_NR_sysconf_clktick (3) +#define TARGET_NR_sysconf_openmax (5) +#define TARGET_NR_sysconf_pagesize (11) +#define TARGET_NR_sysconf_nprocs (14) +#define TARGET_NR_sysconf_acl (25) +#define TARGET_NR_sysconf_mac (28) +#define TARGET_NR_sysconf_cap (29) + + +/* sysmp(cmd, ...) */ +#define TARGET_NR_sysmp_nprocs (1) +#define TARGET_NR_sysmp_naprocs (2) +#define TARGET_NR_sysmp_pgsize (14) + + +/* prctl(cmd, ...) */ +#define TARGET_NR_prctl_isblocked (2) +#define TARGET_NR_prctl_maxpprocs (5) +#define TARGET_NR_prctl_unblkonexec (6) +#define TARGET_NR_prctl_setexitsig (8) +#define TARGET_NR_prctl_termchild (12) +#define TARGET_NR_prctl_getnshare (14) +#define TARGET_NR_prctl_initthreads (20) +#define TARGET_NR_prctl_threadctl (21) +#define TARGET_NR_prctl_lastshexit (22) + + +/* prctl(TARGET_NR_prctl_threadctl, cmd, ...) */ +#define TARGET_NR_prctl_thread_exit (1) +#define TARGET_NR_prctl_thread_block (2) +#define TARGET_NR_prctl_thread_unblock (3) +#define TARGET_NR_prctl_thread_kill (4) +#define TARGET_NR_prctl_thread_sched (5) + + +/* procblk(cmd, ...) */ +#define TARGET_NR_procblk_block (0) +#define TARGET_NR_procblk_unblock (1) +#define TARGET_NR_procblk_count (2) + + +/* usync_cntl(cmd, ...), list from netbsd 5.2 */ +#define TARGET_NR_usync_block (1) +#define TARGET_NR_usync_intr_block (2) +#define TARGET_NR_usync_unblock_all (3) +#define TARGET_NR_usync_unblock (4) +#define TARGET_NR_usync_notify_register (5) +#define TARGET_NR_usync_notify (6) +#define TARGET_NR_usync_notify_delete (7) +#define TARGET_NR_usync_notify_clear (8) +#define TARGET_NR_usync_get_state (11) +#define TARGET_NR_usync_handoff (12) + + +/* psema_cntl(cmd, ...), list from /usr/sbin/par */ +#define TARGET_NR_psema_open (1) +#define TARGET_NR_psema_close (2) +#define TARGET_NR_psema_unlink (3) +#define TARGET_NR_psema_post (4) +#define TARGET_NR_psema_wait (5) +#define TARGET_NR_psema_trywait (6) +#define TARGET_NR_psema_getvalue (7) +#define TARGET_NR_psema_wait2 (9) + + +/* swapctl(cmd, arg) */ +#define TARGET_NR_swapctl_getfree (103) + + +/* sysinfosgi(cmd, buf, size) */ +#define TARGET_NR_sysinfo_gethostname 2 +#define TARGET_NR_sysinfo_sethostname 258 +#define TARGET_NR_sysinfo_getsrpcdomain 9 +#define TARGET_NR_sysinfo_setsrpcdomain 265 +#define TARGET_NR_sysinfo_sysname 1 +#define TARGET_NR_sysinfo_release 3 +#define TARGET_NR_sysinfo_version 4 +#define TARGET_NR_sysinfo_machine 5 +#define TARGET_NR_sysinfo_cpuarch 6 +#define TARGET_NR_sysinfo_hwserial 7 +#define TARGET_NR_sysinfo_hwproducer 8 +#define TARGET_NR_sysinfo_processors 109 + + +/* utssyssgi(obuf, ibuf, cmd) */ +#define TARGET_NR_utssys_uname (0) diff --git a/linux-user/irix/target_cpu.h b/linux-user/irix/target_cpu.h new file mode 100644 index 0000000000..51b9fecd26 --- /dev/null +++ b/linux-user/irix/target_cpu.h @@ -0,0 +1,36 @@ +/* + * MIPS specific CPU ABI and functions for linux-user + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef IRIX_TARGET_CPU_H +#define IRIX_TARGET_CPU_H + +static inline void cpu_clone_regs(CPUMIPSState *env, target_ulong newsp) +{ + if (newsp) { + env->active_tc.gpr[29] = newsp; + } + env->active_tc.gpr[7] = 0; + env->active_tc.gpr[2] = 0; +} + +static inline void cpu_set_tls(CPUMIPSState *env, target_ulong newtls) +{ + env->active_tc.CP0_UserLocal = newtls; +} + +#endif diff --git a/linux-user/irix/target_elf.h b/linux-user/irix/target_elf.h new file mode 100644 index 0000000000..fa3de8de03 --- /dev/null +++ b/linux-user/irix/target_elf.h @@ -0,0 +1,20 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation, or (at your option) any + * later version. See the COPYING file in the top-level directory. + */ + +#ifndef MIPS_TARGET_ELF_H +#define MIPS_TARGET_ELF_H +static inline const char *cpu_get_model(uint32_t eflags) +{ + /* O32 is MIPS I and MIPS II ISA, N32/N64 is MIPS III and MIPS IV ISA */ + if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_1 || + (eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_2) { + return "24Kf"; // MIPS32 +// return "R4000"; + } + return "5Kf"; // MIPS64 +} +#endif diff --git a/linux-user/irix/target_signal.h b/linux-user/irix/target_signal.h new file mode 100644 index 0000000000..01e461d2b4 --- /dev/null +++ b/linux-user/irix/target_signal.h @@ -0,0 +1,66 @@ +#ifndef IRIX_TARGET_SIGNAL_H +#define IRIX_TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { +#ifdef TARGET_ABI32 + abi_uint ss_sp; +#else + abi_ulong ss_sp; +#endif + uint32_t ss_size; + abi_int ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +{ + return state->active_tc.gpr[29]; +} + +struct target_mcontext32 { + uint32_t gregs[36]; + double fregs[16]; + uint32_t fpcsr; +}; + +struct target_mcontext64 { + uint64_t gregs[37]; + double fregs[32]; + uint32_t fpcsr; +}; + +struct target_mcontext { + union { + struct target_mcontext32 _32; + struct target_mcontext64 _64; + } mc; +}; + +struct target_ucontext { + abi_ulong tuc_flags; +#ifdef TARGET_ABI32 + abi_uint tuc_link; +#else + abi_ulong tuc_link; +#endif + target_sigset_t tuc_sigmask; + struct target_sigaltstack tuc_stack; + struct target_mcontext tuc_mcontext; +}; + +int save_context(CPUMIPSState *regs, struct target_mcontext *sc, int setret); +int restore_context(CPUMIPSState *regs, struct target_mcontext *sc); +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/irix/target_structs.h b/linux-user/irix/target_structs.h new file mode 100644 index 0000000000..021f67db40 --- /dev/null +++ b/linux-user/irix/target_structs.h @@ -0,0 +1,55 @@ +/* + * MIPS specific structures for linux-user + * + * Copyright (c) 2013 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef IRIX_TARGET_STRUCTS_H +#define IRIX_TARGET_STRUCTS_H + +struct target_ipc_perm { + abi_uint uid; /* Owner's user ID. */ + abi_uint gid; /* Owner's group ID. */ + abi_uint cuid; /* Creator's user ID. */ + abi_uint cgid; /* Creator's group ID. */ + abi_uint mode; /* Read/write permission. */ + abi_ulong __seq; /* Sequence number. */ + abi_int __key; /* Key. */ + abi_ulong __pad1[4]; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; /* operation permission struct */ +#ifdef TARGET_ABI32 + abi_int shm_segsz; /* size of segment in bytes */ + abi_ulong shm_amp; + short shm_lkcnt; + short __pad0; +#else + abi_int shm_osegsz; + abi_long shm_segsz; /* size of segment in bytes */ + abi_int __pad0; +#endif + abi_int shm_lpid; /* pid of last shmop */ + abi_int shm_cpid; /* pid of creator */ + abi_ulong shm_nattch; /* number of current attaches */ + abi_ulong shm_cnattch; /* number of current attaches */ + abi_ulong shm_atime; /* time of last shmat() */ + abi_ulong shm_dtime; /* time of last shmdt() */ + abi_ulong shm_ctime; /* time of last change by shmctl() */ + abi_ulong __pad1[4]; +}; + +#endif diff --git a/linux-user/irix/target_syscall.h b/linux-user/irix/target_syscall.h new file mode 100644 index 0000000000..581d8bc829 --- /dev/null +++ b/linux-user/irix/target_syscall.h @@ -0,0 +1,30 @@ +#ifndef IRIX_TARGET_SYSCALL_H +#define IRIX_TARGET_SYSCALL_H + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; +}; + +#define UNAME_MACHINE "irix" +#define UNAME_MINIMUM_RELEASE "2.6.32" + +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUMIPSState *env) +{ + return 0x40000; +} + +#endif diff --git a/linux-user/irix/termbits.h b/linux-user/irix/termbits.h new file mode 100644 index 0000000000..4bcd45cb48 --- /dev/null +++ b/linux-user/irix/termbits.h @@ -0,0 +1,260 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 23 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ +#ifdef IRIX_NEW_TERMIO + unsigned int c_ospeed; + unsigned int c_ispeed; +#endif + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_BOTHER 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_IEXTEN 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_TOSTOP 0100000 +#define TARGET_ITOSTOP TARGET_TOSTOP + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VMIN 4 +#define TARGET_VTIME 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +/* VDSUSP not supported */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOF 16 +#define TARGET_VEOL 17 + +/* ioctls */ + +#ifdef IRIX_NEW_TERMIO +#define TARGET_TCGETA 0x54c9 +#define TARGET_TCSETA 0x54ca +#define TARGET_TCSETAW 0x54cb +#define TARGET_TCSETAF 0x54cc +#else +#define TARGET_TCGETA 0x5401 +#define TARGET_TCSETA 0x5402 +#define TARGET_TCSETAW 0x5403 +#define TARGET_TCSETAF 0x5404 +#endif + +#define TARGET_TCSBRK 0x5405 +#define TARGET_TCXONC 0x5406 +#define TARGET_TCFLSH 0x5407 + +#define TARGET_TCGETS 0x540d +#define TARGET_TCSETS 0x540e +#define TARGET_TCSETSW 0x540f +#define TARGET_TCSETSF 0x5410 + +#define TARGET_TCNGETS 0x54d5 +#define TARGET_TCNSETS 0x54d6 +#define TARGET_TCNSETSW 0x54d7 +#define TARGET_TCNSETSF 0x54d8 + +#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ +#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ +#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCMGET 0x741d /* get all modem bits */ +#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ +#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ +#define TARGET_TIOCMSET 0x741a /* set all modem bits */ +#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ +#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ +#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ +#define TARGET_TIOCPKT_START 0x08 /* start output */ +#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ +#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ +#define TARGET_TIOCSETD 0x7401 +#define TARGET_TIOCGETD 0x7400 + +#define TARGET_FIOCLEX 0x6601 +#define TARGET_FIONCLEX 0x6602 +#define TARGET_FIOASYNC 0x667d +#define TARGET_FIONBIO 0x667e +#define TARGET_FIOQSIZE 0x667f + +#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ +#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ +#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ + +#define TARGET_FIONREAD 0x467f +#define TARGET_TIOCINQ TARGET_FIONREAD + +#define TARGET_TIOCGETP 0x7408 +#define TARGET_TIOCSETP 0x7409 +#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ + +/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ +/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ +/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ +/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ +/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ + /* 127-124 compat */ + +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +/* I hope the range from 0x5480 on is free ... */ +#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ +#define TARGET_TIOCGSOFTCAR 0x5481 +#define TARGET_TIOCSSOFTCAR 0x5482 +#define TARGET_TIOCLINUX 0x5483 +#define TARGET_TIOCGSERIAL 0x5484 +#define TARGET_TIOCSSERIAL 0x5485 +#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSERCONFIG 0x5488 +#define TARGET_TIOCSERGWILD 0x5489 +#define TARGET_TIOCSERSWILD 0x548a +#define TARGET_TIOCGLCKTRMIOS 0x548b +#define TARGET_TIOCSLCKTRMIOS 0x548c +#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ diff --git a/linux-user/main.c b/linux-user/main.c index 7bc9bc79b0..8f6475bb99 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -126,7 +126,7 @@ int cpu_get_pic_interrupt(CPUX86State *env) /* Helper routines for implementing atomic operations. */ /* Make sure everything is in a consistent state for calling fork(). */ -void fork_start(void) +void fork_start(CPUArchState *env) { start_exclusive(); mmap_fork_start(); @@ -134,21 +134,21 @@ void fork_start(void) cpu_list_lock(); } -void fork_end(int child) +void fork_end(CPUArchState *env, int child) { mmap_fork_end(child); if (child) { - CPUState *cpu, *next_cpu; + CPUState *cpu, *next_cpu, *cur_cpu = ENV_GET_CPU(env); /* Child processes created by fork() only have a single thread. Discard information about the parent threads. */ CPU_FOREACH_SAFE(cpu, next_cpu) { - if (cpu != thread_cpu) { + if (cpu != cur_cpu) { QTAILQ_REMOVE(&cpus, cpu, node); } } qemu_mutex_init(&tb_ctx.tb_lock); qemu_init_cpu_list(); - gdbserver_fork(thread_cpu); + gdbserver_fork(cur_cpu); /* qemu_init_cpu_list() takes care of reinitializing the * exclusive state, so we don't need to end_exclusive() here. */ @@ -1066,7 +1066,7 @@ static void restore_window(CPUSPARCState *env) #endif } -static void flush_windows(CPUSPARCState *env) +void flush_windows(CPUSPARCState *env) { int offset, cwp1; @@ -1158,6 +1158,38 @@ void cpu_loop (CPUSPARCState *env) env->pc = env->npc; env->npc = env->npc + 4; break; +#ifdef TARGET_ABI_SOLARIS + case 0xa4: /* gethrtime() */ + { + struct timespec ts; + unsigned long long tm; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + + tm = ts.tv_sec * 1000000000LL + ts.tv_nsec; + env->regwptr[0] = (uint32_t)(tm >> 32); + env->regwptr[1] = (uint32_t)(tm); + if (do_strace) + gemu_log("%d gethrtime() = %llu\n", getpid(), tm); + } + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case 0xa7: /* gethrestime() */ + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + env->regwptr[0] = ts.tv_sec; + env->regwptr[1] = ts.tv_nsec; + if (do_strace) + gemu_log("%d gethrestime() = %lu\n", getpid(), ts.tv_sec); + } + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; +#endif #ifndef TARGET_SPARC64 case TT_WIN_OVF: /* window overflow */ save_window(env); @@ -1791,8 +1823,273 @@ void cpu_loop(CPUPPCState *env) #ifdef TARGET_MIPS -# ifdef TARGET_ABI_MIPSO32 -# define MIPS_SYS(name, args) args, +# if defined(TARGET_ABI_IRIX) +/* emulating the PRDA is expensive, since for every memory access the address + * has to be examined. Do this only if the user requires it. + */ +int irix_emulate_prda; + +/* + * The N32 ABI takes 64 bit args and return values in a 64 bit register, while + * the O32 ABI splits these in two 32 bit registers. + * Map 64 bit args to 32 bits here to avoid dealing with it in the syscall code. + * Also, a 64 bit return code in 2 32 bit registers must be recombined for N32. + * + * N32 uses the 64 bit syscall version if one is available (e.g. getdents64) + * Map 32 bit system calls to the 64 bit version here as well. + * + * Structure/union argument passing is left aligned. In N32, an object of 32 bit + * is in that case shifted to the upper half of the 64 bit register. + * Thus, in the special case of semsys(SEMCTL...), the 5th argument must be + * dealt with like a 64 bit argument in N32 for the correct value to be passed. + */ +# define SYSCALL_ARGS(n,a64,r64,s) ((n)|(a64)<<4|((r64)<<8)|((s)<<16)) +# define SYSCALL_NARGS(v) ((v)&0xf) /* #registers, incl. padding */ +# define SYSCALL_ARG64(v) (((v)>>4)&0xf) /* position of 64bit arg */ +# define SYSCALL_RET64(v) (((v)>>8)&0x1) /* returns a 64bit value */ +# define SYSCALL_MAP(v) ((v)>>16) /* N32 32bit syscall to 64bit */ +# define _ 0 /* for a better overview */ +# define X 8 /* place holder for "don't know" for proprietary syscalls */ +static const uint32_t mips_syscall_args[] = { /* see IRIX:/usr/include/sys.s */ + SYSCALL_ARGS(8, _, _, _), /* 0: syscall */ + SYSCALL_ARGS(1, _, _, _), /* 1: exit */ + SYSCALL_ARGS(0, _, _, _), /* 2: fork */ + SYSCALL_ARGS(3, _, _, _), /* 3: read */ + SYSCALL_ARGS(3, _, _, _), /* 4: write */ + SYSCALL_ARGS(3, _, _, _), /* 5: open */ + SYSCALL_ARGS(1, _, _, _), /* 6: close */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(2, _, _, _), /* 8: creat */ + SYSCALL_ARGS(2, _, _, _), /* 9: link */ + SYSCALL_ARGS(1, _, _, _), /* 10: unlink */ + SYSCALL_ARGS(2, _, _, _), /* 11: execv */ + SYSCALL_ARGS(1, _, _, _), /* 12: chdir */ + SYSCALL_ARGS(0, _, _, _), /* 13: time */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(2, _, _, _), /* 15: chmod */ + SYSCALL_ARGS(3, _, _, _), /* 16: chown */ + SYSCALL_ARGS(1, _, _, _), /* 17: brk */ + SYSCALL_ARGS(2, _, _, _), /* 18: stat */ + SYSCALL_ARGS(3, _, _, TARGET_NR_lseek64), /* 19: lseek */ + SYSCALL_ARGS(0, _, _, _), /* 20: getpid */ + SYSCALL_ARGS(6, _, _, _), /* 21: mount */ + SYSCALL_ARGS(1, _, _, _), /* 22: umount */ + SYSCALL_ARGS(1, _, _, _), /* 23: setuid */ + SYSCALL_ARGS(0, _, _, _), /* 24: getuid */ + SYSCALL_ARGS(1, _, _, _), /* 25: stime */ + SYSCALL_ARGS(4, _, _, _), /* 26: ptrace */ + SYSCALL_ARGS(1, _, _, _), /* 27: alarm */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(0, _, _, _), /* 29: pause */ + SYSCALL_ARGS(2, _, _, _), /* 30: utime */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(2, _, _, _), /* 33: access */ + SYSCALL_ARGS(1, _, _, _), /* 34: nice */ + SYSCALL_ARGS(4, _, _, _), /* 35: statfs */ + SYSCALL_ARGS(0, _, _, _), /* 36: sync */ + SYSCALL_ARGS(2, _, _, _), /* 37: kill */ + SYSCALL_ARGS(4, _, _, _), /* 38: fstatfs */ + SYSCALL_ARGS(1, _, _, _), /* 39: pgrpsys */ + SYSCALL_ARGS(X, _, _, _), /* 40: syssgi */ + SYSCALL_ARGS(1, _, _, _), /* 41: dup */ + SYSCALL_ARGS(0, _, _, _), /* 42: pipe */ + SYSCALL_ARGS(1, _, _, _), /* 43: times */ + SYSCALL_ARGS(4, _, _, _), /* 44: profil */ + SYSCALL_ARGS(1, _, _, _), /* 45: plock */ + SYSCALL_ARGS(1, _, _, _), /* 46: setgid */ + SYSCALL_ARGS(0, _, _, _), /* 47: getgid */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(6, _, _, _), /* 49: msgsys */ + SYSCALL_ARGS(4, _, _, _), /* 50: sysmips */ + SYSCALL_ARGS(1, _, _, _), /* 51: acct */ + SYSCALL_ARGS(5, _, _, _), /* 52: shmsys */ + SYSCALL_ARGS(5, 5, _, _), /* 53: semsys */ + SYSCALL_ARGS(3, _, _, _), /* 54: ioctl */ + SYSCALL_ARGS(3, _, _, _), /* 55: uadmin */ + SYSCALL_ARGS(X, _, _, _), /* 56: sysmp */ + SYSCALL_ARGS(3, _, _, _), /* 57: utssys */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(3, _, _, _), /* 59: execve */ + SYSCALL_ARGS(1, _, _, _), /* 60: umask */ + SYSCALL_ARGS(1, _, _, _), /* 61: chroot */ + SYSCALL_ARGS(3, _, _, _), /* 62: fcntl */ + SYSCALL_ARGS(2, _, _, _), /* 63: ulimit */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(2, _, _, _), /* 75: getrlimit64 */ + SYSCALL_ARGS(2, _, _, _), /* 76: setrlimit64 */ + SYSCALL_ARGS(2, _, _, _), /* 77: nanosleep */ + SYSCALL_ARGS(5, 2, 1, _), /* 78: lseek64 */ + SYSCALL_ARGS(1, _, _, _), /* 79: rmdir */ + SYSCALL_ARGS(2, _, _, _), /* 80: mkdir */ + SYSCALL_ARGS(3, _, _, TARGET_NR_getdents64),/* 81: getdents */ + SYSCALL_ARGS(1, _, _, _), /* 82: sginap */ + SYSCALL_ARGS(3, _, _, _), /* 83: sgikopt */ + SYSCALL_ARGS(3, _, _, _), /* 84: sysfs */ + SYSCALL_ARGS(4, _, _, _), /* 85: getmsg */ + SYSCALL_ARGS(4, _, _, _), /* 86: putmsg */ + SYSCALL_ARGS(3, _, _, _), /* 87: poll */ + SYSCALL_ARGS(3, _, _, _), /* 88: sigreturn */ + SYSCALL_ARGS(3, _, _, _), /* 89: accept */ + SYSCALL_ARGS(3, _, _, _), /* 90: bind */ + SYSCALL_ARGS(3, _, _, _), /* 91: connect */ + SYSCALL_ARGS(0, _, _, _), /* 92: gethostid */ + SYSCALL_ARGS(3, _, _, _), /* 93: getpeername */ + SYSCALL_ARGS(3, _, _, _), /* 94: getsockname */ + SYSCALL_ARGS(5, _, _, _), /* 95: getsockopt */ + SYSCALL_ARGS(2, _, _, _), /* 96: listen */ + SYSCALL_ARGS(4, _, _, _), /* 97: recv */ + SYSCALL_ARGS(6, _, _, _), /* 98: recvfrom */ + SYSCALL_ARGS(3, _, _, _), /* 99: recvmsg */ + SYSCALL_ARGS(5, _, _, _), /* 100: select */ + SYSCALL_ARGS(4, _, _, _), /* 101: send */ + SYSCALL_ARGS(3, _, _, _), /* 102: sendmsg */ + SYSCALL_ARGS(6, _, _, _), /* 103: sendto */ + SYSCALL_ARGS(1, _, _, _), /* 104: sethostid */ + SYSCALL_ARGS(5, _, _, _), /* 105: setsockopt */ + SYSCALL_ARGS(2, _, _, _), /* 106: shutdown */ + SYSCALL_ARGS(3, _, _, _), /* 107: socket */ + SYSCALL_ARGS(2, _, _, _), /* 108: gethostname */ + SYSCALL_ARGS(2, _, _, _), /* 109: sethostname */ + SYSCALL_ARGS(2, _, _, _), /* 110: getdomainname */ + SYSCALL_ARGS(2, _, _, _), /* 111: setdomainname */ + SYSCALL_ARGS(2, _, _, TARGET_NR_truncate64),/* 112: truncate */ + SYSCALL_ARGS(2, _, _, TARGET_NR_ftruncate64),/* 113: ftruncate */ + SYSCALL_ARGS(2, _, _, _), /* 114: rename */ + SYSCALL_ARGS(2, _, _, _), /* 115: symlink */ + SYSCALL_ARGS(3, _, _, _), /* 116: readlink */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(X, _, _, _), /* 119: nfssvc */ + SYSCALL_ARGS(X, _, _, _), /* 120: getfh */ + SYSCALL_ARGS(X, _, _, _), /* 121: async_daemon */ + SYSCALL_ARGS(X, _, _, _), /* 122: exportfs */ + SYSCALL_ARGS(2, _, _, _), /* 123: setregid */ + SYSCALL_ARGS(2, _, _, _), /* 123: setreuid */ + SYSCALL_ARGS(2, _, _, _), /* 125: getitimer */ + SYSCALL_ARGS(3, _, _, _), /* 126: setitimer */ + SYSCALL_ARGS(2, _, _, _), /* 127: adjtime */ + SYSCALL_ARGS(1, _, _, _), /* 128: gettimeofday */ + SYSCALL_ARGS(3, _, _, _), /* 129: sproc */ + SYSCALL_ARGS(3, _, _, _), /* 130: prctl */ + SYSCALL_ARGS(3, _, _, _), /* 131: procblk */ + SYSCALL_ARGS(5, _, _, _), /* 132: sprocsp */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(6, _, _, TARGET_NR_mmap64), /* 134: mmap */ + SYSCALL_ARGS(2, _, _, _), /* 135: munmap */ + SYSCALL_ARGS(3, _, _, _), /* 136: mprotect */ + SYSCALL_ARGS(3, _, _, _), /* 137: msync */ + SYSCALL_ARGS(3, _, _, _), /* 138: madvise */ + SYSCALL_ARGS(3, _, _, _), /* 139: pagelock */ + SYSCALL_ARGS(0, _, _, _), /* 140: getpagesize */ + SYSCALL_ARGS(4, _, _, _), /* 141: quotactl */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(1, _, _, _), /* 143: getpgid */ + SYSCALL_ARGS(2, _, _, _), /* 144: setpgid */ + SYSCALL_ARGS(0, _, _, _), /* 145: vhangup */ + SYSCALL_ARGS(1, _, _, _), /* 146: fsync */ + SYSCALL_ARGS(1, _, _, _), /* 147: fchdir */ + SYSCALL_ARGS(2, _, _, TARGET_NR_getrlimit64),/* 148: getrlimit */ + SYSCALL_ARGS(2, _, _, TARGET_NR_setrlimit64),/* 149: setrlimit */ + SYSCALL_ARGS(3, _, _, _), /* 150: cacheflush */ + SYSCALL_ARGS(3, _, _, _), /* 151: cachectl */ + SYSCALL_ARGS(3, _, _, _), /* 152: fchown */ + SYSCALL_ARGS(2, _, _, _), /* 153: fchmod */ + SYSCALL_ARGS(_, _, _, _), + SYSCALL_ARGS(4, _, _, _), /* 155: socketpair */ + SYSCALL_ARGS(3, _, _, _), /* 156: sysinfo */ + SYSCALL_ARGS(1, _, _, _), /* 157: uname */ + SYSCALL_ARGS(3, _, _, _), /* 158: xstat */ + SYSCALL_ARGS(3, _, _, _), /* 159: lxstat */ + SYSCALL_ARGS(3, _, _, _), /* 160: fxstat */ + SYSCALL_ARGS(4, _, _, _), /* 161: xmknod */ + SYSCALL_ARGS(4, _, _, _), /* 162: sigaction */ + SYSCALL_ARGS(1, _, _, _), /* 163: sigpending */ + SYSCALL_ARGS(3, _, _, _), /* 164: sigprocmask */ + SYSCALL_ARGS(1, _, _, _), /* 165: sigsuspend */ + SYSCALL_ARGS(3, _, _, _), /* 166: sigpoll */ + SYSCALL_ARGS(2, _, _, _), /* 167: swapctl */ + SYSCALL_ARGS(1, _, _, _), /* 168: getcontext */ + SYSCALL_ARGS(1, _, _, _), /* 169: setcontext */ + SYSCALL_ARGS(5, _, _, _), /* 170: waitsys */ + SYSCALL_ARGS(2, _, _, _), /* 171: sigstack */ + SYSCALL_ARGS(2, _, _, _), /* 172: sigaltstack */ + SYSCALL_ARGS(2, _, _, _), /* 173: sigsendset */ + SYSCALL_ARGS(2, _, _, TARGET_NR_statvfs64), /* 174: statvfs */ + SYSCALL_ARGS(2, _, _, TARGET_NR_fstatvfs64),/* 175: fstatvfs */ + SYSCALL_ARGS(5, _, _, _), /* 176: getpmsg */ + SYSCALL_ARGS(5, _, _, _), /* 177: putpmsg */ + SYSCALL_ARGS(3, _, _, _), /* 178: lchown */ + SYSCALL_ARGS(0, _, _, _), /* 179: priocntl */ + SYSCALL_ARGS(X, _, _, _), /* 180: ksigqueue */ + SYSCALL_ARGS(3, _, _, _), /* 181: readv */ + SYSCALL_ARGS(3, _, _, _), /* 182: writev */ + SYSCALL_ARGS(4, 2, _, _), /* 183: truncate64 */ + SYSCALL_ARGS(4, 2, _, _), /* 184: ftruncate64 */ + SYSCALL_ARGS(8, 6, _, _), /* 185: mmap64 */ + SYSCALL_ARGS(X, _, _, _), /* 186: dmi */ + SYSCALL_ARGS(6, 4, _, _), /* 187: pread64 */ + SYSCALL_ARGS(6, 4, _, _), /* 188: pwrite64 */ + SYSCALL_ARGS(1, _, _, _), /* 189: fdatasync */ + SYSCALL_ARGS(X, _, _, _), /* 190: sgifastpath */ + SYSCALL_ARGS(5, _, _, _), /* 191: attr_get */ + SYSCALL_ARGS(5, _, _, _), /* 192: attr_getf */ + SYSCALL_ARGS(5, _, _, _), /* 193: attr_set */ + SYSCALL_ARGS(5, _, _, _), /* 194: attr_setf */ + SYSCALL_ARGS(3, _, _, _), /* 195: attr_remove */ + SYSCALL_ARGS(3, _, _, _), /* 196: attr_removef */ + SYSCALL_ARGS(5, _, _, _), /* 197: attr_list */ + SYSCALL_ARGS(5, _, _, _), /* 198: attr_listf */ + SYSCALL_ARGS(4, _, _, _), /* 199: attr_multi */ + SYSCALL_ARGS(4, _, _, _), /* 200: attr_multif */ + SYSCALL_ARGS(2, _, _, _), /* 201: statvfs64 */ + SYSCALL_ARGS(2, _, _, _), /* 202: fstatvfs64 */ + SYSCALL_ARGS(2, _, _, _), /* 203: getmountid */ + SYSCALL_ARGS(5, _, _, _), /* 204: nsproc */ + SYSCALL_ARGS(3, _, _, _), /* 205: getdents64 */ + SYSCALL_ARGS(X, _, _, _), /* 206: afs_syscall */ + SYSCALL_ARGS(4, _, _, TARGET_NR_ngetdents64),/* 207: ngetdents */ + SYSCALL_ARGS(4, _, _, _), /* 208: ngetdents64 */ + SYSCALL_ARGS(X, _, _, _), /* 209: sgi_sesmgr */ + SYSCALL_ARGS(X, _, _, _), /* 210: pidsprocsp */ + SYSCALL_ARGS(X, _, _, _), /* 211: rexec */ + SYSCALL_ARGS(3, _, _, _), /* 212: timer_create */ + SYSCALL_ARGS(1, _, _, _), /* 213: timer_delete */ + SYSCALL_ARGS(4, _, _, _), /* 214: timer_settime */ + SYSCALL_ARGS(2, _, _, _), /* 215: timer_gettime */ + SYSCALL_ARGS(1, _, _, _), /* 216: timer_getoverrun */ + SYSCALL_ARGS(2, _, _, _), /* 217: sched_rr_get_interval */ + SYSCALL_ARGS(0, _, _, _), /* 218: sched_yield */ + SYSCALL_ARGS(1, _, _, _), /* 219: sched_getscheduler */ + SYSCALL_ARGS(3, _, _, _), /* 220: sched_setscheduler */ + SYSCALL_ARGS(2, _, _, _), /* 221: sched_getparam */ + SYSCALL_ARGS(2, _, _, _), /* 222: sched_setparam */ + SYSCALL_ARGS(2, _, _, _), /* 223: usync_cntl */ + SYSCALL_ARGS(5, _, _, _), /* 224: psema_cntl */ + SYSCALL_ARGS(X, _, _, _), /* 225: restartreturn */ + SYSCALL_ARGS(5, _, _, _), /* 226: sysget */ + SYSCALL_ARGS(3, _, _, _), /* 227: xpg4_recvmsg */ + SYSCALL_ARGS(X, _, _, _), /* 228: umfscall */ + SYSCALL_ARGS(X, _, _, _), /* 229: nsproctid */ + SYSCALL_ARGS(X, _, _, _), /* 230: rexec_complete */ + SYSCALL_ARGS(2, _, _, _), /* 231: xpg4_sigaltstack */ + SYSCALL_ARGS(5, _, _, _), /* 232: xpg4_select */ + SYSCALL_ARGS(2, _, _, _), /* 233: xpg4_setregid */ + SYSCALL_ARGS(2, _, _, _), /* 234: linkfollow */ +}; +# else +# define MIPS_SYS(name, args) args, +# define SYSCALL_NARGS(v) (v) static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_syscall , 8) /* 4000 */ MIPS_SYS(sys_exit , 1) @@ -2160,6 +2457,7 @@ static const uint8_t mips_syscall_args[] = { }; # undef MIPS_SYS # endif /* O32 */ +#define NUM_SYSCALLS (sizeof(mips_syscall_args) / sizeof(*mips_syscall_args)) static int do_store_exclusive(CPUMIPSState *env) { @@ -2241,14 +2539,45 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, return ret; } +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN32) +/* split the arg64'th arg, which is a 64 bit arg in a 64 bit register, into an + * even/odd 32 bit register pair, moving the other args up as necessary. This is + * needed because the syscall ABI for TARGET_ABI32 only knows about 32 bit args. + */ +static void get_args_n32(target_ulong *regs, int arg64, int num, abi_ulong args[8]) +{ + int i, j; + + /* what a nuisance, and all this just for a few of the syscalls :-( */ + if (arg64) { + for (i = 0; i < arg64-1; i++) + args[i] = regs[i]; + args[i] = 0; i += (i & 1); /* align to even register */ + args[i++] = regs[arg64-1] >> 32; + args[i++] = regs[arg64-1]; + /* at most registers are needed for the expanded args */ + for (j = arg64; i < num; j++) + args[i++] = regs[j]; + } else { + for (i = 0; i < num; i++) + args[i] = regs[i]; + } +} +#endif + void cpu_loop(CPUMIPSState *env) { CPUState *cs = CPU(mips_env_get_cpu(env)); target_siginfo_t info; int trapnr; abi_long ret; -# ifdef TARGET_ABI_MIPSO32 unsigned int syscall_num; + int offset = 0; +# ifdef TARGET_ABI_IRIX + TaskState *ts = cs->opaque; + + __put_user(ts->ts_tid, (abi_int *)&ts->prda[0xe00]); + __put_user(ts->ts_tid, (abi_int *)&ts->prda[0xe40]); # endif for(;;) { @@ -2260,17 +2589,23 @@ void cpu_loop(CPUMIPSState *env) switch(trapnr) { case EXCP_SYSCALL: env->active_tc.PC += 4; -# ifdef TARGET_ABI_MIPSO32 - syscall_num = env->active_tc.gpr[2] - 4000; + syscall_num = env->active_tc.gpr[2] - TARGET_NR_Linux; +# ifdef TARGET_ABI_IRIX + /* handle indirect syscalls here, else N32 64 bit args are passed incorrectly */ + offset = (syscall_num == TARGET_NR_syscall - TARGET_NR_Linux); + if (offset) + syscall_num = env->active_tc.gpr[4] - TARGET_NR_Linux; +# endif if (syscall_num >= sizeof(mips_syscall_args)) { ret = -TARGET_ENOSYS; } else { +# ifdef TARGET_ABI_MIPSO32 int nb_args; abi_ulong sp_reg; - abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; + abi_ulong arg4 = 0, arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; - nb_args = mips_syscall_args[syscall_num]; - sp_reg = env->active_tc.gpr[29]; + nb_args = SYSCALL_NARGS(mips_syscall_args[syscall_num]); + sp_reg = env->active_tc.gpr[29] + 4*offset; switch (nb_args) { /* these arguments are taken from the stack */ case 8: @@ -2289,24 +2624,41 @@ void cpu_loop(CPUMIPSState *env) if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) { goto done_syscall; } + case 4: + if (offset && (ret = get_user_ual(arg4, sp_reg + 12)) != 0) { + goto done_syscall; + } default: break; } - ret = do_syscall(env, env->active_tc.gpr[2], - env->active_tc.gpr[4], - env->active_tc.gpr[5], - env->active_tc.gpr[6], - env->active_tc.gpr[7], + ret = do_syscall(env, syscall_num + TARGET_NR_Linux, + env->active_tc.gpr[4+offset], + env->active_tc.gpr[5+offset], + env->active_tc.gpr[6+offset], + offset ? arg4 : env->active_tc.gpr[7], arg5, arg6, arg7, arg8); - } -done_syscall: +done_syscall: ; # else - ret = do_syscall(env, env->active_tc.gpr[2], - env->active_tc.gpr[4], env->active_tc.gpr[5], - env->active_tc.gpr[6], env->active_tc.gpr[7], - env->active_tc.gpr[8], env->active_tc.gpr[9], - env->active_tc.gpr[10], env->active_tc.gpr[11]); +# if defined TARGET_ABI_IRIX && defined TARGET_ABI_MIPSN32 + /* split 64 bit args into 2 32 bit args for N32 */ + int nb_args; + int arg64; + abi_ulong args[8]; + + /* map certain syscalls to their 64 bit version */ + if (SYSCALL_MAP(mips_syscall_args[syscall_num])) + syscall_num = SYSCALL_MAP(mips_syscall_args[syscall_num]) - TARGET_NR_Linux; + nb_args = SYSCALL_NARGS(mips_syscall_args[syscall_num]); + arg64 = SYSCALL_ARG64(mips_syscall_args[syscall_num]); + get_args_n32(&env->active_tc.gpr[4+offset], arg64, nb_args, args); +# else + target_ulong *args = &env->active_tc.gpr[4+offset]; +# endif + ret = do_syscall(env, syscall_num + TARGET_NR_Linux, + args[0], args[1], args[2], args[3], + args[4], args[5], args[6], args[7]); # endif /* O32 */ + } if (ret == -TARGET_ERESTARTSYS) { env->active_tc.PC -= 4; break; @@ -2316,13 +2668,29 @@ done_syscall: Avoid clobbering register state. */ break; } + /* on return: gpr7 = error flag, gpr2/3 = value(s) or error code */ +# if defined TARGET_ABI_IRIX +# if defined TARGET_ABI_MIPSN32 + /* restore a 64 bit retval for N32 */ + if (SYSCALL_RET64(mips_syscall_args[syscall_num])) { + target_ulong tret = ((target_ulong)ret << 32) | env->active_tc.gpr[3]; + env->active_tc.gpr[7] = (tret >= (target_ulong)-1700); + env->active_tc.gpr[2] = (env->active_tc.gpr[7] ? -tret : tret); + } else +# endif + { + env->active_tc.gpr[7] = (ret >= (abi_ulong)-1700); + env->active_tc.gpr[2] = (env->active_tc.gpr[7] ? -ret : ret); + } +# else if ((abi_ulong)ret >= (abi_ulong)-1133) { env->active_tc.gpr[7] = 1; /* error flag */ - ret = -ret; + env->active_tc.gpr[2] = -ret; } else { env->active_tc.gpr[7] = 0; /* error flag */ + env->active_tc.gpr[2] = ret; } - env->active_tc.gpr[2] = ret; +# endif break; case EXCP_TLBL: case EXCP_TLBS: @@ -2342,6 +2710,14 @@ done_syscall: info.si_code = 0; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; +#ifdef TARGET_ABI_IRIX + case EXCP_FPE: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = 0; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; +#endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; @@ -3944,9 +4320,7 @@ void qemu_cpu_kick(CPUState *cpu) void task_settid(TaskState *ts) { - if (ts->ts_tid == 0) { - ts->ts_tid = (pid_t)syscall(SYS_gettid); - } + ts->ts_tid = (pid_t)syscall(SYS_gettid); } void stop_all_tasks(void) @@ -3962,6 +4336,39 @@ void stop_all_tasks(void) void init_task_state(TaskState *ts) { ts->used = 1; + +#ifdef TARGET_ABI_IRIX + pthread_mutex_init(&ts->procblk_mutex, NULL); + pthread_cond_init(&ts->procblk_cond, NULL); +#endif +} + +TaskState *find_task_state(pid_t tid) +{ + CPUState *cpu; + TaskState *ts = NULL; + + for (cpu = first_cpu; cpu; cpu = CPU_NEXT(cpu)) { + ts = cpu->opaque; + if (ts->ts_tid == tid) + break; + } + + return ts; +} + +CPUState *find_cpu_state(pid_t tid) +{ + CPUState *cpu; + TaskState *ts; + + for (cpu = first_cpu; cpu; cpu = CPU_NEXT(cpu)) { + ts = cpu->opaque; + if (ts->ts_tid == tid) + break; + } + + return cpu; } CPUArchState *cpu_copy(CPUArchState *env) @@ -4574,7 +4981,7 @@ int main(int argc, char **argv, char **envp) target_set_brk(info->brk); syscall_init(); - signal_init(); + signal_init(env); /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay generating the prologue until now so that the prologue can take @@ -4856,6 +5263,17 @@ int main(int argc, char **argv, char **envp) } restore_snan_bit_mode(env); } +# if defined TARGET_ABI_IRIX && !defined TARGET_ABI_MIPSO32 + /* TODO: is this OK? */ + if ((info->elf_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_4) { + /* enable MIPS IV COP1X instructions for N32 and N64 */ + env->CP0_Status |= (1 << CP0St_CU3); + env->hflags |= MIPS_HFLAG_COP1X; + } + /* check if PRDA emulation is requested */ + if (getenv("QEMU_IRIXPRDA")) + irix_emulate_prda = 1; +# endif } #elif defined(TARGET_NIOS2) { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index f4b4ca72ad..029bf0f188 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -58,6 +58,9 @@ struct image_info { abi_ulong pt_dynamic_addr; struct image_info *other_info; #endif +#ifdef TARGET_ABI_IRIX + abi_ulong phdr_offset; +#endif }; #ifdef TARGET_I386 @@ -119,6 +122,22 @@ typedef struct TaskState { /* Extra fields for semihosted binaries. */ abi_ulong heap_base; abi_ulong heap_limit; +#endif +#if defined(TARGET_ABI_IRIX) + struct TaskState *parent_task; + abi_ulong ctx_link; + abi_ulong sigtramp; + unsigned char prda[TARGET_PAGE_SIZE]; + int procblk_count; + pthread_mutex_t procblk_mutex; + pthread_cond_t procblk_cond; + int is_pthread; + int is_blocked; + int termchild_sig; + int exit_sig; +#endif +#if defined(TARGET_ABI_SOLARIS) + abi_ulong ctx_link; #endif abi_ulong stack_base; int used; /* non zero if used */ @@ -152,6 +171,8 @@ typedef struct TaskState { extern char *exec_path; void init_task_state(TaskState *ts); +TaskState *find_task_state(pid_t tid); +CPUState *find_cpu_state(pid_t tid); void task_settid(TaskState *); void stop_all_tasks(void); extern const char *qemu_uname_release; @@ -189,6 +210,15 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, uint32_t get_elf_eflags(int fd); int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); +#ifdef TARGET_ABI_IRIX +#ifdef TARGET_ABI_MIPSN64 +struct elf64_phdr; +abi_ulong sgi_map_elf_image(int image_fd, struct elf64_phdr *phdr, int phnum); +#else +struct elf32_phdr; +abi_ulong sgi_map_elf_image(int image_fd, struct elf32_phdr *phdr, int phnum); +#endif +#endif abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len); @@ -205,8 +235,8 @@ void cpu_loop(CPUArchState *env); const char *target_strerror(int err); int get_osversion(void); void init_qemu_uname_release(void); -void fork_start(void); -void fork_end(int child); +void fork_start(CPUArchState *env); +void fork_end(CPUArchState *env, int child); /* Creates the initial guest address space in the host memory space using * the given host start address hint and size. The guest_start parameter @@ -378,7 +408,7 @@ extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); -void signal_init(void); +void signal_init(CPUArchState *env); int queue_signal(CPUArchState *env, int sig, int si_type, target_siginfo_t *info); void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); @@ -387,8 +417,8 @@ int target_to_host_signal(int sig); int host_to_target_signal(int sig); long do_sigreturn(CPUArchState *env); long do_rt_sigreturn(CPUArchState *env); -abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); -int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +abi_long do_sigaltstack(CPUArchState *env, abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); +int do_sigprocmask(CPUArchState *env, int how, const sigset_t *set, sigset_t *oldset); /** * block_signals: block all signals while handling this guest syscall * @@ -407,7 +437,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); * * Return value: non-zero if there was a pending signal, zero if not. */ -int block_signals(void); /* Returns non zero if signal pending */ +int block_signals(CPUArchState *env); /* Returns non zero if signal pending */ #ifdef TARGET_I386 /* vm86.c */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 4d3f244612..827180e969 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -20,6 +20,7 @@ #include "qemu/bitops.h" #include #include +#include #include "qemu.h" #include "qemu-common.h" @@ -80,7 +81,7 @@ static uint8_t host_to_target_signal_table[_NSIG] = { [__SIGRTMIN] = __SIGRTMAX, [__SIGRTMAX] = __SIGRTMIN, }; -static uint8_t target_to_host_signal_table[_NSIG]; +static uint8_t target_to_host_signal_table[TARGET_NSIG]; static inline int on_sig_stack(unsigned long sp) { @@ -103,7 +104,7 @@ int host_to_target_signal(int sig) int target_to_host_signal(int sig) { - if (sig < 0 || sig >= _NSIG) + if (sig < 0 || sig >= TARGET_NSIG) return sig; return target_to_host_signal_table[sig]; } @@ -117,14 +118,18 @@ static inline void target_sigaddset(target_sigset_t *set, int signum) { signum--; abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); - set->sig[signum / TARGET_NSIG_BPW] |= mask; + if (signum < TARGET_NSIG_BPW * TARGET_NSIG_WORDS) + set->sig[signum / TARGET_NSIG_BPW] |= mask; } static inline int target_sigismember(const target_sigset_t *set, int signum) { signum--; abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); - return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0); + if (signum < TARGET_NSIG_BPW * TARGET_NSIG_WORDS) + return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0); + else + return 0; } static void host_to_target_sigset_internal(target_sigset_t *d, @@ -132,7 +137,7 @@ static void host_to_target_sigset_internal(target_sigset_t *d, { int i; target_sigemptyset(d); - for (i = 1; i <= TARGET_NSIG; i++) { + for (i = 1; i <= _NSIG; i++) { if (sigismember(s, i)) { target_sigaddset(d, host_to_target_signal(i)); } @@ -146,7 +151,7 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) host_to_target_sigset_internal(&d1, s); for(i = 0;i < TARGET_NSIG_WORDS; i++) - d->sig[i] = tswapal(d1.sig[i]); + __put_user(d1.sig[i], &d->sig[i]); } static void target_to_host_sigset_internal(sigset_t *d, @@ -154,7 +159,7 @@ static void target_to_host_sigset_internal(sigset_t *d, { int i; sigemptyset(d); - for (i = 1; i <= TARGET_NSIG; i++) { + for (i = 1; i <= TARGET_NSIG_BPW * TARGET_NSIG_WORDS; i++) { if (target_sigismember(s, i)) { sigaddset(d, target_to_host_signal(i)); } @@ -167,7 +172,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) int i; for(i = 0;i < TARGET_NSIG_WORDS; i++) - s1.sig[i] = tswapal(s->sig[i]); + __get_user(s1.sig[i], &s->sig[i]); target_to_host_sigset_internal(d, &s1); } @@ -176,7 +181,11 @@ void host_to_target_old_sigset(abi_ulong *old_sigset, { target_sigset_t d; host_to_target_sigset(&d, sigset); +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + *(abi_uint *)old_sigset = d.sig[0]; +#else *old_sigset = d.sig[0]; +#endif } void target_to_host_old_sigset(sigset_t *sigset, @@ -185,15 +194,20 @@ void target_to_host_old_sigset(sigset_t *sigset, target_sigset_t d; int i; +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + d.sig[0] = *(abi_uint *)old_sigset; +#else d.sig[0] = *old_sigset; +#endif for(i = 1;i < TARGET_NSIG_WORDS; i++) d.sig[i] = 0; target_to_host_sigset(sigset, &d); } -int block_signals(void) +int block_signals(CPUArchState *env) { - TaskState *ts = (TaskState *)thread_cpu->opaque; + CPUState *cpu = ENV_GET_CPU(env); + TaskState *ts = (TaskState *)cpu->opaque; sigset_t set; /* It's OK to block everything including SIGSEGV, because we won't @@ -213,9 +227,10 @@ int block_signals(void) * 0 on success. * If set is NULL, this is guaranteed not to fail. */ -int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) +int do_sigprocmask(CPUArchState *env, int how, const sigset_t *set, sigset_t *oldset) { - TaskState *ts = (TaskState *)thread_cpu->opaque; + CPUState *cpu = ENV_GET_CPU(env); + TaskState *ts = (TaskState *)cpu->opaque; if (oldset) { *oldset = ts->signal_mask; @@ -224,7 +239,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) if (set) { int i; - if (block_signals()) { + if (block_signals(env)) { return -TARGET_ERESTARTSYS; } @@ -254,13 +269,14 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) } #if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \ - !defined(TARGET_NIOS2) + !defined(TARGET_NIOS2) && !defined(TARGET_ABI_SOLARIS) /* Just set the guest's signal mask to the specified value; the * caller is assumed to have called block_signals() already. */ -static void set_sigmask(const sigset_t *set) +static void set_sigmask(CPUArchState *env, const sigset_t *set) { - TaskState *ts = (TaskState *)thread_cpu->opaque; + CPUState *cpu = ENV_GET_CPU(env); + TaskState *ts = (TaskState *)cpu->opaque; ts->signal_mask = *set; } @@ -317,7 +333,9 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, switch (sig) { case TARGET_SIGCHLD: tinfo->_sifields._sigchld._pid = info->si_pid; +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS tinfo->_sifields._sigchld._uid = info->si_uid; +#endif tinfo->_sifields._sigchld._status = host_to_target_waitstatus(info->si_status); tinfo->_sifields._sigchld._utime = info->si_utime; @@ -383,8 +401,10 @@ static void tswap_siginfo(target_siginfo_t *tinfo, case QEMU_SI_CHLD: __put_user(info->_sifields._sigchld._pid, &tinfo->_sifields._sigchld._pid); +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS __put_user(info->_sifields._sigchld._uid, &tinfo->_sifields._sigchld._uid); +#endif __put_user(info->_sifields._sigchld._status, &tinfo->_sifields._sigchld._status); __put_user(info->_sifields._sigchld._utime, @@ -465,9 +485,10 @@ static int core_dump_signal(int sig) } } -void signal_init(void) +void signal_init(CPUArchState *env) { - TaskState *ts = (TaskState *)thread_cpu->opaque; + CPUState *cpu = ENV_GET_CPU(env); + TaskState *ts = (TaskState *)cpu->opaque; struct sigaction act; struct sigaction oact; int i, j; @@ -480,7 +501,8 @@ void signal_init(void) } for(i = 1; i < _NSIG; i++) { j = host_to_target_signal_table[i]; - target_to_host_signal_table[j] = i; + if (j < TARGET_NSIG) + target_to_host_signal_table[j] = i; } /* Set the signal mask from the host mask. */ @@ -517,10 +539,8 @@ void signal_init(void) * also forces the signal to "not blocked, not ignored", but for QEMU * that work is done in process_pending_signals(). */ -static void force_sig(int sig) +static void force_sig(CPUArchState *env, int sig) { - CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; target_siginfo_t info; info.si_signo = sig; @@ -536,7 +556,7 @@ static void force_sig(int sig) * at the point of failure. */ #if !defined(TARGET_RISCV) -static void force_sigsegv(int oldsig) +static void force_sigsegv(CPUArchState *env, int oldsig) { if (oldsig == SIGSEGV) { /* Make sure we don't try to deliver the signal again; this will @@ -544,17 +564,16 @@ static void force_sigsegv(int oldsig) */ sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL; } - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); } #endif #endif /* abort execution with signal */ -static void QEMU_NORETURN dump_core_and_abort(int target_sig) +static void QEMU_NORETURN dump_core_and_abort(CPUArchState *env, int target_sig) { - CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; + CPUState *cpu = ENV_GET_CPU(env); TaskState *ts = (TaskState *)cpu->opaque; int host_sig, core_dumped = 0; struct sigaction act; @@ -633,8 +652,8 @@ static inline void rewind_if_in_safe_syscall(void *puc) static void host_signal_handler(int host_signum, siginfo_t *info, void *puc) { - CPUArchState *env = thread_cpu->env_ptr; - CPUState *cpu = ENV_GET_CPU(env); + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu->env_ptr; TaskState *ts = cpu->opaque; int sig; @@ -683,12 +702,12 @@ static void host_signal_handler(int host_signum, siginfo_t *info, sigdelset(&uc->uc_sigmask, SIGBUS); /* interrupt the virtual CPU as soon as possible */ - cpu_exit(thread_cpu); + cpu_exit(cpu); } /* do_sigaltstack() returns target values and errnos. */ /* compare linux/kernel/signal.c:do_sigaltstack() */ -abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) +abi_long do_sigaltstack(CPUArchState *env, abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { int ret; struct target_sigaltstack oss; @@ -709,7 +728,8 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) #if defined(TARGET_PPC64) /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */ - struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; + CPUState *cpu = ENV_GET_CPU(env); + struct image_info *image = ((TaskState *)cpu->opaque)->info; if (get_ppc64_abi(image) > 1) { minstacksize = 4096; } @@ -760,7 +780,7 @@ out: } /* do_sigaction() return target values and host errnos */ -int do_sigaction(int sig, const struct target_sigaction *act, +int do_sigaction(CPUArchState *env, int sig, const struct target_sigaction *act, struct target_sigaction *oact) { struct target_sigaction *k; @@ -772,7 +792,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, return -TARGET_EINVAL; } - if (block_signals()) { + if (block_signals(env)) { return -TARGET_ERESTARTSYS; } @@ -1168,7 +1188,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } #endif @@ -1264,7 +1284,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } static int @@ -1356,7 +1376,7 @@ long do_sigreturn(CPUX86State *env) } target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); /* restore registers */ if (restore_sigcontext(env, &frame->sc)) @@ -1366,7 +1386,7 @@ long do_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } #endif @@ -1382,13 +1402,13 @@ long do_rt_sigreturn(CPUX86State *env) if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) { goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, + if (do_sigaltstack(env, frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { goto badframe; } @@ -1398,7 +1418,7 @@ long do_rt_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -1523,7 +1543,7 @@ static int target_restore_sigframe(CPUARMState *env, uint64_t pstate; target_to_host_sigset(&set, &sf->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); for (i = 0; i < 31; i++) { __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]); @@ -1629,7 +1649,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(usig); + force_sigsegv(env, usig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -1663,7 +1683,7 @@ long do_rt_sigreturn(CPUARMState *env) goto badframe; } - if (do_sigaltstack(frame_addr + + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { goto badframe; @@ -1674,7 +1694,7 @@ long do_rt_sigreturn(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -1996,7 +2016,7 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: - force_sigsegv(usig); + force_sigsegv(regs, usig); } static void setup_frame_v2(int usig, struct target_sigaction *ka, @@ -2018,7 +2038,7 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: - force_sigsegv(usig); + force_sigsegv(regs, usig); } static void setup_frame(int usig, struct target_sigaction *ka, @@ -2076,7 +2096,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: - force_sigsegv(usig); + force_sigsegv(env, usig); } static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, @@ -2107,7 +2127,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: - force_sigsegv(usig); + force_sigsegv(env, usig); } static void setup_rt_frame(int usig, struct target_sigaction *ka, @@ -2182,7 +2202,7 @@ static long do_sigreturn_v1(CPUARMState *env) } target_to_host_sigset_internal(&host_set, &set); - set_sigmask(&host_set); + set_sigmask(env, &host_set); if (restore_sigcontext(env, &frame->sc)) { goto badframe; @@ -2197,7 +2217,7 @@ static long do_sigreturn_v1(CPUARMState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -2264,7 +2284,7 @@ static int do_sigframe_return_v2(CPUARMState *env, abi_ulong *regspace; target_to_host_sigset(&host_set, &uc->tuc_sigmask); - set_sigmask(&host_set); + set_sigmask(env, &host_set); if (restore_sigcontext(env, &uc->tuc_mcontext)) return 1; @@ -2284,7 +2304,7 @@ static int do_sigframe_return_v2(CPUARMState *env, } } - if (do_sigaltstack(context_addr + if (do_sigaltstack(env, context_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { return 1; @@ -2331,7 +2351,7 @@ static long do_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -2366,13 +2386,13 @@ static long do_rt_sigreturn_v1(CPUARMState *env) } target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); - set_sigmask(&host_set); + set_sigmask(env, &host_set); if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) { goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(env, frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; #if 0 @@ -2385,7 +2405,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -2421,7 +2441,7 @@ static long do_rt_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -2434,6 +2454,208 @@ long do_rt_sigreturn(CPUARMState *env) } } +#elif defined(TARGET_ABI_SOLARIS) + +/* for an explanation of the stack frame layout see http://icps.u-strasbg.fr/ + * people/loechner/public_html/enseignement/SPARC/sparcstack.html + */ + +/* NOTE: Solaris uses setcontext instead of sigreturn */ +/* TODO: 64 bit version of this */ + +/* the signal handling is modelled after the Illuminos source (Solaris 10?) */ +struct target_signal_frame { + int fr_locals[8]; /* saved %l0-7 */ + int fr_ins[8]; /* saved %i0-7 */ + uint32_t fr_stret; /* struct return addr */ + int fr_args[7]; /* arg dump [0-5], more args if any */ + struct target_ucontext fr_uc; +}; + +#define UREG_I0 16 +#define UREG_O0 0 +#define UREG_O1 1 +#define UREG_O2 2 +#define UREG_L0 8 +#define UREG_FP UREG_I6 +#define UREG_SP UREG_O6 + +#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) + +static inline abi_ulong get_sigframe(struct target_sigaction *sa, + CPUSPARCState *env, + unsigned long framesize) +{ + abi_ulong sp; + + sp = env->regwptr[UREG_SP]; + + /* This is the X/Open sanctioned signal stack switching. */ + if (sa->sa_flags & TARGET_SA_ONSTACK) { + if (!on_sig_stack(sp) + && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + return sp - framesize; +} + +int save_context(CPUSPARCState *env, struct target_mcontext *sc, int setret) +{ + struct target_mcontext32 *mc32 = &sc->_32; + abi_ulong *sp; + int i; + + /* flush all but the current window to the stack (saves %l0-7/%i0-7) */ + flush_windows(env); + + /* the stack always points to 64 bytes for the current %l0-7/%i0-7 */ + if (!(sp = lock_user(VERIFY_WRITE, env->regwptr[UREG_SP], 16*4, 0))) + return -1; + for (i = 0; i < 16; i++) + __put_user(env->regwptr[UREG_L0 + i], &sp[i]); + unlock_user(sp, env->regwptr[UREG_SP], 16*4); + + /* all other registers go to the mcontext */ + __put_user(env->psr, &mc32->gregs[0]); + __put_user(env->pc, &mc32->gregs[1]); + __put_user(env->npc, &mc32->gregs[2]); + __put_user(env->y, &mc32->gregs[3]); + for (i=1; i < 8; i++) { + __put_user(env->gregs[i], &mc32->gregs[4+i-1]); + } + for (i=0; i < 8; i++) { + __put_user(env->regwptr[UREG_O0 + i], &mc32->gregs[11+i]); + } + + __put_user(env->fsr, &mc32->fpfsr); + for (i=0; i < 16; i++) { + __put_user(env->fpr[i].d, &mc32->dregs[i]); + } + + /* setup "success" return code for return from getcontext if required */ + if (setret) { + __put_user(env->psr & ~PSR_CARRY, &mc32->gregs[0]); + __put_user(0, &mc32->gregs[11]); + } + + return 0; +} + +int restore_context(CPUSPARCState *env, struct target_mcontext *sc) +{ + struct target_mcontext32 *mc32 = &sc->_32; + abi_ulong *sp; + int i; + + /* clean out windows, if any */ + flush_windows(env); + + /* get current window registers from mcontext (psr,pc,%y,%o0-7,%g1-7) */ + __get_user(env->psr, &mc32->gregs[0]); + __get_user(env->pc, &mc32->gregs[1]); + __get_user(env->npc, &mc32->gregs[2]); + __get_user(env->y, &mc32->gregs[3]); + for (i=1; i < 8; i++) { + __get_user(env->gregs[i], &mc32->gregs[4+i-1]); + } + for (i=0; i < 8; i++) { + __get_user(env->regwptr[UREG_O0 + i], &mc32->gregs[11+i]); + } + + __get_user(env->fsr, &mc32->fpfsr); + for (i=0; i < 16; i++) { + __get_user(env->fpr[i].d, &mc32->dregs[i]); + } + + /* get %l0-7/%i0-7 from the stack */ + if (!(sp = lock_user(VERIFY_READ, env->regwptr[UREG_SP], 16*4, 1))) + return -1; + for (i = 0; i < 16; i++) + __get_user(env->regwptr[UREG_L0 + i], &sp[i]); + unlock_user(sp, env->regwptr[UREG_SP], 0); + + return 0; +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUSPARCState *env) +{ + TaskState *ts = ENV_GET_CPU(env)->opaque; + abi_ulong sf_addr, sinf_addr; + struct target_signal_frame *sf = NULL; + struct target_siginfo *si = NULL; + int sigframe_size, siginfo_size, i; + + /* signal frame setup */ + sigframe_size = NF_ALIGNEDSZ; + siginfo_size = (info ? sizeof(struct target_siginfo) : 0); + sf_addr = get_sigframe(ka, env, sigframe_size + siginfo_size); + sinf_addr = sf_addr + sigframe_size; + + sf = lock_user(VERIFY_WRITE, sf_addr, sizeof(struct target_signal_frame), 0); + if (!sf) + goto sigsegv; + + if (info) { + si = lock_user(VERIFY_WRITE, sinf_addr, sizeof(struct target_siginfo), 0); + if (!si) + goto sigsegv; + } + + /* UC_MCONTEXT */ + if (save_context(env, &sf->fr_uc.tuc_mcontext, 0)) + goto sigsegv; + /* UC_SIGMASK */ + for (i = 0; i < TARGET_NSIG_WORDS; i++) + __put_user(set->sig[i], &sf->fr_uc.tuc_sigmask.sig[i]); + /* UC_STACK */ + __put_user(0, &sf->fr_uc.tuc_stack.ss_sp); + __put_user(0, &sf->fr_uc.tuc_stack.ss_size); + __put_user(0, &sf->fr_uc.tuc_stack.ss_flags); + + __put_user(0x0f, &sf->fr_uc.tuc_flags); + __put_user(ts->ctx_link, (abi_ulong *)&sf->fr_uc.tuc_link); + ts->ctx_link = sf_addr + offsetof(struct target_signal_frame, fr_uc); + + /* setup stack for backtracing */ + for (i = 0; i < 8; i++) + __put_user(env->regwptr[UREG_L0+i], &sf->fr_locals[i]); + for (i = 0; i < 8; i++) + __put_user(env->regwptr[UREG_I0+i], &sf->fr_ins[i]); + + /* store siginfo, if any */ + if (info) + tswap_siginfo(si, info); + + /* setup signal handler parameters */ + env->regwptr[UREG_SP] = sf_addr; + env->regwptr[UREG_O0] = sig; + env->regwptr[UREG_O1] = sinf_addr; + env->regwptr[UREG_O2] = sf_addr + offsetof(struct target_signal_frame, fr_uc); + + /* point pc to signal handler */ + env->pc = ka->_sa_handler; + env->npc = (env->pc + 4); + + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); + unlock_user(si, sinf_addr, sizeof(struct target_siginfo)); + return; +sigsegv: + //fprintf(stderr, "force_sig\n"); + if (sf) + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); + if (si) + unlock_user(si, sinf_addr, sizeof(struct target_siginfo)); + force_sigsegv(env, sig); +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUSPARCState *env) +{ + setup_rt_frame(sig, ka, NULL, set, env); +} + #elif defined(TARGET_SPARC) #define __SUNOS_MAXWIN 31 @@ -2519,16 +2741,16 @@ struct target_rt_signal_frame { qemu_siginfo_fpu_t fpu_state; }; -#define UREG_O0 16 -#define UREG_O6 22 -#define UREG_I0 0 -#define UREG_I1 1 -#define UREG_I2 2 -#define UREG_I3 3 -#define UREG_I4 4 -#define UREG_I5 5 -#define UREG_I6 6 -#define UREG_I7 7 +#define UREG_I0 16 +#define UREG_I6 22 +#define UREG_O0 0 +#define UREG_O1 1 +#define UREG_O2 2 +#define UREG_O3 3 +#define UREG_O4 4 +#define UREG_O5 5 +#define UREG_O6 6 +#define UREG_O7 7 #define UREG_L0 8 #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 @@ -2539,7 +2761,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa, { abi_ulong sp; - sp = env->regwptr[UREG_FP]; + sp = env->regwptr[UREG_SP]; /* This is the X/Open sanctioned signal stack switching. */ if (sa->sa_flags & TARGET_SA_ONSTACK) { @@ -2564,7 +2786,7 @@ setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask) __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } for (i=0; i < 8; i++) { - __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); + __put_user(env->regwptr[UREG_O0 + i], &si->si_regs.u_regs[i+8]); } __put_user(mask, &si->si_mask); return err; @@ -2635,11 +2857,11 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto sigsegv; /* 3. signal handler back-trampoline and parameters */ - env->regwptr[UREG_FP] = sf_addr; - env->regwptr[UREG_I0] = sig; - env->regwptr[UREG_I1] = sf_addr + + env->regwptr[UREG_SP] = sf_addr; + env->regwptr[UREG_O0] = sig; + env->regwptr[UREG_O1] = sf_addr + offsetof(struct target_signal_frame, info); - env->regwptr[UREG_I2] = sf_addr + + env->regwptr[UREG_O2] = sf_addr + offsetof(struct target_signal_frame, info); /* 4. signal handler */ @@ -2647,11 +2869,11 @@ static void setup_frame(int sig, struct target_sigaction *ka, env->npc = (env->pc + 4); /* 5. return to kernel instructions */ if (ka->sa_restorer) { - env->regwptr[UREG_I7] = ka->sa_restorer; + env->regwptr[UREG_O7] = ka->sa_restorer; } else { uint32_t val32; - env->regwptr[UREG_I7] = sf_addr + + env->regwptr[UREG_O7] = sf_addr + offsetof(struct target_signal_frame, insns) - 2 * 4; /* mov __NR_sigreturn, %g1 */ @@ -2672,11 +2894,11 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; #if 0 sigill_and_return: - force_sig(TARGET_SIGILL); + force_sig(env, TARGET_SIGILL); #endif sigsegv: unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - force_sigsegv(sig); + force_sigsegv(env, sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -2695,7 +2917,7 @@ long do_sigreturn(CPUSPARCState *env) sigset_t host_set; int err=0, i; - sf_addr = env->regwptr[UREG_FP]; + sf_addr = env->regwptr[UREG_SP]; trace_user_do_sigreturn(env, sf_addr); if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { goto segv_and_exit; @@ -2727,7 +2949,7 @@ long do_sigreturn(CPUSPARCState *env) __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); } for (i=0; i < 8; i++) { - __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + __get_user(env->regwptr[i + UREG_O0], &sf->info.si_regs.u_regs[i+8]); } /* FIXME: implement FPU save/restore: @@ -2745,7 +2967,7 @@ long do_sigreturn(CPUSPARCState *env) } target_to_host_sigset_internal(&host_set, &set); - set_sigmask(&host_set); + set_sigmask(env, &host_set); if (err) { goto segv_and_exit; @@ -2755,7 +2977,7 @@ long do_sigreturn(CPUSPARCState *env) segv_and_exit: unlock_user_struct(sf, sf_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -2844,7 +3066,7 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong fp, i7, w_addr; unsigned int i; - ucp_addr = env->regwptr[UREG_I0]; + ucp_addr = env->regwptr[UREG_O0]; if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { goto do_sigsegv; } @@ -2854,7 +3076,7 @@ void sparc64_set_context(CPUSPARCState *env) if ((pc | npc) & 3) { goto do_sigsegv; } - if (env->regwptr[UREG_I1]) { + if (env->regwptr[UREG_O1]) { target_sigset_t target_set; sigset_t set; @@ -2869,7 +3091,7 @@ void sparc64_set_context(CPUSPARCState *env) } } target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); } env->pc = pc; env->npc = npc; @@ -2885,19 +3107,19 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7])); - __get_user(env->regwptr[UREG_I0], (&(*grp)[SPARC_MC_O0])); - __get_user(env->regwptr[UREG_I1], (&(*grp)[SPARC_MC_O1])); - __get_user(env->regwptr[UREG_I2], (&(*grp)[SPARC_MC_O2])); - __get_user(env->regwptr[UREG_I3], (&(*grp)[SPARC_MC_O3])); - __get_user(env->regwptr[UREG_I4], (&(*grp)[SPARC_MC_O4])); - __get_user(env->regwptr[UREG_I5], (&(*grp)[SPARC_MC_O5])); - __get_user(env->regwptr[UREG_I6], (&(*grp)[SPARC_MC_O6])); - __get_user(env->regwptr[UREG_I7], (&(*grp)[SPARC_MC_O7])); + __get_user(env->regwptr[UREG_O0], (&(*grp)[SPARC_MC_O0])); + __get_user(env->regwptr[UREG_O1], (&(*grp)[SPARC_MC_O1])); + __get_user(env->regwptr[UREG_O2], (&(*grp)[SPARC_MC_O2])); + __get_user(env->regwptr[UREG_O3], (&(*grp)[SPARC_MC_O3])); + __get_user(env->regwptr[UREG_O4], (&(*grp)[SPARC_MC_O4])); + __get_user(env->regwptr[UREG_O5], (&(*grp)[SPARC_MC_O5])); + __get_user(env->regwptr[UREG_O6], (&(*grp)[SPARC_MC_O6])); + __get_user(env->regwptr[UREG_O7], (&(*grp)[SPARC_MC_O7])); __get_user(fp, &(ucp->tuc_mcontext.mc_fp)); __get_user(i7, &(ucp->tuc_mcontext.mc_i7)); - w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_SP]; if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), abi_ulong) != 0) { goto do_sigsegv; @@ -2930,7 +3152,7 @@ void sparc64_set_context(CPUSPARCState *env) return; do_sigsegv: unlock_user_struct(ucp, ucp_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); } void sparc64_get_context(CPUSPARCState *env) @@ -2945,7 +3167,7 @@ void sparc64_get_context(CPUSPARCState *env) target_sigset_t target_set; sigset_t set; - ucp_addr = env->regwptr[UREG_I0]; + ucp_addr = env->regwptr[UREG_O0]; if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) { goto do_sigsegv; } @@ -2962,7 +3184,7 @@ void sparc64_get_context(CPUSPARCState *env) * have any way to signal a failure or restart this operation since * this is not a normal syscall. */ - err = do_sigprocmask(0, NULL, &set); + err = do_sigprocmask(env, 0, NULL, &set); assert(err == 0); host_to_target_sigset_internal(&target_set, &set); if (TARGET_NSIG_WORDS == 1) { @@ -2991,16 +3213,16 @@ void sparc64_get_context(CPUSPARCState *env) __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5])); __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6])); __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7])); - __put_user(env->regwptr[UREG_I0], &((*grp)[SPARC_MC_O0])); - __put_user(env->regwptr[UREG_I1], &((*grp)[SPARC_MC_O1])); - __put_user(env->regwptr[UREG_I2], &((*grp)[SPARC_MC_O2])); - __put_user(env->regwptr[UREG_I3], &((*grp)[SPARC_MC_O3])); - __put_user(env->regwptr[UREG_I4], &((*grp)[SPARC_MC_O4])); - __put_user(env->regwptr[UREG_I5], &((*grp)[SPARC_MC_O5])); - __put_user(env->regwptr[UREG_I6], &((*grp)[SPARC_MC_O6])); - __put_user(env->regwptr[UREG_I7], &((*grp)[SPARC_MC_O7])); + __put_user(env->regwptr[UREG_O0], &((*grp)[SPARC_MC_O0])); + __put_user(env->regwptr[UREG_O1], &((*grp)[SPARC_MC_O1])); + __put_user(env->regwptr[UREG_O2], &((*grp)[SPARC_MC_O2])); + __put_user(env->regwptr[UREG_O3], &((*grp)[SPARC_MC_O3])); + __put_user(env->regwptr[UREG_O4], &((*grp)[SPARC_MC_O4])); + __put_user(env->regwptr[UREG_O5], &((*grp)[SPARC_MC_O5])); + __put_user(env->regwptr[UREG_O6], &((*grp)[SPARC_MC_O6])); + __put_user(env->regwptr[UREG_O7], &((*grp)[SPARC_MC_O7])); - w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_SP]; fp = i7 = 0; if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), abi_ulong) != 0) { @@ -3033,12 +3255,12 @@ void sparc64_get_context(CPUSPARCState *env) return; do_sigsegv: unlock_user_struct(ucp, ucp_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); } #endif #elif defined(TARGET_MIPS) || defined(TARGET_MIPS64) -# if defined(TARGET_ABI_MIPSO32) +# if defined(TARGET_ABI_MIPSO32) || defined(TARGET_ABI_IRIX) struct target_sigcontext { uint32_t sc_regmask; /* Unused */ uint32_t sc_status; @@ -3081,12 +3303,16 @@ struct target_sigcontext { # endif /* O32 */ struct sigframe { +#ifndef TARGET_ABI_IRIX uint32_t sf_ass[4]; /* argument save space for o32 */ uint32_t sf_code[2]; /* signal trampoline */ +#endif struct target_sigcontext sf_sc; target_sigset_t sf_mask; }; +#ifndef TARGET_ABI_IRIX +/* see linux-user/irix/target_signal.h */ struct target_ucontext { target_ulong tuc_flags; target_ulong tuc_link; @@ -3095,14 +3321,18 @@ struct target_ucontext { struct target_sigcontext tuc_mcontext; target_sigset_t tuc_sigmask; }; +#endif struct target_rt_sigframe { +#ifndef TARGET_ABI_IRIX uint32_t rs_ass[4]; /* argument save space for o32 */ uint32_t rs_code[2]; /* signal trampoline */ +#endif struct target_siginfo rs_info; struct target_ucontext rs_uc; }; +#ifndef TARGET_ABI_IRIX /* Install trampoline to jump back from signal handler */ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) { @@ -3119,6 +3349,7 @@ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) __put_user(0x0000000c , tramp + 1); return err; } +#endif static inline void setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) @@ -3187,13 +3418,86 @@ restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) } } +#ifdef TARGET_ABI_IRIX +int +save_context(CPUMIPSState *regs, struct target_mcontext *sc, int setret) +{ + int err = 0; + int i; + + /* O32 saves a 32 bit context, N32 and N64 save a 64 bit context */ +#ifdef TARGET_ABI_MIPSO32 + struct target_mcontext32 *mc = &sc->mc._32; +#else + struct target_mcontext64 *mc = &sc->mc._64; +#endif + + /* store cpu registers */ + __put_user(regs->active_tc.PC, &mc->gregs[35]); + + __put_user( 0, &mc->gregs[0] ); + for (i = 1; i < 32; i++) { + __put_user( regs->active_tc.gpr[i], &mc->gregs[i] ); + } + + __put_user(regs->active_tc.LO[0], &mc->gregs[32]); + __put_user(regs->active_tc.HI[0], &mc->gregs[33]); + + /* store fpu registers */ + for (i = 0; i < sizeof(mc->fregs)/sizeof(mc->fregs[0]); i++) { + __put_user( regs->active_fpu.fpr[i].d, (uint64_t *)&mc->fregs[i] ); + } + + __put_user( regs->active_fpu.fcr31, &mc->fpcsr ); + + /* set return code from getcontext if required */ + if (setret) { + __put_user( 0, &mc->gregs[2] ); + __put_user( 0, &mc->gregs[7] ); + } + + return err; +} + +int +restore_context(CPUMIPSState *regs, struct target_mcontext *sc) +{ + int err = 0; + int i; + + /* O32 restores a 32 bit context, N32 and N64 restore a 64 bit context */ +#ifdef TARGET_ABI_MIPSO32 + struct target_mcontext32 *mc = &sc->mc._32; +#else + struct target_mcontext64 *mc = &sc->mc._64; +#endif + + /* restore cpu registers */ + __get_user(regs->active_tc.PC, &mc->gregs[35]); + + for (i = 1; i < 32; i++) { + __get_user( regs->active_tc.gpr[i], &mc->gregs[i] ); + } + + __get_user(regs->active_tc.LO[0], &mc->gregs[32]); + __get_user(regs->active_tc.HI[0], &mc->gregs[33]); + + /* restore fpu registers */ + for (i = 0; i < sizeof(mc->fregs)/sizeof(mc->fregs[0]); i++) { + __get_user( regs->active_fpu.fpr[i].d, (uint64_t *)&mc->fregs[i] ); + } + + return err; +} +#endif + /* * Determine which stack to use.. */ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) { - unsigned long sp; + abi_ulong sp; /* Default to using normal stack */ sp = regs->active_tc.gpr[29]; @@ -3222,11 +3526,22 @@ static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env) } } -# if defined(TARGET_ABI_MIPSO32) +# if defined(TARGET_ABI_MIPSO32) || defined(TARGET_ABI_IRIX) +/* IRIX knowhow taken from netbsd-5:/usr/src/sys/compat/irix/irix-signal.[ch]. + * This is special insofar as the signal trampoline is part of libc, and the + * address of it is handed down to the kernel with sigaction. Linux uses the + * trampoline only for syscall(sigreturn), while in IRIX the trampoline controls + * the complete signal handling. It is called instead of the signal handler, + * and is given the signal handler as an argument. + */ + /* compare linux/arch/mips/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct target_sigaction * ka, target_sigset_t *set, CPUMIPSState *regs) { +#ifdef TARGET_ABI_IRIX + TaskState *ts = ENV_GET_CPU(regs)->opaque; +#endif struct sigframe *frame; abi_ulong frame_addr; int i; @@ -3237,7 +3552,9 @@ static void setup_frame(int sig, struct target_sigaction * ka, goto give_sigsegv; } +#ifndef TARGET_ABI_IRIX install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); +#endif setup_sigcontext(regs, &frame->sf_sc); @@ -3251,6 +3568,7 @@ static void setup_frame(int sig, struct target_sigaction * ka, * a0 = signal number * a1 = 0 (should be cause) * a2 = pointer to struct sigcontext + * (a3 = pointer to signal handler) (ABI_IRIX) * * $25 and PC point to the signal handler, $29 points to the * struct sigframe. @@ -3259,17 +3577,23 @@ static void setup_frame(int sig, struct target_sigaction * ka, regs->active_tc.gpr[ 5] = 0; regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc); regs->active_tc.gpr[29] = frame_addr; +#ifdef TARGET_ABI_IRIX + regs->active_tc.gpr[ 7] = ka->_sa_handler; + regs->active_tc.gpr[31] = 0; + regs->active_tc.PC = regs->active_tc.gpr[25] = ts->sigtramp; +#else regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler; +#endif mips_set_hflags_isa_mode_from_pc(regs); unlock_user_struct(frame, frame_addr, 1); return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(regs, sig); } long do_sigreturn(CPUMIPSState *regs) @@ -3280,7 +3604,11 @@ long do_sigreturn(CPUMIPSState *regs) target_sigset_t target_set; int i; +#ifdef TARGET_ABI_IRIX + frame_addr = regs->active_tc.gpr[ 5] - offsetof(struct sigframe, sf_sc); +#else frame_addr = regs->active_tc.gpr[29]; +#endif trace_user_do_sigreturn(regs, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; @@ -3290,7 +3618,7 @@ long do_sigreturn(CPUMIPSState *regs) } target_to_host_sigset_internal(&blocked, &target_set); - set_sigmask(&blocked); + set_sigmask(regs, &blocked); restore_sigcontext(regs, &frame->sf_sc); @@ -3306,15 +3634,17 @@ long do_sigreturn(CPUMIPSState *regs) /* Unreached */ #endif - regs->active_tc.PC = regs->CP0_EPC; - mips_set_hflags_isa_mode_from_pc(regs); - /* I am not sure this is right, but it seems to work - * maybe a problem with nested signals ? */ - regs->CP0_EPC = 0; + if (regs->CP0_EPC) { + regs->active_tc.PC = regs->CP0_EPC; + mips_set_hflags_isa_mode_from_pc(regs); + /* I am not sure this is right, but it seems to work + * maybe a problem with nested signals ? */ + regs->CP0_EPC = 0; + } return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(regs, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } # endif /* O32 */ @@ -3323,6 +3653,9 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUMIPSState *env) { +#ifdef TARGET_ABI_IRIX + TaskState *ts = ENV_GET_CPU(env)->opaque; +#endif struct target_rt_sigframe *frame; abi_ulong frame_addr; int i; @@ -3333,7 +3666,9 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, goto give_sigsegv; } +#ifndef TARGET_ABI_IRIX install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn); +#endif tswap_siginfo(&frame->rs_info, info); @@ -3344,7 +3679,17 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &frame->rs_uc.tuc_stack.ss_flags); +#ifdef TARGET_ABI_IRIX + if (save_context(env, &frame->rs_uc.tuc_mcontext, 0)) + goto give_sigsegv; + __put_user(ts->ctx_link, (abi_ulong *)&frame->rs_uc.tuc_link); + ts->ctx_link = frame_addr + offsetof(struct target_rt_sigframe, rs_uc); + __put_user(0x0f, &frame->rs_uc.tuc_flags); + for (i = 0; i < TARGET_NSIG_WORDS; i++) + __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); +#else setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); +#endif for(i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); @@ -3356,6 +3701,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, * a0 = signal number * a1 = pointer to siginfo_t * a2 = pointer to ucontext_t + * (a3 = pointer to signal handler) (ABI_IRIX) * * $25 and PC point to the signal handler, $29 points to the * struct sigframe. @@ -3366,52 +3712,75 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, env->active_tc.gpr[ 6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc); env->active_tc.gpr[29] = frame_addr; +#ifdef TARGET_ABI_IRIX + /* inform trampoline about this being an rt sginal */ + env->active_tc.gpr[ 4] |= 0x80000000L; + env->active_tc.gpr[ 7] = ka->_sa_handler; + env->active_tc.gpr[31] = 0; + env->active_tc.PC = env->active_tc.gpr[25] = ts->sigtramp; +#else env->active_tc.gpr[31] = frame_addr + offsetof(struct target_rt_sigframe, rs_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler; +#endif mips_set_hflags_isa_mode_from_pc(env); unlock_user_struct(frame, frame_addr, 1); return; give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(env, sig); } long do_rt_sigreturn(CPUMIPSState *env) { +#ifdef TARGET_ABI_IRIX + TaskState *ts = ENV_GET_CPU(env)->opaque; +#endif struct target_rt_sigframe *frame; abi_ulong frame_addr; sigset_t blocked; +#ifdef TARGET_ABI_IRIX + frame_addr = env->active_tc.gpr[ 5] - offsetof(struct target_rt_sigframe, rs_uc); +#else frame_addr = env->active_tc.gpr[29]; +#endif trace_user_do_rt_sigreturn(env, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { goto badframe; } target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); - set_sigmask(&blocked); + set_sigmask(env, &blocked); +#ifdef TARGET_ABI_IRIX + if (restore_context(env, &frame->rs_uc.tuc_mcontext)) + goto badframe; + __get_user(ts->ctx_link, (abi_ulong *)&frame->rs_uc.tuc_link); +#else restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); +#endif - if (do_sigaltstack(frame_addr + + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; - env->active_tc.PC = env->CP0_EPC; - mips_set_hflags_isa_mode_from_pc(env); - /* I am not sure this is right, but it seems to work - * maybe a problem with nested signals ? */ - env->CP0_EPC = 0; + if (env->CP0_EPC) { + env->active_tc.PC = env->CP0_EPC; + mips_set_hflags_isa_mode_from_pc(env); + /* I am not sure this is right, but it seems to work + * maybe a problem with nested signals ? */ + env->CP0_EPC = 0; + } return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -3609,7 +3978,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(regs, sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3672,7 +4041,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(regs, sig); } long do_sigreturn(CPUSH4State *regs) @@ -3699,7 +4068,7 @@ long do_sigreturn(CPUSH4State *regs) goto badframe; target_to_host_sigset_internal(&blocked, &target_set); - set_sigmask(&blocked); + set_sigmask(regs, &blocked); restore_sigcontext(regs, &frame->sc); @@ -3708,7 +4077,7 @@ long do_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(regs, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -3725,11 +4094,11 @@ long do_rt_sigreturn(CPUSH4State *regs) } target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask); - set_sigmask(&blocked); + set_sigmask(regs, &blocked); restore_sigcontext(regs, &frame->uc.tuc_mcontext); - if (do_sigaltstack(frame_addr + + if (do_sigaltstack(regs, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(regs)) == -EFAULT) { goto badframe; @@ -3740,7 +4109,7 @@ long do_rt_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(regs, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_MICROBLAZE) @@ -3919,7 +4288,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sigsegv(sig); + force_sigsegv(env, sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3949,7 +4318,7 @@ long do_sigreturn(CPUMBState *env) __get_user(target_set.sig[i], &frame->extramask[i - 1]); } target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(&frame->uc.tuc_mcontext, env); /* We got here through a sigreturn syscall, our path back is via an @@ -3959,7 +4328,7 @@ long do_sigreturn(CPUMBState *env) unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -4090,7 +4459,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sigsegv(sig); + force_sigsegv(env, sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4121,13 +4490,13 @@ long do_sigreturn(CPUCRISState *env) __get_user(target_set.sig[i], &frame->extramask[i - 1]); } target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(&frame->sc, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -4262,7 +4631,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, __get_user(env->regs[R_SP], &gregs[28]); off = offsetof(struct target_rt_sigframe, uc.tuc_stack); - err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env)); + err = do_sigaltstack(env, frame_addr + off, 0, get_sp_from_cpustate(env)); if (err == -EFAULT) { return 1; } @@ -4332,7 +4701,7 @@ give_sigsegv: if (sig == TARGET_SIGSEGV) { ka->_sa_handler = TARGET_SIG_DFL; } - force_sigsegv(sig); + force_sigsegv(env, sig); return; } @@ -4356,7 +4725,7 @@ long do_rt_sigreturn(CPUNios2State *env) } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - do_sigprocmask(SIG_SETMASK, &set, NULL); + do_sigprocmask(env, SIG_SETMASK, &set, NULL); if (rt_restore_ucontext(env, &frame->uc, &rval)) { goto badframe; @@ -4367,7 +4736,7 @@ long do_rt_sigreturn(CPUNios2State *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return 0; } /* TARGET_NIOS2 */ @@ -4565,7 +4934,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(env, sig); } long do_sigreturn(CPUOpenRISCState *env) @@ -4746,7 +5115,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4801,7 +5170,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } static int @@ -4844,7 +5213,7 @@ long do_sigreturn(CPUS390XState *env) __get_user(target_set.sig[0], &frame->sc.oldmask[0]); target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); /* ~_BLOCKABLE? */ + set_sigmask(env, &set); /* ~_BLOCKABLE? */ if (restore_sigregs(env, &frame->sregs)) { goto badframe; @@ -4854,7 +5223,7 @@ long do_sigreturn(CPUS390XState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -4870,13 +5239,13 @@ long do_rt_sigreturn(CPUS390XState *env) } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); /* ~_BLOCKABLE? */ + set_sigmask(env, &set); /* ~_BLOCKABLE? */ if (restore_sigregs(env, &frame->uc.tuc_mcontext)) { goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0, + if (do_sigaltstack(env, frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { goto badframe; } @@ -4885,7 +5254,7 @@ long do_rt_sigreturn(CPUS390XState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -5358,7 +5727,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(env, sig); } #endif /* !defined(TARGET_PPC64) */ @@ -5373,7 +5742,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, int i, err = 0; #if defined(TARGET_PPC64) struct target_sigcontext *sc = 0; - struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; + CPUState *cpu = ENV_GET_CPU(env); + struct image_info *image = ((TaskState *)cpu->opaque)->info; #endif rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf)); @@ -5459,7 +5829,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); - force_sigsegv(sig); + force_sigsegv(env, sig); } @@ -5483,7 +5853,7 @@ long do_sigreturn(CPUPPCState *env) __get_user(set.sig[1], &sc->_unused[3]); #endif target_to_host_sigset_internal(&blocked, &set); - set_sigmask(&blocked); + set_sigmask(env, &blocked); __get_user(sr_addr, &sc->regs); if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1)) @@ -5497,7 +5867,7 @@ long do_sigreturn(CPUPPCState *env) sigsegv: unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } #endif /* !defined(TARGET_PPC64) */ @@ -5525,7 +5895,7 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig) return 1; target_to_host_sigset_internal(&blocked, &set); - set_sigmask(&blocked); + set_sigmask(env, &blocked); restore_user_regs(env, mcp, sig); unlock_user_struct(mcp, mcp_addr, 1); @@ -5544,7 +5914,7 @@ long do_rt_sigreturn(CPUPPCState *env) if (do_setcontext(&rt_sf->uc, env, 1)) goto sigsegv; - do_sigaltstack(rt_sf_addr + do_sigaltstack(env, rt_sf_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, env->gpr[1]); @@ -5553,7 +5923,7 @@ long do_rt_sigreturn(CPUPPCState *env) sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -5711,7 +6081,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } static inline void target_rt_save_fpu_state(struct target_ucontext *uc, @@ -5894,7 +6264,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sigsegv(sig); + force_sigsegv(env, sig); } long do_sigreturn(CPUM68KState *env) @@ -5918,7 +6288,7 @@ long do_sigreturn(CPUM68KState *env) } target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); /* restore registers */ @@ -5928,7 +6298,7 @@ long do_sigreturn(CPUM68KState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -5943,14 +6313,14 @@ long do_rt_sigreturn(CPUM68KState *env) goto badframe; target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); /* restore registers */ if (target_rt_restore_ucontext(env, &frame->uc)) goto badframe; - if (do_sigaltstack(frame_addr + + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; @@ -5960,7 +6330,7 @@ long do_rt_sigreturn(CPUM68KState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -6100,7 +6470,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); return; } @@ -6155,7 +6525,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); return; } @@ -6182,14 +6552,14 @@ long do_sigreturn(CPUAlphaState *env) __get_user(target_set.sig[0], &sc->sc_mask); target_to_host_sigset_internal(&set, &target_set); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(env, sc); unlock_user_struct(sc, sc_addr, 0); return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -6204,10 +6574,10 @@ long do_rt_sigreturn(CPUAlphaState *env) goto badframe; } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, env->ir[IR_SP]) == -EFAULT) { goto badframe; @@ -6219,7 +6589,7 @@ long do_rt_sigreturn(CPUAlphaState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -6355,7 +6725,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } long do_rt_sigreturn(CPUTLGState *env) @@ -6369,10 +6739,10 @@ long do_rt_sigreturn(CPUTLGState *env) goto badframe; } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, env->regs[TILEGX_R_SP]) == -EFAULT) { goto badframe; @@ -6384,7 +6754,7 @@ long do_rt_sigreturn(CPUTLGState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -6520,7 +6890,7 @@ badframe: if (sig == TARGET_SIGSEGV) { ka->_sa_handler = TARGET_SIG_DFL; } - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); } static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc) @@ -6553,7 +6923,7 @@ static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc) } target_to_host_sigset_internal(&blocked, &target_set); - set_sigmask(&blocked); + set_sigmask(env, &blocked); restore_sigcontext(env, &uc->uc_mcontext); } @@ -6571,7 +6941,7 @@ long do_rt_sigreturn(CPURISCVState *env) restore_ucontext(env, &frame->uc); - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { goto badframe; } @@ -6581,7 +6951,7 @@ long do_rt_sigreturn(CPURISCVState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return 0; } @@ -6741,7 +7111,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sigsegv(sig); + force_sigsegv(env, sig); } long do_rt_sigreturn(CPUArchState *env) @@ -6755,12 +7125,12 @@ long do_rt_sigreturn(CPUArchState *env) goto badframe; } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); - set_sigmask(&set); + set_sigmask(env, &set); restore_sigcontext(env, &frame->uc.tuc_mcontext); unlock_user_struct(frame, frame_addr, 0); - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + if (do_sigaltstack(env, frame_addr + offsetof(struct target_rt_sigframe, uc.tuc_stack), 0, env->gr[30]) == -EFAULT) { goto badframe; @@ -6770,7 +7140,7 @@ long do_rt_sigreturn(CPUArchState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV); + force_sig(env, TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } @@ -6838,12 +7208,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH && sig != TARGET_SIGCONT) { - dump_core_and_abort(sig); + dump_core_and_abort(cpu_env, sig); } } else if (handler == TARGET_SIG_IGN) { /* ignore sig */ } else if (handler == TARGET_SIG_ERR) { - dump_core_and_abort(sig); + dump_core_and_abort(cpu_env, sig); } else { /* compute the blocked signals during the handler execution */ sigset_t *blocked_set; @@ -6872,12 +7242,13 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, save_v86_state(env); } #endif + /* prepare the stack frame of the virtual CPU */ -#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ +#if (defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \ || defined(TARGET_PPC64) || defined(TARGET_HPPA) \ || defined(TARGET_NIOS2) || defined(TARGET_X86_64) \ - || defined(TARGET_RISCV) + || defined(TARGET_RISCV)) && !defined(TARGET_ABI_IRIX) /* These targets do not have traditional signals. */ setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env); #else diff --git a/linux-user/socket.h b/linux-user/socket.h index 7051cd2cf4..ae1bc338fc 100644 --- a/linux-user/socket.h +++ b/linux-user/socket.h @@ -1,5 +1,91 @@ -#if defined(TARGET_MIPS) +#if defined(TARGET_ABI_IRIX) || defined(TARGET_ABI_SOLARIS) + + /* For setsockopt(2) */ + #define TARGET_SOL_SOCKET 0xffff + + #define TARGET_SO_DEBUG 0x0001 + #define TARGET_SO_REUSEADDR 0x0004 + #define TARGET_SO_KEEPALIVE 0x0008 + #define TARGET_SO_DONTROUTE 0x0010 + #define TARGET_SO_BROADCAST 0x0020 + #define TARGET_SO_LINGER 0x0080 + #define TARGET_SO_OOBINLINE 0x0100 + #define TARGET_SO_ACCEPTCONN 0x0002 + /* To add :#define TARGET_SO_REUSEPORT 0x0200 */ + + #define TARGET_SO_TYPE 0x1008 + #define TARGET_SO_ERROR 0x1007 + #define TARGET_SO_SNDBUF 0x1001 + #define TARGET_SO_RCVBUF 0x1002 + #define TARGET_SO_SNDBUFFORCE 0x10ff + #define TARGET_SO_RCVBUFFORCE 0x10fe + #define TARGET_SO_RCVLOWAT 0x1003 + #define TARGET_SO_SNDLOWAT 0x1004 + #define TARGET_SO_RCVTIMEO 0x1006 + #define TARGET_SO_SNDTIMEO 0x1005 + #define TARGET_SO_PROTOCOL 0x1009 + #define TARGET_SO_DOMAIN 0x100c + #define TARGET_SO_TIMESTAMP 0x1013 + #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP + + /* linux-specific, might as well be the same as on i386 */ + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_BSDCOMPAT 14 + + #define TARGET_SO_PASSCRED 17 + #define TARGET_SO_PEERCRED 18 + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + + #define TARGET_SO_PEERSEC 30 + #define TARGET_SO_PASSSEC 34 + #define TARGET_SO_TIMESTAMPNS 35 + #define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 19 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 21 + + #define TARGET_SO_MARK 36 + + #define TARGET_SO_TIMESTAMPING 37 + #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING + + #define TARGET_SO_RXQ_OVFL 40 + + #define TARGET_SO_WIFI_STATUS 41 + #define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS + #define TARGET_SO_PEEK_OFF 42 + + /* Instruct lower device to use last 4-bytes of skb data as FCS */ + #define TARGET_SO_NOFCS 43 + + /** sock_type - Socket types */ + + #define ARCH_HAS_SOCKET_TYPES 1 + + enum sock_type { + TARGET_SOCK_STREAM = 2, + TARGET_SOCK_DGRAM = 1, + TARGET_SOCK_RAW = 4, + TARGET_SOCK_RDM = 5, + TARGET_SOCK_SEQPACKET = 6, + TARGET_SOCK_CLOEXEC = 0x080000, + TARGET_SOCK_NONBLOCK = 0x100000, + }; + + #define TARGET_SOCK_MAX (TARGET_SOCK_SEQPACKET + 1) + #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */ + +#elif defined(TARGET_MIPS) /* MIPS special values for constants */ /* diff --git a/linux-user/solaris/syscall_nr.h b/linux-user/solaris/syscall_nr.h new file mode 100644 index 0000000000..d6873f14ea --- /dev/null +++ b/linux-user/solaris/syscall_nr.h @@ -0,0 +1,360 @@ +/* + * Solaris syscalls. This is derived from Netbsd svr4_32_sysent.c and Solaris 7 + * syscall.h, with extensions from Illumos for stuff undefined in Solaris 7. + */ + +#define TARGET_NR_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_linkat 7 /* wait in Solaris 7 */ +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_symlinkat 11 /* exec in Solaris 7 */ +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_chown 16 +#define TARGET_NR_brk 17 +#define TARGET_NR_stat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_readlinkat 22 /* umount in Solaris 7 */ +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_pcsample 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_fstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_statfs 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_fstatfs 38 +#define TARGET_NR_pgrpsys 39 +#define TARGET_NR_xenix 40 /* uucopystr for Solaris 10 */ +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_profil 44 +#define TARGET_NR_faccessat 45 /* plock in Solaris 7 */ +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_mknodat 48 /* signal in Solaris 7 */ +#define TARGET_NR_msgsys 49 +#define TARGET_NR_sysarch 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_shmsys 52 +#define TARGET_NR_semsys 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_uadmin 55 +#define TARGET_NR_fchownat 56 /* undefined for Solaris 7 */ +#define TARGET_NR_utssyssunos 57 +#define TARGET_NR_fdsync 58 +#define TARGET_NR_execve 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_fcntl 62 +#define TARGET_NR_ulimit 63 +#define TARGET_NR_renameat 64 /* undefined in Solaris 7 */ +#define TARGET_NR_unlinkat 65 /* undefined in Solaris 7 */ +#define TARGET_NR_fstatat 66 /* undefined in Solaris 7 */ +#define TARGET_NR_fstatat64 67 /* undefined in Solaris 7 */ +#define TARGET_NR_openat 68 /* undefined in Solaris 7 */ +#define TARGET_NR_openat64 69 /* undefined in Solaris 7 */ +#define TARGET_NR_tasksys 70 /* undefined in Solaris 7 */ +#define TARGET_NR_acctctl 71 /* undefined in Solaris 7 */ +#define TARGET_NR_exacctsys 72 /* undefined in Solaris 7 */ +#define TARGET_NR_getpagesizes 73 /* undefined in Solaris 7 */ +#define TARGET_NR_rctlsys 74 /* undefined in Solaris 7 */ +#define TARGET_NR_sidsys 75 /* undefined in Solaris 7 */ +#define TARGET_NR_fsat 76 /* undefined in Solaris 7 */ +#define TARGET_NR_lwp_park 77 /* undefined in Solaris 7 */ +#define TARGET_NR_sendfilev 78 /* undefined in Solaris 7 */ +#define TARGET_NR_rmdir 79 +#define TARGET_NR_mkdir 80 +#define TARGET_NR_getdents 81 +#define TARGET_NR_privsys 82 /* undefined in Solaris 7 */ +#define TARGET_NR_ucredsys 83 /* undefined in Solaris 7 */ +#define TARGET_NR_sysfs 84 +#define TARGET_NR_getmsg 85 +#define TARGET_NR_putmsg 86 +#define TARGET_NR_poll 87 +#define TARGET_NR_lstat 88 +#define TARGET_NR_symlink 89 +#define TARGET_NR_readlink 90 +#define TARGET_NR_setgroups 91 +#define TARGET_NR_getgroups 92 +#define TARGET_NR_fchmod 93 +#define TARGET_NR_fchown 94 +#define TARGET_NR_sigprocmask 95 +#define TARGET_NR_sigsuspend 96 +#define TARGET_NR_sigaltstack 97 +#define TARGET_NR_sigaction 98 +#define TARGET_NR_sigpendingsys 99 +#define TARGET_NR_context 100 +#define TARGET_NR_fchmodat 101 /* evsys in Solaris 7 */ +#define TARGET_NR_mkdirat 102 /* evtrapret in Solaris 7 */ +#define TARGET_NR_statvfs 103 +#define TARGET_NR_fstatvfs 104 +#define TARGET_NR_getloadavg 105 +#define TARGET_NR_nfssys 106 +#define TARGET_NR_waitid 107 +#define TARGET_NR_sigsendsys 108 +#define TARGET_NR_hrtsys 109 +#define TARGET_NR_acancel 110 /* utimesys in Solaris 10 */ +#define TARGET_NR_async 111 /* sigresend in Solaris 10 */ +#define TARGET_NR_priocntlsys 112 +#define TARGET_NR_pathconf 113 +#define TARGET_NR_mincore 114 +#define TARGET_NR_mmap 115 +#define TARGET_NR_mprotect 116 +#define TARGET_NR_munmap 117 +#define TARGET_NR_fpathconf 118 +#define TARGET_NR_vfork 119 +#define TARGET_NR_fchdir 120 +#define TARGET_NR_readv 121 +#define TARGET_NR_writev 122 +#define TARGET_NR_xstat 123 /* preadv in Solaris 10 */ +#define TARGET_NR_lxstat 124 /* pwritev in Solaris 10 */ +#define TARGET_NR_fxstat 125 /* undefined in Solaris 10 */ +#define TARGET_NR_xmknod 126 /* undefined in Solaris 10 */ +#define TARGET_NR_clocal 127 /* mmapobj in Solaris 10 */ +#define TARGET_NR_setrlimit 128 +#define TARGET_NR_getrlimit 129 +#define TARGET_NR_lchown 130 +#define TARGET_NR_memcntl 131 +#define TARGET_NR_getpmsg 132 +#define TARGET_NR_putpmsg 133 +#define TARGET_NR_rename 134 +#define TARGET_NR_unamesunos 135 +#define TARGET_NR_setegid 136 +#define TARGET_NR_sysconfig 137 +#define TARGET_NR_adjtime 138 +#define TARGET_NR_sysinfosunos 139 +#define TARGET_NR_sharefs 140 /* undefined for Solaris 7 */ +#define TARGET_NR_seteuid 141 +#define TARGET_NR_forksys 142 /* vtrace for Solaris 7 */ +#define TARGET_NR_fork1 143 /* undefined for Solaris 10 */ +#define TARGET_NR_sigtimedwait 144 +#define TARGET_NR_lwp_info 145 +#define TARGET_NR_yield 146 +#define TARGET_NR_lwp_sema_wait 147 /* undefined in Solaris 10 */ +#define TARGET_NR_lwp_sema_post 148 +#define TARGET_NR_lwp_sema_trywait 149 +#define TARGET_NR_lwp_detach 150 /* undefined for Solaris 7 */ +#define TARGET_NR_corectl 151 +#define TARGET_NR_modctl 152 +#define TARGET_NR_fchroot 153 +#define TARGET_NR_utimes 154 +#define TARGET_NR_vhangup 155 +#define TARGET_NR_gettimeofday 156 +#define TARGET_NR_getitimer 157 +#define TARGET_NR_setitimer 158 +#define TARGET_NR_lwp_create 159 +#define TARGET_NR_lwp_exit 160 +#define TARGET_NR_lwp_suspend 161 +#define TARGET_NR_lwp_continue 162 +#define TARGET_NR_lwp_kill 163 +#define TARGET_NR_lwp_self 164 +#define TARGET_NR_lwp_setprivate 165 /* lwp_sigmask for Solaris 10 */ +#define TARGET_NR_lwp_getprivate 166 /* lwp_private for Solaris 10 */ +#define TARGET_NR_lwp_wait 167 +#define TARGET_NR_lwp_mutex_wakeup 168 +#define TARGET_NR_lwp_mutex_lock 169 /* undefined in Solaris 10 */ +#define TARGET_NR_lwp_cond_wait 170 +#define TARGET_NR_lwp_cond_signal 171 +#define TARGET_NR_lwp_cond_broadcast 172 +#define TARGET_NR_pread 173 +#define TARGET_NR_pwrite 174 +#define TARGET_NR__llseek 175 +#define TARGET_NR_inst_sync 176 +#define TARGET_NR_brand 177 +#define TARGET_NR_kaio 178 +#define TARGET_NR_cpc 179 /* undefined in Solaris 7 */ +#define TARGET_NR_meminfosys 180 /* undefined in Solaris 7 */ +#define TARGET_NR_rusagesys 181 /* undefined in Solaris 7 */ +#define TARGET_NR_port 182 /* undefined in Solaris 7 */ +#define TARGET_NR_pollsys 183 /* undefined in Solaris 7 */ +#define TARGET_NR_tsolsys 184 /* labelsys in Solaris 10 */ +#define TARGET_NR_acl 185 +#define TARGET_NR_auditsys 186 +#define TARGET_NR_processor_bind 187 +#define TARGET_NR_processor_info 188 +#define TARGET_NR_p_online 189 +#define TARGET_NR_sigqueue 190 +#define TARGET_NR_clock_gettime 191 +#define TARGET_NR_clock_settime 192 +#define TARGET_NR_clock_getres 193 +#define TARGET_NR_timer_create 194 +#define TARGET_NR_timer_delete 195 +#define TARGET_NR_timer_settime 196 +#define TARGET_NR_timer_gettime 197 +#define TARGET_NR_timer_getoverrun 198 +#define TARGET_NR_nanosleep 199 +#define TARGET_NR_facl 200 +#define TARGET_NR_door 201 +#define TARGET_NR_setreuid 202 +#define TARGET_NR_setregid 203 +#define TARGET_NR_install_utrap 204 +#define TARGET_NR_signotify 205 +#define TARGET_NR_schedctl 206 +#define TARGET_NR_pset 207 +#define TARGET_NR_sparc_utrap_install 208 +#define TARGET_NR_resolvepath 209 +#define TARGET_NR_signotifywait 210 /* lwp_mutex_timedlock for Solaris 10 */ +#define TARGET_NR_lwp_sigredirect 211 /* lwp_sema_timedwait for Solaris 10 */ +#define TARGET_NR_lwp_alarm 212 /* lwp_rwlock_sys for Solaris 10 */ +/* system calls for large files ( > 2 gigabyte) */ +#define TARGET_NR_getdents64 213 +#define TARGET_NR_mmap64 214 +#define TARGET_NR_stat64 215 +#define TARGET_NR_lstat64 216 +#define TARGET_NR_fstat64 217 +#define TARGET_NR_statvfs64 218 +#define TARGET_NR_fstatvfs64 219 +#define TARGET_NR_setrlimit64 220 +#define TARGET_NR_getrlimit64 221 +#define TARGET_NR_pread64 222 +#define TARGET_NR_pwrite64 223 +#define TARGET_NR_creat64 224 +#define TARGET_NR_open64 225 +#define TARGET_NR_rpcsys 226 +#define TARGET_NR_zone 227 /* undefined in Solaris 7 */ +#define TARGET_NR_autofssys 228 /* undefined in Solaris 7 */ +#define TARGET_NR_getcwd 229 +#define TARGET_NR_so_socket 230 +#define TARGET_NR_so_socketpair 231 +#define TARGET_NR_bind 232 +#define TARGET_NR_listen 233 +#define TARGET_NR_accept 234 +#define TARGET_NR_connect 235 +#define TARGET_NR_shutdown 236 +#define TARGET_NR_recv 237 +#define TARGET_NR_recvfrom 238 +#define TARGET_NR_recvmsg 239 +#define TARGET_NR_send 240 +#define TARGET_NR_sendmsg 241 +#define TARGET_NR_sendto 242 +#define TARGET_NR_getpeername 243 +#define TARGET_NR_getsockname 244 +#define TARGET_NR_getsockopt 245 +#define TARGET_NR_setsockopt 246 +#define TARGET_NR_sockconfig 247 +/* NTP system calls */ +#define TARGET_NR_ntp_gettime 248 +#define TARGET_NR_ntp_adjtime 249 +#define TARGET_NR_lwp_mutex_unlock 250 +#define TARGET_NR_lwp_mutex_trylock 251 +#define TARGET_NR_lwp_mutex_register 252 +#define TARGET_NR_cladm 253 +#define TARGET_NR_uucopy 254 /* undefined in Solaris 7 */ +#define TARGET_NR_umount2 255 /* undefined in Solaris 7 */ + + +/* forksys(cmd) */ +#define TARGET_NR_forksys_forkx 0 +#define TARGET_NR_forksys_forkallx 1 +#define TARGET_NR_forksys_vforkx 2 + +/* pgrpsys(cmd, ...) */ +#define TARGET_NR_pgrpsys_getpgrp 0 +#define TARGET_NR_pgrpsys_setpgrp 1 +#define TARGET_NR_pgrpsys_getsid 2 +#define TARGET_NR_pgrpsys_setsid 3 +#define TARGET_NR_pgrpsys_getpgid 4 +#define TARGET_NR_pgrpsys_setpgid 5 + +/* sigpendingsys(cmd, ...) */ +#define TARGET_NR_sigpsys_sigpending 1 +#define TARGET_NR_sigpsys_sigfillset 2 + +/* memcntl(..., ..., cmd, ...) */ +#define TARGET_NR_memcntl_msync 1 +#define TARGET_NR_memcntl_mlock 2 +#define TARGET_NR_memcntl_munlock 3 +#define TARGET_NR_memcntl_madvise 4 +#define TARGET_NR_memcntl_mlockall 5 +#define TARGET_NR_memcntl_munlockall 6 +#define TARGET_NR_memcntl_hatadvise 7 + +/* context(cmd, ...) */ +#define TARGET_NR_context_getcontext 0 +#define TARGET_NR_context_setcontext 1 + +/* fsat(cmd, ...) */ +#define TARGET_NR_fsat_openat 0 +#define TARGET_NR_fsat_openat64 1 +#define TARGET_NR_fsat_fstatat64 2 +#define TARGET_NR_fsat_fstatat 3 +#define TARGET_NR_fsat_renameat 4 +#define TARGET_NR_fsat_fchownat 5 +#define TARGET_NR_fsat_unlinkat 6 +#define TARGET_NR_fsat_futimesat 7 + +/* msgsys(cmd, ...) */ +#define TARGET_NR_msgsys_msgget 0 +#define TARGET_NR_msgsys_msgctl 1 +#define TARGET_NR_msgsys_msgrcv 2 +#define TARGET_NR_msgsys_msgsnd 3 +#define TARGET_NR_msgsys_msgids 4 +#define TARGET_NR_msgsys_msgsnap 5 + +/* shmsys(cmd, ...) */ +#define TARGET_NR_shmsys_shmat 0 +#define TARGET_NR_shmsys_shmctl 1 +#define TARGET_NR_shmsys_shmdt 2 +#define TARGET_NR_shmsys_shmget 3 +#define TARGET_NR_shmsys_shmids 4 + +/* semsys(cmd, ...) */ +#define TARGET_NR_semsys_semctl 0 +#define TARGET_NR_semsys_semget 1 +#define TARGET_NR_semsys_semop 2 +#define TARGET_NR_semsys_semids 3 +#define TARGET_NR_semsys_semtimedop 4 + +/* rusagesys(cmd, ...) */ +#define TARGET_NR_rusagesys_rusage 0 +#define TARGET_NR_rusagesys_rusagecld 1 +#define TARGET_NR_rusagesys_rusagelwp 2 +#define TARGET_NR_rusagesys_vmusage 3 + +/* sysconfig(cmd) */ +#define TARGET_NR_sysconf_childmax 3 +#define TARGET_NR_sysconf_openmax 4 +#define TARGET_NR_sysconf_pagesize 6 +#define TARGET_NR_sysconf_clktick 7 +#define TARGET_NR_sysconf_nprocs 12 +#define TARGET_NR_sysconf_physmem 26 +#define TARGET_NR_sysconf_stckprot 43 + +/* systnfosunos(cmd, ...) */ +#define TARGET_NR_sysinfo_gethostname 2 +#define TARGET_NR_sysinfo_sethostname 258 +#define TARGET_NR_sysinfo_getsrpcdomain 9 +#define TARGET_NR_sysinfo_setsrpcdomain 265 +#define TARGET_NR_sysinfo_sysname 1 +#define TARGET_NR_sysinfo_release 3 +#define TARGET_NR_sysinfo_version 4 +#define TARGET_NR_sysinfo_machine 5 +#define TARGET_NR_sysinfo_cpuarch 6 +#define TARGET_NR_sysinfo_hwserial 7 +#define TARGET_NR_sysinfo_hwproducer 8 +#define TARGET_NR_sysinfo_platform 513 +#define TARGET_NR_sysinfo_isalist 514 +#define TARGET_NR_sysinfo_arch32 516 +#define TARGET_NR_sysinfo_arch64 517 +#define TARGET_NR_sysinfo_archkern 518 +#define TARGET_NR_sysinfo_archnative 519 diff --git a/linux-user/solaris/target_cpu.h b/linux-user/solaris/target_cpu.h new file mode 100644 index 0000000000..feab02e2cc --- /dev/null +++ b/linux-user/solaris/target_cpu.h @@ -0,0 +1,44 @@ +/* + * SPARC specific CPU ABI and functions for linux-user + * + * Copyright (C) 2003 Thomas M. Ogrisegg + * Copyright (C) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef SOLARIS_TARGET_CPU_H +#define SOLARIS_TARGET_CPU_H + +static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp) +{ + if (newsp) { + env->regwptr[22] = newsp; + } + /* syscall return for clone child: 0, and clear CF since + * this counts as a success return value. + */ + env->regwptr[0] = 0; +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + env->xcc &= ~PSR_CARRY; +#else + env->psr &= ~PSR_CARRY; +#endif +} + +static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) +{ + env->gregs[7] = newtls; +} + +#endif diff --git a/linux-user/solaris/target_elf.h b/linux-user/solaris/target_elf.h new file mode 100644 index 0000000000..a510ceb612 --- /dev/null +++ b/linux-user/solaris/target_elf.h @@ -0,0 +1,18 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation, or (at your option) any + * later version. See the COPYING file in the top-level directory. + */ + +#ifndef SPARC_TARGET_ELF_H +#define SPARC_TARGET_ELF_H +static inline const char *cpu_get_model(uint32_t eflags) +{ +#ifdef TARGET_SPARC64 + return "TI UltraSparc II"; +#else + return "Fujitsu MB86904"; +#endif +} +#endif diff --git a/linux-user/solaris/target_signal.h b/linux-user/solaris/target_signal.h new file mode 100644 index 0000000000..425a0e7684 --- /dev/null +++ b/linux-user/solaris/target_signal.h @@ -0,0 +1,91 @@ +#ifndef SOLARIS_TARGET_SIGNAL_H +#define SOLARIS_TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_SIGSTKSZ 16384 + +#ifndef UREG_O6 +#define UREG_O6 6 +#endif +#ifndef UREG_SP +#define UREG_SP UREG_O6 +#endif + +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_SP]; +} + +struct target_mcontext32 { + uint32_t gregs[19]; + uint32_t gwins; + union { + double dregs[16]; + float fregs[32]; + }; + uint32_t fqu; /* ptr to array of FQ entries */ + uint32_t fpfsr; /* FPU status register */ + uint8_t fpqcnt; /* # of entries in saved FQ */ + uint8_t fpqesz; /* # of bytes per FQ entry */ + uint8_t fpen; /* flag signifying fpu in use */ + uint32_t pad1; + uint32_t xrsid; + uint32_t xrsptr; + uint32_t pad[19]; +}; + +struct target_mcontext64 { + uint64_t gregs[21]; + uint32_t gwins; + union { + double dregs[16]; + float fregs[32]; + }; + uint32_t fqu; /* ptr to array of FQ entries */ + uint32_t fpfsr; /* FPU status register */ + uint8_t fpqcnt; /* # of entries in saved FQ */ + uint8_t fpqesz; /* # of bytes per FQ entry */ + uint8_t fpen; /* flag signifying fpu in use */ + uint32_t pad1; + uint32_t xrsid; + uint32_t xrsptr; + uint32_t pad[19]; +}; + +struct target_mcontext { + union { + struct target_mcontext32 _32; + struct target_mcontext64 _64; + }; +}; + +struct target_ucontext { + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_sigset_t tuc_sigmask; + struct target_sigaltstack tuc_stack; + int pad; + struct target_mcontext tuc_mcontext; +}; + +int save_context(CPUSPARCState *regs, struct target_mcontext *sc, int setret); +int restore_context(CPUSPARCState *regs, struct target_mcontext *sc); + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/solaris/target_structs.h b/linux-user/solaris/target_structs.h new file mode 100644 index 0000000000..17aa60b480 --- /dev/null +++ b/linux-user/solaris/target_structs.h @@ -0,0 +1,63 @@ +/* + * SPARC specific structures for linux-user + * + * Copyright (c) 2013 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef SOLARIS_TARGET_STRUCTS_H +#define SOLARIS_TARGET_STRUCTS_H + +struct target_ipc_perm { + abi_int __key; /* Key. */ + abi_uint uid; /* Owner's user ID. */ + abi_uint gid; /* Owner's group ID. */ + abi_uint cuid; /* Creator's user ID. */ + abi_uint cgid; /* Creator's group ID. */ +#if TARGET_ABI_BITS == 32 + abi_ushort __pad1; + abi_ushort mode; /* Read/write permission. */ + abi_ushort __pad2; +#else + abi_ushort mode; + abi_ushort __pad1; +#endif + abi_ushort __seq; /* Sequence number. */ + uint64_t __unused1; + uint64_t __unused2; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; /* operation permission struct */ +#if TARGET_ABI_BITS == 32 + abi_uint __pad1; +#endif + abi_ulong shm_atime; /* time of last shmat() */ +#if TARGET_ABI_BITS == 32 + abi_uint __pad2; +#endif + abi_ulong shm_dtime; /* time of last shmdt() */ +#if TARGET_ABI_BITS == 32 + abi_uint __pad3; +#endif + abi_ulong shm_ctime; /* time of last change by shmctl() */ + abi_long shm_segsz; /* size of segment in bytes */ + abi_ulong shm_cpid; /* pid of creator */ + abi_ulong shm_lpid; /* pid of last shmop */ + abi_long shm_nattch; /* number of current attaches */ + abi_ulong __unused1; + abi_ulong __unused2; +}; + +#endif diff --git a/linux-user/solaris/target_syscall.h b/linux-user/solaris/target_syscall.h new file mode 100644 index 0000000000..e4d485867c --- /dev/null +++ b/linux-user/solaris/target_syscall.h @@ -0,0 +1,24 @@ +#ifndef SOLARIS_TARGET_SYSCALL_H +#define SOLARIS_TARGET_SYSCALL_H + +struct target_pt_regs { + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; +}; + +#define UNAME_MACHINE "sun4" +#define UNAME_MINIMUM_RELEASE "2.6.32" + +/* SPARC kernels don't define this in their Kconfig, but they have the + * same ABI as if they did, implemented by sparc-specific code which fishes + * directly in the u_regs() struct for half the parameters in sparc_do_fork() + * and copy_thread(). + */ +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x1 +#define TARGET_MLOCKALL_MCL_FUTURE 0x2 + +#endif diff --git a/linux-user/solaris/termbits.h b/linux-user/solaris/termbits.h new file mode 100644 index 0000000000..24ea54e157 --- /dev/null +++ b/linux-user/solaris/termbits.h @@ -0,0 +1,280 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VEOL 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 + +#define TARGET_VSUSP 10 +#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 + +/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is + * shared with eof/eol + */ +#define TARGET_VMIN TARGET_VEOF +#define TARGET_VTIME TARGET_VEOL + +/* c_iflag bits */ +#define TARGET_IGNBRK 0x00000001 +#define TARGET_BRKINT 0x00000002 +#define TARGET_IGNPAR 0x00000004 +#define TARGET_PARMRK 0x00000008 +#define TARGET_INPCK 0x00000010 +#define TARGET_ISTRIP 0x00000020 +#define TARGET_INLCR 0x00000040 +#define TARGET_IGNCR 0x00000080 +#define TARGET_ICRNL 0x00000100 +#define TARGET_IUCLC 0x00000200 +#define TARGET_IXON 0x00000400 +#define TARGET_IXANY 0x00000800 +#define TARGET_IXOFF 0x00001000 +#define TARGET_IMAXBEL 0x00002000 +#define TARGET_IUTF8 0x00004000 + +/* c_oflag bits */ +#define TARGET_OPOST 0x00000001 +#define TARGET_OLCUC 0x00000002 +#define TARGET_ONLCR 0x00000004 +#define TARGET_OCRNL 0x00000008 +#define TARGET_ONOCR 0x00000010 +#define TARGET_ONLRET 0x00000020 +#define TARGET_OFILL 0x00000040 +#define TARGET_OFDEL 0x00000080 +#define TARGET_NLDLY 0x00000100 +#define TARGET_NL0 0x00000000 +#define TARGET_NL1 0x00000100 +#define TARGET_CRDLY 0x00000600 +#define TARGET_CR0 0x00000000 +#define TARGET_CR1 0x00000200 +#define TARGET_CR2 0x00000400 +#define TARGET_CR3 0x00000600 +#define TARGET_TABDLY 0x00001800 +#define TARGET_TAB0 0x00000000 +#define TARGET_TAB1 0x00000800 +#define TARGET_TAB2 0x00001000 +#define TARGET_TAB3 0x00001800 +#define TARGET_XTABS 0x00001800 +#define TARGET_BSDLY 0x00002000 +#define TARGET_BS0 0x00000000 +#define TARGET_BS1 0x00002000 +#define TARGET_VTDLY 0x00004000 +#define TARGET_VT0 0x00000000 +#define TARGET_VT1 0x00004000 +#define TARGET_FFDLY 0x00008000 +#define TARGET_FF0 0x00000000 +#define TARGET_FF1 0x00008000 +#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ +#define TARGET_WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0x0020000f +#define TARGET_B0 0x00000000 /* hang up */ +#define TARGET_B50 0x00000001 +#define TARGET_B75 0x00000002 +#define TARGET_B110 0x00000003 +#define TARGET_B134 0x00000004 +#define TARGET_B150 0x00000005 +#define TARGET_B200 0x00000006 +#define TARGET_B300 0x00000007 +#define TARGET_B600 0x00000008 +#define TARGET_B1200 0x00000009 +#define TARGET_B1800 0x0000000a +#define TARGET_B2400 0x0000000b +#define TARGET_B4800 0x0000000c +#define TARGET_B9600 0x0000000d +#define TARGET_B19200 0x0000000e +#define TARGET_B38400 0x0000000f +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0x00000030 +#define TARGET_CS5 0x00000000 +#define TARGET_CS6 0x00000010 +#define TARGET_CS7 0x00000020 +#define TARGET_CS8 0x00000030 +#define TARGET_CSTOPB 0x00000040 +#define TARGET_CREAD 0x00000080 +#define TARGET_PARENB 0x00000100 +#define TARGET_PARODD 0x00000200 +#define TARGET_HUPCL 0x00000400 +#define TARGET_CLOCAL 0x00000800 +#define TARGET_CBAUDEX 0x00200000 +/* We'll never see these speeds with the Zilogs, but for completeness... */ +#define TARGET_B57600 (TARGET_CBAUDEX+1) +#define TARGET_B115200 (TARGET_CBAUDEX+2) +#define TARGET_B230400 (TARGET_CBAUDEX+3) +#define TARGET_B460800 (TARGET_CBAUDEX+4) +/* This is what we can do with the Zilogs. */ +#define TARGET_B76800 (TARGET_CBAUDEX+5) +/* This is what we can do with the SAB82532. */ +#define TARGET_B153600 (TARGET_CBAUDEX+6) +#define TARGET_B307200 (TARGET_CBAUDEX+7) +#define TARGET_B614400 (TARGET_CBAUDEX+8) +#define TARGET_B921600 (TARGET_CBAUDEX+9) +/* And these are the rest... */ +#define TARGET_B500000 (TARGET_CBAUDEX+10) +#define TARGET_B576000 (TARGET_CBAUDEX+11) +#define TARGET_B1000000 (TARGET_CBAUDEX+12) +#define TARGET_B1152000 (TARGET_CBAUDEX+13) +#define TARGET_B1500000 (TARGET_CBAUDEX+14) +#define TARGET_B2000000 (TARGET_CBAUDEX+15) +/* These have totally bogus values and nobody uses them + so far. Later on we'd have to use say 0x10000x and + adjust CBAUD constant and drivers accordingly. +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define TARGET_CIBAUD 0x004f0000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000001 +#define TARGET_ICANON 0x00000002 +#define TARGET_XCASE 0x00000004 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000010 +#define TARGET_ECHOK 0x00000020 +#define TARGET_ECHONL 0x00000040 +#define TARGET_NOFLSH 0x00000080 +#define TARGET_TOSTOP 0x00000100 +#define TARGET_ECHOCTL 0x00000200 +#define TARGET_ECHOPRT 0x00000400 +#define TARGET_ECHOKE 0x00000800 +#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define TARGET_FLUSHO 0x00002000 +#define TARGET_PENDIN 0x00004000 +#define TARGET_IEXTEN 0x00008000 + +/* ioctls */ +#define TARGET_IO_(t,n) (((t)<<8)|(n)) + +/* Big T */ +#define TARGET_TCGETA TARGET_IO_('T', 1) +#define TARGET_TCSETA TARGET_IO_('T', 2) +#define TARGET_TCSETAW TARGET_IO_('T', 3) +#define TARGET_TCSETAF TARGET_IO_('T', 4) +#define TARGET_TCSBRK TARGET_IO_('T', 5) +#define TARGET_TCXONC TARGET_IO_('T', 6) +#define TARGET_TCFLSH TARGET_IO_('T', 7) +#define TARGET_TCGETS TARGET_IO_('T', 13) +#define TARGET_TCSETS TARGET_IO_('T', 14) +#define TARGET_TCSETSW TARGET_IO_('T', 15) +#define TARGET_TCSETSF TARGET_IO_('T', 16) + +#define TARGET_TIOCGSOFTCAR TARGET_IO_('T', 105) +#define TARGET_TIOCSSOFTCAR TARGET_IO_('T', 106) +//#define __TIOCUCNTL _IOCTL('T', 102) /* SunOS Specific */ +#define TARGET_TIOCSWINSZ TARGET_IO_('T', 103) +#define TARGET_TIOCGWINSZ TARGET_IO_('T', 104) + +//#define __TIOCREMOTE _IOCTL('t', 30) /* SunOS Specific */ +/* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to + * thing we support some ioctls under Linux (autoconfiguration stuff) + */ +/* Little t */ +#define TARGET_TIOCGETD TARGET_IO_('t', 0) +#define TARGET_TIOCSETD TARGET_IO_('t', 1) +//#define __TIOCHPCL _IOCTL('t') /* SunOS Specific */ +//#define __TIOCMODG _IOCTL('t', 3) /* SunOS Specific */ +//#define __TIOCMODS _IOCTL('t', 4) /* SunOS Specific */ +//#define __TIOCGETP _IOCTL('t', 8) /* SunOS Specific */ +//#define __TIOCSETP _IOCTL('t', 9) /* SunOS Specific */ +//#define __TIOCSETN _IOCTL('t', 10) /* SunOS Specific */ +#define TARGET_TIOCEXCL TARGET_IO_('t', 13) +#define TARGET_TIOCNXCL TARGET_IO_('t', 14) +//#define __TIOCFLUSH _IOCTL('t', 16) /* SunOS Specific */ +//#define __TIOCSETC _IOCTL('t', 17) /* SunOS Specific */ +//#define __TIOCGETC _IOCTL('t', 18) /* SunOS Specific */ +//#define __TIOCTCNTL _IOCTL('t', 32) /* SunOS Specific */ +//#define __TIOCSIGNAL _IOCTL('t', 31) /* SunOS Specific */ +//#define __TIOCSETX _IOCTL('t', 34) /* SunOS Specific */ +//#define __TIOCGETX _IOCTL('t', 35) /* SunOS Specific */ +#define TARGET_TIOCCONS TARGET_IO_('t', 36) +//#define __TIOCSSIZE _IOCTL('t', 37) /* SunOS Specific */ +//#define __TIOCGSIZE _IOCTL('t', 38) /* SunOS Specific */ +#define TARGET_TIOCMGET TARGET_IO_('t', 29) +#define TARGET_TIOCMBIC TARGET_IO_('t', 28) +#define TARGET_TIOCMBIS TARGET_IO_('t', 27) +#define TARGET_TIOCMSET TARGET_IO_('t', 26) +#define TARGET_TIOCSTART TARGET_IO_('t', 110) +#define TARGET_TIOCSTOP TARGET_IO_('t', 111) +#define TARGET_TIOCPKT TARGET_IO_('t', 112) +#define TARGET_TIOCNOTTY TARGET_IO_('t', 113) +#define TARGET_TIOCSTI TARGET_IO_('t', 23) +#define TARGET_TIOCOUTQ TARGET_IO_('t', 115) +//#define __TIOCGLTC _IOCTL('t', 116) /* SunOS Specific */ +//#define __TIOCSLTC _IOCTL('t', 117) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +//#define __TIOCCDTR TARGET_IO_('t', 120) /* SunOS Specific */ +//#define __TIOCSDTR TARGET_IO_('t', 121) /* SunOS Specific */ +#define TARGET_TIOCCBRK TARGET_IO_('t', 122) +#define TARGET_TIOCSBRK TARGET_IO_('t', 123) +//#define __TIOCLGET TARGET_IO_('t', 124) /* SunOS Specific */ +//#define __TIOCLSET TARGET_IO_('t', 125) /* SunOS Specific */ +//#define __TIOCLBIC TARGET_IO_('t', 126) /* SunOS Specific */ +//#define __TIOCLBIS TARGET_IO_('t', 127) /* SunOS Specific */ +//#define __TIOCISPACE TARGET_IO_('t', 128) /* SunOS Specific */ +//#define __TIOCISIZE TARGET_IO_('t', 129) /* SunOS Specific */ +#define TARGET_TIOCSPGRP TARGET_IO_('t', 21) +#define TARGET_TIOCGPGRP TARGET_IO_('t', 20) +#define TARGET_TIOCSCTTY TARGET_IO_('t', 132) +#define TARGET_TIOCGSID TARGET_IO_('t', 22) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TARGET_TIOCGPTN TARGET_IO_('t', 134) /* Get Pty Number */ +#define TARGET_TIOCSPTLCK TARGET_IO_('t', 135) /* Lock/unlock PTY */ + +/* Little f */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ +//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ + +/* Linux specific, no SunOS equivalent. */ +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TCSBRKP 0x5425 +#define TARGET_TIOCTTYGSTRUCT 0x5426 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ +#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index e445e2b463..8bc27d982d 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -21,16 +21,16 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 -#ifndef UREG_I6 -#define UREG_I6 6 +#ifndef UREG_O6 +#define UREG_O6 6 #endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 +#ifndef UREG_SP +#define UREG_SP UREG_O6 #endif static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { - return state->regwptr[UREG_FP]; + return state->regwptr[UREG_SP]; } diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h index 4449457baf..7be685dab8 100644 --- a/linux-user/sparc64/target_signal.h +++ b/linux-user/sparc64/target_signal.h @@ -21,16 +21,16 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 -#ifndef UREG_I6 -#define UREG_I6 6 +#ifndef UREG_O6 +#define UREG_O6 6 #endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 +#ifndef UREG_SP +#define UREG_SP UREG_O6 #endif static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { - return state->regwptr[UREG_FP]; + return state->regwptr[UREG_SP]; } diff --git a/linux-user/strace.c b/linux-user/strace.c index bd897a3f20..7fc7b2c6fc 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -73,6 +76,7 @@ UNUSED static void print_socket_protocol(int domain, int type, int protocol); /* * Utility functions */ +#if defined(TARGET_NR_semctl) || defined(TARGET_NR_ipc) static void print_ipc_cmd(int cmd) { @@ -120,6 +124,7 @@ if( cmd == val ) { \ /* Some value we don't recognize */ gemu_log("%d",cmd); } +#endif static void print_signal(abi_ulong arg, int last) @@ -188,6 +193,7 @@ static void print_si_code(int arg) gemu_log("%s", codename); } +#if defined(TARGET_NR_rt_sigqueueinfo) || defined(TARGET_NR_rt_tgsigqueueinfo) static void get_target_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) { @@ -241,8 +247,10 @@ static void get_target_siginfo(target_siginfo_t *tinfo, case TARGET_SIGCHLD: __get_user(tinfo->_sifields._sigchld._pid, &info->_sifields._sigchld._pid); +#if !defined(TARGET_ABI_IRIX) && !defined(TARGET_ABI_SOLARIS) __get_user(tinfo->_sifields._sigchld._uid, &info->_sifields._sigchld._uid); +#endif __get_user(tinfo->_sifields._sigchld._status, &info->_sifields._sigchld._status); __get_user(tinfo->_sifields._sigchld._utime, @@ -274,6 +282,7 @@ static void get_target_siginfo(target_siginfo_t *tinfo, tinfo->si_code = deposit32(si_code, 16, 16, si_type); } +#endif static void print_siginfo(const target_siginfo_t *tinfo) { @@ -303,8 +312,8 @@ static void print_siginfo(const target_siginfo_t *tinfo) tinfo->_sifields._timer._timer2); break; case QEMU_SI_POLL: - gemu_log(", si_band=%d, si_fd=%d", - tinfo->_sifields._sigpoll._band, + gemu_log(", si_band = "TARGET_ABI_FMT_ld", si_fd = %d", + (abi_long)tinfo->_sifields._sigpoll._band, tinfo->_sifields._sigpoll._fd); break; case QEMU_SI_FAULT: @@ -312,14 +321,20 @@ static void print_siginfo(const target_siginfo_t *tinfo) print_pointer(tinfo->_sifields._sigfault._addr, 1); break; case QEMU_SI_CHLD: - gemu_log(", si_pid=%u, si_uid=%u, si_status=%d" + gemu_log(", si_pid = %u" +#if !defined(TARGET_ABI_IRIX) && !defined(TARGET_ABI_SOLARIS) + ", si_uid = %u" +#endif + ", si_status = %d" ", si_utime=" TARGET_ABI_FMT_ld ", si_stime=" TARGET_ABI_FMT_ld, (unsigned int)(tinfo->_sifields._sigchld._pid), +#if !defined(TARGET_ABI_IRIX) && !defined(TARGET_ABI_SOLARIS) (unsigned int)(tinfo->_sifields._sigchld._uid), +#endif tinfo->_sifields._sigchld._status, - tinfo->_sifields._sigchld._utime, - tinfo->_sifields._sigchld._stime); + (abi_long)tinfo->_sifields._sigchld._utime, + (abi_long)tinfo->_sifields._sigchld._stime); break; case QEMU_SI_RT: gemu_log(", si_pid=%u, si_uid=%u, si_sigval=" TARGET_ABI_FMT_ld, @@ -451,17 +466,22 @@ print_socket_type(int type) case TARGET_SOCK_SEQPACKET: gemu_log("SOCK_SEQPACKET"); break; +#ifdef TARGET_SOCK_PACKET case TARGET_SOCK_PACKET: gemu_log("SOCK_PACKET"); break; +#endif } } static void print_socket_protocol(int domain, int type, int protocol) { - if (domain == AF_PACKET || - (domain == AF_INET && type == TARGET_SOCK_PACKET)) { + if (domain == AF_PACKET +#ifdef TARGET_SOCK_PACKET + || (domain == AF_INET && type == TARGET_SOCK_PACKET) +#endif + ) { switch (protocol) { case 0x0003: gemu_log("ETH_P_ALL"); @@ -725,6 +745,7 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) } #endif +#ifdef TARGET_NR_adjtimex /* special meanings of adjtimex()' non-negative return values */ #define TARGET_TIME_OK 0 /* clock synchronized, no leap second */ #define TARGET_TIME_INS 1 /* insert leap second */ @@ -770,6 +791,7 @@ print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret) gemu_log("\n"); } +#endif UNUSED static struct flags access_flags[] = { FLAG_GENERIC(F_OK), @@ -1410,6 +1432,7 @@ print_fcntl(const struct syscallname *name, gemu_log("F_SETOWN,"); print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); break; +#ifdef TARGET_F_SETSIG case TARGET_F_GETSIG: gemu_log("F_GETSIG"); break; @@ -1417,6 +1440,7 @@ print_fcntl(const struct syscallname *name, gemu_log("F_SETSIG,"); print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); break; +#endif #if TARGET_ABI_BITS == 32 case TARGET_F_GETLK64: gemu_log("F_GETLK64,"); @@ -1543,8 +1567,11 @@ print_socket(const struct syscallname *name, gemu_log(","); print_socket_type(type); gemu_log(","); - if (domain == AF_PACKET || - (domain == AF_INET && type == TARGET_SOCK_PACKET)) { + if (domain == AF_PACKET +#ifdef TARGET_SOCK_PACKET + || (domain == AF_INET && type == TARGET_SOCK_PACKET) +#endif + ) { protocol = tswap16(protocol); } print_socket_protocol(domain, type, protocol); @@ -1888,16 +1915,25 @@ print_socketcall(const struct syscallname *name, } #endif -#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ - defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) +#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || defined(TARGET_NR_xstat) || \ + defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) || defined(TARGET_NR_lxstat) static void print_stat(const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { print_syscall_prologue(name); +#if defined(TARGET_NR_xstat) || defined(TARGET_NR_lxstat) + if (name->nr == TARGET_NR_xstat || name->nr == TARGET_NR_lxstat) { + print_raw_param("%d", arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 1); + } else +#endif + { print_string(arg0, 0); print_pointer(arg1, 1); + } print_syscall_epilogue(name); } #define print_lstat print_stat @@ -1905,15 +1941,24 @@ print_stat(const struct syscallname *name, #define print_lstat64 print_stat #endif -#if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) +#if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) || defined(TARGET_NR_fxstat) static void print_fstat(const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { print_syscall_prologue(name); +#ifdef TARGET_NR_fxstat + if (name->nr == TARGET_NR_fxstat) { + print_raw_param("%d", arg0, 0); + print_raw_param("%d", arg1, 0); + print_pointer(arg2, 1); + } else +#endif + { print_raw_param("%d", arg0, 0); print_pointer(arg1, 1); + } print_syscall_epilogue(name); } #define print_fstat64 print_fstat @@ -2605,7 +2650,7 @@ print_syscall(int num, int i; const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; - gemu_log("%d ", getpid() ); + gemu_log("%ld ", syscall(SYS_gettid) ); for(i=0;i #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -44,6 +50,8 @@ #include #include #include +#include +#include #include #include #include @@ -182,38 +190,38 @@ #undef _syscall6 #define _syscall0(type,name) \ -static type name (void) \ +static inline type name (void) \ { \ return syscall(__NR_##name); \ } #define _syscall1(type,name,type1,arg1) \ -static type name (type1 arg1) \ +static inline type name (type1 arg1) \ { \ return syscall(__NR_##name, arg1); \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ -static type name (type1 arg1,type2 arg2) \ +static inline type name (type1 arg1,type2 arg2) \ { \ return syscall(__NR_##name, arg1, arg2); \ } #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -static type name (type1 arg1,type2 arg2,type3 arg3) \ +static inline type name (type1 arg1,type2 arg2,type3 arg3) \ { \ return syscall(__NR_##name, arg1, arg2, arg3); \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ +static inline type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ -static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +static inline type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)\ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ } @@ -221,7 +229,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ -static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ +static inline type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,\ type6 arg6) \ { \ return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ @@ -270,34 +278,44 @@ _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, co _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); #endif +#ifdef TARGET_NR_rt_sigqueueinfo _syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo) _syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig, siginfo_t *, uinfo) +#endif +#ifdef TARGET_NR_syslog _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) -#ifdef __NR_exit_group +#endif +#if defined __NR_exit_group && defined TARGET_NR_exit_group _syscall1(int,exit_group,int,error_code) #endif #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) _syscall1(int,set_tid_address,int *,tidptr) #endif -#if defined(TARGET_NR_futex) && defined(__NR_futex) +#if defined(__NR_futex) _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) #endif +#ifdef TARGET_NR_sched_getaffinity #define __NR_sys_sched_getaffinity __NR_sched_getaffinity _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len, unsigned long *, user_mask_ptr); #define __NR_sys_sched_setaffinity __NR_sched_setaffinity _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len, unsigned long *, user_mask_ptr); +#endif #define __NR_sys_getcpu __NR_getcpu _syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache); +#ifdef TARGET_NR_reboot _syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd, void *, arg); +#endif +#ifdef TARGET_NR_capget _syscall2(int, capget, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); _syscall2(int, capset, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); +#endif #if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get) _syscall2(int, ioprio_get, int, which, int, who) #endif @@ -570,6 +588,7 @@ static void fd_trans_dup(int oldfd, int newfd) } } +#ifdef TARGET_NR_getcwd static int sys_getcwd1(char *buf, size_t size) { if (getcwd(buf, size) == NULL) { @@ -578,6 +597,7 @@ static int sys_getcwd1(char *buf, size_t size) } return strlen(buf)+1; } +#endif #ifdef TARGET_NR_utimensat #if defined(__NR_utimensat) @@ -756,7 +776,9 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [ESRMNT] = TARGET_ESRMNT, [ECOMM] = TARGET_ECOMM, [EPROTO] = TARGET_EPROTO, +#if defined EDOTDOT && defined TARGET_EDOTDOT [EDOTDOT] = TARGET_EDOTDOT, +#endif [EMULTIHOP] = TARGET_EMULTIHOP, [EBADMSG] = TARGET_EBADMSG, [ENAMETOOLONG] = TARGET_ENAMETOOLONG, @@ -801,7 +823,9 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [ENAVAIL] = TARGET_ENAVAIL, [EISNAM] = TARGET_EISNAM, [EREMOTEIO] = TARGET_EREMOTEIO, +#if defined EDQUOT && defined TARGET_EDQUOT [EDQUOT] = TARGET_EDQUOT, +#endif [ESHUTDOWN] = TARGET_ESHUTDOWN, [ETOOMANYREFS] = TARGET_ETOOMANYREFS, [ETIMEDOUT] = TARGET_ETIMEDOUT, @@ -812,33 +836,37 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [EINPROGRESS] = TARGET_EINPROGRESS, [ESTALE] = TARGET_ESTALE, [ECANCELED] = TARGET_ECANCELED, +#if defined ENOMEDIUM && defined TARGET_ENOMEDIUM [ENOMEDIUM] = TARGET_ENOMEDIUM, +#endif +#if defined EMEDIUMTYPE && defined TARGET_EMEDIUMTYPE [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE, -#ifdef ENOKEY +#endif +#if defined ENOKEY && defined TARGET_ENOKEY [ENOKEY] = TARGET_ENOKEY, #endif -#ifdef EKEYEXPIRED +#if defined EKEYEXPIRED && defined TARGET_EKEYEXPIRED [EKEYEXPIRED] = TARGET_EKEYEXPIRED, #endif -#ifdef EKEYREVOKED +#if defined EKEYREVOKED && defined TARGET_EKEYREVOKED [EKEYREVOKED] = TARGET_EKEYREVOKED, #endif -#ifdef EKEYREJECTED +#if defined EKEYREJECTED && defined TARGET_EKEYREJECTED [EKEYREJECTED] = TARGET_EKEYREJECTED, #endif -#ifdef EOWNERDEAD +#if defined EOWNERDEAD && defined TARGET_EOWNERDEAD [EOWNERDEAD] = TARGET_EOWNERDEAD, #endif -#ifdef ENOTRECOVERABLE +#if defined ENOTRECOVERABLE && defined TARGET_ENOTRECOVERABLE [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, #endif #ifdef ENOMSG [ENOMSG] = TARGET_ENOMSG, #endif -#ifdef ERKFILL +#if defined ERKFILL && defined TARGET_ERFKILL [ERFKILL] = TARGET_ERFKILL, #endif -#ifdef EHWPOISON +#if defined EHWPOISON && defined TARGET_EHWPOISON [EHWPOISON] = TARGET_EHWPOISON, #endif }; @@ -890,39 +918,39 @@ const char *target_strerror(int err) } #define safe_syscall0(type, name) \ -static type safe_##name(void) \ +static inline type safe_##name(void) \ { \ return safe_syscall(__NR_##name); \ } #define safe_syscall1(type, name, type1, arg1) \ -static type safe_##name(type1 arg1) \ +static inline type safe_##name(type1 arg1) \ { \ return safe_syscall(__NR_##name, arg1); \ } #define safe_syscall2(type, name, type1, arg1, type2, arg2) \ -static type safe_##name(type1 arg1, type2 arg2) \ +static inline type safe_##name(type1 arg1, type2 arg2) \ { \ return safe_syscall(__NR_##name, arg1, arg2); \ } #define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ -static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \ +static inline type safe_##name(type1 arg1, type2 arg2, type3 arg3) \ { \ return safe_syscall(__NR_##name, arg1, arg2, arg3); \ } #define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4) \ -static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +static inline type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } #define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4, type5, arg5) \ -static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ +static inline type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) \ { \ return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ @@ -930,7 +958,7 @@ static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ #define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4, type5, arg5, type6, arg6) \ -static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ +static inline type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) \ { \ return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ @@ -1170,12 +1198,18 @@ static inline abi_long copy_from_user_fdset(fd_set *fds, int n) { int i, nw, j, k; +#ifdef TARGET_ABI_IRIX + abi_uint b, *target_fds; + int bw = 8*sizeof(b); +#else abi_ulong b, *target_fds; + int bw = TARGET_ABI_BITS; +#endif - nw = DIV_ROUND_UP(n, TARGET_ABI_BITS); + nw = DIV_ROUND_UP(n, bw); if (!(target_fds = lock_user(VERIFY_READ, target_fds_addr, - sizeof(abi_ulong) * nw, + sizeof(b) * nw, 1))) return -TARGET_EFAULT; @@ -1184,7 +1218,7 @@ static inline abi_long copy_from_user_fdset(fd_set *fds, for (i = 0; i < nw; i++) { /* grab the abi_ulong */ __get_user(b, &target_fds[i]); - for (j = 0; j < TARGET_ABI_BITS; j++) { + for (j = 0; j < bw; j++) { /* check the bit inside the abi_ulong */ if ((b >> j) & 1) FD_SET(k, fds); @@ -1217,19 +1251,25 @@ static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, { int i, nw, j, k; abi_long v; - abi_ulong *target_fds; +#ifdef TARGET_ABI_IRIX + abi_uint b, *target_fds; + int bw = 8*sizeof(b); +#else + abi_ulong b, *target_fds; + int bw = TARGET_ABI_BITS; +#endif - nw = DIV_ROUND_UP(n, TARGET_ABI_BITS); + nw = DIV_ROUND_UP(n, bw); if (!(target_fds = lock_user(VERIFY_WRITE, target_fds_addr, - sizeof(abi_ulong) * nw, + sizeof(b) * nw, 0))) return -TARGET_EFAULT; k = 0; for (i = 0; i < nw; i++) { v = 0; - for (j = 0; j < TARGET_ABI_BITS; j++) { + for (j = 0; j < bw; j++) { v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j); k++; } @@ -1263,24 +1303,24 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr, if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) return -TARGET_EFAULT; - target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec); - target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec); - target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec); - target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec); - target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss); - target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss); - target_rusage->ru_idrss = tswapal(rusage->ru_idrss); - target_rusage->ru_isrss = tswapal(rusage->ru_isrss); - target_rusage->ru_minflt = tswapal(rusage->ru_minflt); - target_rusage->ru_majflt = tswapal(rusage->ru_majflt); - target_rusage->ru_nswap = tswapal(rusage->ru_nswap); - target_rusage->ru_inblock = tswapal(rusage->ru_inblock); - target_rusage->ru_oublock = tswapal(rusage->ru_oublock); - target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd); - target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv); - target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals); - target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw); - target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw); + __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec); + __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec); + __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec); + __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec); + __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss); + __put_user(rusage->ru_ixrss, &target_rusage->ru_ixrss); + __put_user(rusage->ru_idrss, &target_rusage->ru_idrss); + __put_user(rusage->ru_isrss, &target_rusage->ru_isrss); + __put_user(rusage->ru_minflt, &target_rusage->ru_minflt); + __put_user(rusage->ru_majflt, &target_rusage->ru_majflt); + __put_user(rusage->ru_nswap, &target_rusage->ru_nswap); + __put_user(rusage->ru_inblock, &target_rusage->ru_inblock); + __put_user(rusage->ru_oublock, &target_rusage->ru_oublock); + __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd); + __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv); + __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals); + __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw); + __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw); unlock_user_struct(target_rusage, target_addr, 1); return 0; @@ -1291,7 +1331,7 @@ static inline rlim_t target_to_host_rlim(abi_ulong target_rlim) abi_ulong target_rlim_swap; rlim_t result; - target_rlim_swap = tswapal(target_rlim); + __get_user(target_rlim_swap, &target_rlim); if (target_rlim_swap == TARGET_RLIM_INFINITY) return RLIM_INFINITY; @@ -1311,11 +1351,43 @@ static inline abi_ulong host_to_target_rlim(rlim_t rlim) target_rlim_swap = TARGET_RLIM_INFINITY; else target_rlim_swap = rlim; - result = tswapal(target_rlim_swap); + __put_user(target_rlim_swap, &result); return result; } +#ifdef TARGET_NR_getrlimit64 +static inline rlim_t target_to_host_rlim64(uint64_t target_rlim) +{ + uint64_t target_rlim_swap; + rlim_t result; + + __get_user(target_rlim_swap, &target_rlim); + if (target_rlim_swap == TARGET_RLIM64_INFINITY) + return RLIM_INFINITY; + + result = target_rlim_swap; + if (target_rlim_swap != (rlim_t)result) + return RLIM_INFINITY; + + return result; +} + +static inline uint64_t host_to_target_rlim64(rlim_t rlim) +{ + uint64_t target_rlim_swap; + uint64_t result; + + if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) + target_rlim_swap = TARGET_RLIM64_INFINITY; + else + target_rlim_swap = rlim; + __put_user(target_rlim_swap, &result); + + return result; +} +#endif + static inline int target_to_host_resource(int code) { switch (code) { @@ -1354,6 +1426,56 @@ static inline int target_to_host_resource(int code) } } +#if defined(TARGET_NR_pathconf) || defined(TARGET_ABI_IRIX) +static inline int target_to_host_pathconf(int code) +{ + switch (code) { + case TARGET_PC_LINK_MAX: + return _PC_LINK_MAX; + case TARGET_PC_MAX_CANON: + return _PC_MAX_CANON; + case TARGET_PC_MAX_INPUT: + return _PC_MAX_INPUT; + case TARGET_PC_NAME_MAX: + return _PC_NAME_MAX; + case TARGET_PC_PATH_MAX: + return _PC_PATH_MAX; + case TARGET_PC_PIPE_BUF: + return _PC_PIPE_BUF; + case TARGET_PC_NO_TRUNC: + return _PC_NO_TRUNC; + case TARGET_PC_VDISABLE: + return _PC_VDISABLE; + case TARGET_PC_CHOWN_RESTRICTED: + return _PC_CHOWN_RESTRICTED; + case TARGET_PC_ASYNC_IO: + return _PC_ASYNC_IO; + case TARGET_PC_PRIO_IO: + return _PC_PRIO_IO; + case TARGET_PC_SYNC_IO: + return _PC_SYNC_IO; +#ifndef TARGET_ABI_IRIX + case TARGET_PC_ALLOC_SIZE_MIN: + return _PC_ALLOC_SIZE_MIN; + case TARGET_PC_REC_INCR_XFER_SIZE: + return _PC_REC_INCR_XFER_SIZE; + case TARGET_PC_REC_MAX_XFER_SIZE: + return _PC_REC_MAX_XFER_SIZE; + case TARGET_PC_REC_MIN_XFER_SIZE: + return _PC_REC_MIN_XFER_SIZE; + case TARGET_PC_REC_XFER_ALIGN: + return _PC_REC_XFER_ALIGN; + case TARGET_PC_SYMLINK_MAX: + return _PC_SYMLINK_MAX; + case TARGET_PC_2_SYMLINKS: + return _PC_2_SYMLINKS; +#endif + default: + return code; + } +} +#endif + static inline abi_long copy_from_user_timeval(struct timeval *tv, abi_ulong target_tv_addr) { @@ -1491,6 +1613,7 @@ static abi_long do_select(int n, if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) return -TARGET_EFAULT; +#ifndef TARGET_ABI_IRIX if (target_tv_addr) { tv.tv_sec = ts.tv_sec; tv.tv_usec = ts.tv_nsec / 1000; @@ -1498,6 +1621,7 @@ static abi_long do_select(int n, return -TARGET_EFAULT; } } +#endif } return ret; @@ -1514,11 +1638,11 @@ static abi_long do_old_select(abi_ulong arg1) return -TARGET_EFAULT; } - nsel = tswapal(sel->n); - inp = tswapal(sel->inp); - outp = tswapal(sel->outp); - exp = tswapal(sel->exp); - tvp = tswapal(sel->tvp); + __get_user(nsel, &sel->n); + __get_user(inp, &sel->inp); + __get_user(outp, &sel->outp); + __get_user(exp, &sel->exp); + __get_user(tvp, &sel->tvp); unlock_user_struct(sel, arg1, 0); @@ -1582,7 +1706,7 @@ static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; if (len == sizeof(struct target_ip_mreqn)) - mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex); + __get_user(mreqn->imr_ifindex, &target_smreqn->imr_ifindex); unlock_user(target_smreqn, target_addr, 0); return 0; @@ -1604,7 +1728,7 @@ static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr, if (!target_saddr) return -TARGET_EFAULT; - sa_family = tswap16(target_saddr->sa_family); + __get_user(sa_family, &target_saddr->sa_family); /* Oops. The caller might send a incomplete sun_path; sun_path * must be terminated by \0 (see the manual page), but @@ -1631,14 +1755,14 @@ static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr, struct sockaddr_nl *nladdr; nladdr = (struct sockaddr_nl *)addr; - nladdr->nl_pid = tswap32(nladdr->nl_pid); - nladdr->nl_groups = tswap32(nladdr->nl_groups); + __get_user(nladdr->nl_pid, &nladdr->nl_pid); + __get_user(nladdr->nl_groups, &nladdr->nl_groups); } else if (sa_family == AF_PACKET) { struct target_sockaddr_ll *lladdr; lladdr = (struct target_sockaddr_ll *)addr; - lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex); - lladdr->sll_hatype = tswap16(lladdr->sll_hatype); + __get_user(lladdr->sll_ifindex, &lladdr->sll_ifindex); + __get_user(lladdr->sll_hatype, &lladdr->sll_hatype); } unlock_user(target_saddr, target_addr, 0); @@ -1662,21 +1786,21 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, memcpy(target_saddr, addr, len); if (len >= offsetof(struct target_sockaddr, sa_family) + sizeof(target_saddr->sa_family)) { - target_saddr->sa_family = tswap16(addr->sa_family); + __put_user(addr->sa_family, &target_saddr->sa_family); } if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) { struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr; - target_nl->nl_pid = tswap32(target_nl->nl_pid); - target_nl->nl_groups = tswap32(target_nl->nl_groups); + __put_user(target_nl->nl_pid, &target_nl->nl_pid); + __put_user(target_nl->nl_groups, &target_nl->nl_groups); } else if (addr->sa_family == AF_PACKET) { struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr; - target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex); - target_ll->sll_hatype = tswap16(target_ll->sll_hatype); + __put_user(target_ll->sll_ifindex, &target_ll->sll_ifindex); + __put_user(target_ll->sll_hatype, &target_ll->sll_hatype); } else if (addr->sa_family == AF_INET6 && len >= sizeof(struct target_sockaddr_in6)) { struct target_sockaddr_in6 *target_in6 = (struct target_sockaddr_in6 *)target_saddr; - target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id); + __put_user(target_in6->sin6_scope_id, &target_in6->sin6_scope_id); } unlock_user(target_saddr, target_addr, len); @@ -1692,10 +1816,10 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, struct target_cmsghdr *target_cmsg, *target_cmsg_start; socklen_t space = 0; - msg_controllen = tswapal(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + __get_user(msg_controllen, &target_msgh->msg_controllen); + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; - target_cmsg_addr = tswapal(target_msgh->msg_control); + __get_user(target_cmsg_addr, &target_msgh->msg_control); target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); target_cmsg_start = target_cmsg; if (!target_cmsg) @@ -1704,9 +1828,10 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, while (cmsg && target_cmsg) { void *data = CMSG_DATA(cmsg); void *target_data = TARGET_CMSG_DATA(target_cmsg); + int len, level; - int len = tswapal(target_cmsg->cmsg_len) - - sizeof(struct target_cmsghdr); + __get_user(len, &target_cmsg->cmsg_len); + len -= TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); space += CMSG_SPACE(len); if (space > msgh->msg_controllen) { @@ -1724,12 +1849,13 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, break; } - if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) { + __get_user(level, &target_cmsg->cmsg_level); + if (level == TARGET_SOL_SOCKET) { cmsg->cmsg_level = SOL_SOCKET; } else { - cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); + cmsg->cmsg_level = level; } - cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); + __get_user(cmsg->cmsg_type, &target_cmsg->cmsg_type); cmsg->cmsg_len = CMSG_LEN(len); if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { @@ -1774,10 +1900,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, struct target_cmsghdr *target_cmsg, *target_cmsg_start; socklen_t space = 0; - msg_controllen = tswapal(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + __get_user(msg_controllen, &target_msgh->msg_controllen); + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; - target_cmsg_addr = tswapal(target_msgh->msg_control); + __get_user(target_cmsg_addr, &target_msgh->msg_control); target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); target_cmsg_start = target_cmsg; if (!target_cmsg) @@ -1802,11 +1928,11 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, } if (cmsg->cmsg_level == SOL_SOCKET) { - target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET); + __put_user(TARGET_SOL_SOCKET, &target_cmsg->cmsg_level); } else { - target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); + __put_user(cmsg->cmsg_level, &target_cmsg->cmsg_level); } - target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); + __put_user(cmsg->cmsg_type, &target_cmsg->cmsg_type); /* Payload types which need a different size of payload on * the target must adjust tgt_len here. @@ -1979,7 +2105,8 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, } } - target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len)); + tgt_len = TARGET_CMSG_LEN(tgt_len); + __put_user(tgt_len, &target_cmsg->cmsg_len); tgt_space = TARGET_CMSG_SPACE(tgt_len); if (msg_controllen < tgt_space) { tgt_space = msg_controllen; @@ -1992,7 +2119,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, } unlock_user(target_cmsg, target_cmsg_addr, space); the_end: - target_msgh->msg_controllen = tswapal(space); + __put_user(space, &target_msgh->msg_controllen); return 0; } @@ -2859,7 +2986,6 @@ static abi_long target_to_host_data_audit(struct nlmsghdr *nlh) nlh->nlmsg_type); return -TARGET_EINVAL; } - return 0; } @@ -2874,6 +3000,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, { abi_long ret; int val; + void *target_optval; struct ip_mreqn *ip_mreq; struct ip_mreq_source *ip_mreq_source; @@ -3032,6 +3159,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, } break; case TARGET_SOL_SOCKET: + ret = 0; switch (optname) { case TARGET_SO_RCVTIMEO: { @@ -3125,6 +3253,10 @@ set_timeout: case TARGET_SO_REUSEADDR: optname = SO_REUSEADDR; break; + case TARGET_SO_LINGER: + optname = SO_LINGER; + if (optlen < sizeof(struct linger)) ret = -TARGET_EINVAL; + break; case TARGET_SO_TYPE: optname = SO_TYPE; break; @@ -3184,9 +3316,10 @@ set_timeout: if (optlen < sizeof(uint32_t)) return -TARGET_EINVAL; - if (get_user_u32(val, optval_addr)) + if (!(target_optval = lock_user(VERIFY_READ, optval_addr, optlen, 1))) return -TARGET_EFAULT; - ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, target_optval, optlen)); + unlock_user(target_optval, optval_addr, 0); break; default: unimplemented: @@ -3422,8 +3555,10 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, total_len = 0; for (i = 0; i < count; i++) { - abi_ulong base = tswapal(target_vec[i].iov_base); - abi_long len = tswapal(target_vec[i].iov_len); + abi_ulong base; + abi_long len; + __get_user(base, &target_vec[i].iov_base); + __get_user(len, &target_vec[i].iov_len); if (len < 0) { err = EINVAL; @@ -3461,8 +3596,10 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, fail: while (--i >= 0) { - if (tswapal(target_vec[i].iov_len) > 0) { - unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0); + if (vec[i].iov_len > 0) { + abi_ulong base; + __get_user(base, &target_vec[i].iov_base); + unlock_user(vec[i].iov_base, base, 0); } } unlock_user(target_vec, target_addr, 0); @@ -3482,8 +3619,10 @@ static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, count * sizeof(struct target_iovec), 1); if (target_vec) { for (i = 0; i < count; i++) { - abi_ulong base = tswapal(target_vec[i].iov_base); - abi_long len = tswapal(target_vec[i].iov_len); + abi_ulong base; + abi_long len; + __get_user(base, &target_vec[i].iov_base); + __get_user(len, &target_vec[i].iov_len); if (len < 0) { break; } @@ -3557,7 +3696,7 @@ static abi_long packet_target_to_host_sockaddr(void *host_addr, } memcpy(addr, target_saddr, len); - addr->sa_family = tswap16(target_saddr->sa_family); + __get_user(addr->sa_family, &target_saddr->sa_family); /* spkt_protocol is big-endian */ unlock_user(target_saddr, target_addr, 0); @@ -3733,7 +3872,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, abi_ulong target_vec; if (msgp->msg_name) { - msg.msg_namelen = tswap32(msgp->msg_namelen); + __get_user(msg.msg_namelen, &msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen+1); ret = target_to_host_sockaddr(fd, msg.msg_name, tswapal(msgp->msg_name), @@ -3752,12 +3891,12 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, msg.msg_name = NULL; msg.msg_namelen = 0; } - msg.msg_controllen = 2 * tswapal(msgp->msg_controllen); + __get_user(msg.msg_controllen, &msgp->msg_controllen); msg.msg_control = alloca(msg.msg_controllen); - msg.msg_flags = tswap32(msgp->msg_flags); + __get_user(msg.msg_flags, &msgp->msg_flags); - count = tswapal(msgp->msg_iovlen); - target_vec = tswapal(msgp->msg_iov); + __get_user(count, &msgp->msg_iovlen); + __get_user(target_vec, &msgp->msg_iov); if (count > IOV_MAX) { /* sendrcvmsg returns a different errno for this condition than @@ -3806,7 +3945,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, ret = host_to_target_cmsg(msgp, &msg); } if (!is_error(ret)) { - msgp->msg_namelen = tswap32(msg.msg_namelen); + __put_user(msg.msg_namelen, &msgp->msg_namelen); if (msg.msg_name != NULL && msg.msg_name != (void *)-1) { ret = host_to_target_sockaddr(tswapal(msgp->msg_name), msg.msg_name, msg.msg_namelen); @@ -3850,6 +3989,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, #define MSG_WAITFORONE 0x10000 #endif +#if defined(TARGET_NR_socketcall) || defined(TARGET_NR_sendmmsg) static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec, unsigned int vlen, unsigned int flags, int send) @@ -3872,7 +4012,7 @@ static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec, if (is_error(ret)) { break; } - mmsgp[i].msg_len = tswap32(ret); + __put_user(ret, &mmsgp[i].msg_len); /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ if (flags & MSG_WAITFORONE) { flags |= MSG_DONTWAIT; @@ -3889,6 +4029,7 @@ static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec, } return ret; } +#endif /* do_accept4() Must return target values and target errnos. */ static abi_long do_accept4(int fd, abi_ulong target_addr, @@ -3985,6 +4126,7 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, return ret; } +#ifndef TARGET_ABI_SOLARIS /* do_socketpair() Must return target values and target errnos. */ static abi_long do_socketpair(int domain, int type, int protocol, abi_ulong target_tab_addr) @@ -4002,6 +4144,7 @@ static abi_long do_socketpair(int domain, int type, int protocol, } return ret; } +#endif /* do_sendto() Must return target values and target errnos. */ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, @@ -4224,20 +4367,20 @@ static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) return -TARGET_EFAULT; target_ip = &(target_sd->sem_perm); - host_ip->__key = tswap32(target_ip->__key); - host_ip->uid = tswap32(target_ip->uid); - host_ip->gid = tswap32(target_ip->gid); - host_ip->cuid = tswap32(target_ip->cuid); - host_ip->cgid = tswap32(target_ip->cgid); + __get_user(host_ip->__key, &target_ip->__key); + __get_user(host_ip->uid, &target_ip->uid); + __get_user(host_ip->gid, &target_ip->gid); + __get_user(host_ip->cuid, &target_ip->cuid); + __get_user(host_ip->cgid, &target_ip->cgid); #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC) - host_ip->mode = tswap32(target_ip->mode); + __get_user(host_ip->mode, &target_ip->mode); #else - host_ip->mode = tswap16(target_ip->mode); + __get_user(host_ip->mode, &target_ip->mode); #endif #if defined(TARGET_PPC) - host_ip->__seq = tswap32(target_ip->__seq); + __get_user(host_ip->__seq, &target_ip->__seq); #else - host_ip->__seq = tswap16(target_ip->__seq); + __get_user(host_ip->__seq, &target_ip->__seq); #endif unlock_user_struct(target_sd, target_addr, 0); return 0; @@ -4252,20 +4395,20 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) return -TARGET_EFAULT; target_ip = &(target_sd->sem_perm); - target_ip->__key = tswap32(host_ip->__key); - target_ip->uid = tswap32(host_ip->uid); - target_ip->gid = tswap32(host_ip->gid); - target_ip->cuid = tswap32(host_ip->cuid); - target_ip->cgid = tswap32(host_ip->cgid); + __put_user(host_ip->__key, &target_ip->__key); + __put_user(host_ip->uid, &target_ip->uid); + __put_user(host_ip->gid, &target_ip->gid); + __put_user(host_ip->cuid, &target_ip->cuid); + __put_user(host_ip->cgid, &target_ip->cgid); #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC) - target_ip->mode = tswap32(host_ip->mode); + __put_user(host_ip->mode, &target_ip->mode); #else - target_ip->mode = tswap16(host_ip->mode); + __put_user(host_ip->mode, &target_ip->mode); #endif #if defined(TARGET_PPC) - target_ip->__seq = tswap32(host_ip->__seq); + __put_user(host_ip->__seq, &target_ip->__seq); #else - target_ip->__seq = tswap16(host_ip->__seq); + __put_user(host_ip->__seq, &target_ip->__seq); #endif unlock_user_struct(target_sd, target_addr, 1); return 0; @@ -4280,9 +4423,9 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, return -TARGET_EFAULT; if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr)) return -TARGET_EFAULT; - host_sd->sem_nsems = tswapal(target_sd->sem_nsems); - host_sd->sem_otime = tswapal(target_sd->sem_otime); - host_sd->sem_ctime = tswapal(target_sd->sem_ctime); + __get_user(host_sd->sem_nsems, &target_sd->sem_nsems); + __get_user(host_sd->sem_otime, &target_sd->sem_otime); + __get_user(host_sd->sem_ctime, &target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 0); return 0; } @@ -4296,9 +4439,9 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, return -TARGET_EFAULT; if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm))) return -TARGET_EFAULT; - target_sd->sem_nsems = tswapal(host_sd->sem_nsems); - target_sd->sem_otime = tswapal(host_sd->sem_otime); - target_sd->sem_ctime = tswapal(host_sd->sem_ctime); + __put_user(host_sd->sem_nsems, &target_sd->sem_nsems); + __put_user(host_sd->sem_otime, &target_sd->sem_otime); + __put_user(host_sd->sem_ctime, &target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 1); return 0; } @@ -4345,9 +4488,15 @@ union semun { union target_semun { int val; +#ifdef TARGET_ABI32 + abi_uint buf; + abi_uint array; + abi_uint __buf; +#else abi_ulong buf; abi_ulong array; abi_ulong __buf; +#endif }; static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array, @@ -4559,14 +4708,14 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, return -TARGET_EFAULT; if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr)) return -TARGET_EFAULT; - host_md->msg_stime = tswapal(target_md->msg_stime); - host_md->msg_rtime = tswapal(target_md->msg_rtime); - host_md->msg_ctime = tswapal(target_md->msg_ctime); - host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes); - host_md->msg_qnum = tswapal(target_md->msg_qnum); - host_md->msg_qbytes = tswapal(target_md->msg_qbytes); - host_md->msg_lspid = tswapal(target_md->msg_lspid); - host_md->msg_lrpid = tswapal(target_md->msg_lrpid); + __get_user(host_md->msg_stime, &target_md->msg_stime); + __get_user(host_md->msg_rtime, &target_md->msg_rtime); + __get_user(host_md->msg_ctime, &target_md->msg_ctime); + __get_user(host_md->__msg_cbytes, &target_md->__msg_cbytes); + __get_user(host_md->msg_qnum, &target_md->msg_qnum); + __get_user(host_md->msg_qbytes, &target_md->msg_qbytes); + __get_user(host_md->msg_lspid, &target_md->msg_lspid); + __get_user(host_md->msg_lrpid, &target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); return 0; } @@ -4580,14 +4729,14 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, return -TARGET_EFAULT; if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm))) return -TARGET_EFAULT; - target_md->msg_stime = tswapal(host_md->msg_stime); - target_md->msg_rtime = tswapal(host_md->msg_rtime); - target_md->msg_ctime = tswapal(host_md->msg_ctime); - target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes); - target_md->msg_qnum = tswapal(host_md->msg_qnum); - target_md->msg_qbytes = tswapal(host_md->msg_qbytes); - target_md->msg_lspid = tswapal(host_md->msg_lspid); - target_md->msg_lrpid = tswapal(host_md->msg_lrpid); + __put_user(host_md->msg_stime, &target_md->msg_stime); + __put_user(host_md->msg_rtime, &target_md->msg_rtime); + __put_user(host_md->msg_ctime, &target_md->msg_ctime); + __put_user(host_md->__msg_cbytes, &target_md->__msg_cbytes); + __put_user(host_md->msg_qnum, &target_md->msg_qnum); + __put_user(host_md->msg_qbytes, &target_md->msg_qbytes); + __put_user(host_md->msg_lspid, &target_md->msg_lspid); + __put_user(host_md->msg_lrpid, &target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 1); return 0; } @@ -4676,7 +4825,7 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, unlock_user_struct(target_mb, msgp, 0); return -TARGET_ENOMEM; } - host_mb->mtype = (abi_long) tswapal(target_mb->mtype); + __get_user(host_mb->mtype, &target_mb->mtype); memcpy(host_mb->mtext, target_mb->mtext, msgsz); ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg)); g_free(host_mb); @@ -4719,7 +4868,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, unlock_user(target_mtext, target_mtext_addr, ret); } - target_mb->mtype = tswapal(host_mb->mtype); + __put_user(host_mb->mtype, &target_mb->mtype); end: if (target_mb) @@ -5100,7 +5249,7 @@ struct IOCTLEntry { #define MAX_STRUCT_SIZE 4096 -#ifdef CONFIG_FIEMAP +#if defined(CONFIG_FIEMAP) && !defined(TARGET_ABI_IRIX) && !defined(TARGET_ABI_SOLARIS) /* So fiemap access checks don't overflow on 32 bit systems. * This is very slightly smaller than the limit imposed by * the underlying kernel. @@ -5283,6 +5432,7 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp, return ret; } +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, int cmd, abi_long arg) { @@ -5635,6 +5785,7 @@ static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp, int sig = target_to_host_signal(arg); return get_errno(safe_ioctl(fd, ie->host_cmd, sig)); } +#endif #ifdef TIOCGPTPEER static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp, @@ -5652,6 +5803,8 @@ static IOCTLEntry ioctl_entries[] = { { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } }, #define IOCTL_IGNORE(cmd) \ { TARGET_ ## cmd, 0, #cmd }, +#define IOCTL_MAP(tcmd, hcmd, access, ...) \ + { TARGET_ ## tcmd, hcmd, #hcmd, access, 0, { __VA_ARGS__ } }, #include "ioctls.h" { 0, 0, }, }; @@ -5860,7 +6013,10 @@ static void target_to_host_termios (void *dst, const void *src) target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); +#if defined TARGET_ABI_IRIX +#elif !defined TARGET_ABI_SOLARIS host->c_line = target->c_line; +#endif memset(host->c_cc, 0, sizeof(host->c_cc)); host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; @@ -5895,7 +6051,14 @@ static void host_to_target_termios (void *dst, const void *src) tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); +#if defined TARGET_ABI_IRIX +#ifdef NEW + target->c_ospeed = 0; + target->c_ispeed = 0; +#endif +#elif !defined TARGET_ABI_SOLARIS target->c_line = host->c_line; +#endif memset(target->c_cc, 0, sizeof(target->c_cc)); target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; @@ -5984,10 +6147,10 @@ static abi_long write_ldt(CPUX86State *env, return -TARGET_EINVAL; if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) return -TARGET_EFAULT; - ldt_info.entry_number = tswap32(target_ldt_info->entry_number); - ldt_info.base_addr = tswapal(target_ldt_info->base_addr); - ldt_info.limit = tswap32(target_ldt_info->limit); - ldt_info.flags = tswap32(target_ldt_info->flags); + __get_user(ldt_info.entry_number, &target_ldt_info->entry_number); + __get_user(ldt_info.base_addr, &target_ldt_info->base_addr); + __get_user(ldt_info.limit, &target_ldt_info->limit); + __get_user(ldt_info.flags, &target_ldt_info->flags); unlock_user_struct(target_ldt_info, ptr, 0); if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) @@ -6057,8 +6220,8 @@ static abi_long write_ldt(CPUX86State *env, /* Install the new entry ... */ install: lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); - lp[0] = tswap32(entry_1); - lp[1] = tswap32(entry_2); + __put_user(entry_1, &lp[0]); + __put_user(entry_2, &lp[1]); return 0; } @@ -6099,15 +6262,15 @@ abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); if (!target_ldt_info) return -TARGET_EFAULT; - ldt_info.entry_number = tswap32(target_ldt_info->entry_number); - ldt_info.base_addr = tswapal(target_ldt_info->base_addr); - ldt_info.limit = tswap32(target_ldt_info->limit); - ldt_info.flags = tswap32(target_ldt_info->flags); + __get_user(ldt_info.entry_number, &target_ldt_info->entry_number); + __get_user(ldt_info.base_addr, &target_ldt_info->base_addr); + __get_user(ldt_info.limit, &target_ldt_info->limit); + __get_user(ldt_info.flags, &target_ldt_info->flags); if (ldt_info.entry_number == -1) { for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) { if (gdt_table[i] == 0) { ldt_info.entry_number = i; - target_ldt_info->entry_number = tswap32(i); + __put_user(i, &target_ldt_info->entry_number); break; } } @@ -6166,8 +6329,8 @@ abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) /* Install the new entry ... */ install: lp = (uint32_t *)(gdt_table + ldt_info.entry_number); - lp[0] = tswap32(entry_1); - lp[1] = tswap32(entry_2); + __put_user(entry_1, &lp[0]); + __put_user(entry_2, &lp[1]); return 0; } @@ -6183,15 +6346,15 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); if (!target_ldt_info) return -TARGET_EFAULT; - idx = tswap32(target_ldt_info->entry_number); + __get_user(idx, &target_ldt_info->entry_number); if (idx < TARGET_GDT_ENTRY_TLS_MIN || idx > TARGET_GDT_ENTRY_TLS_MAX) { unlock_user_struct(target_ldt_info, ptr, 1); return -TARGET_EINVAL; } lp = (uint32_t *)(gdt_table + idx); - entry_1 = tswap32(lp[0]); - entry_2 = tswap32(lp[1]); + __get_user(entry_1, &lp[0]); + __get_user(entry_2, &lp[1]); read_exec_only = ((entry_2 >> 9) & 1) ^ 1; contents = (entry_2 >> 10) & 3; @@ -6211,9 +6374,9 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) base_addr = (entry_1 >> 16) | (entry_2 & 0xff000000) | ((entry_2 & 0xff) << 16); - target_ldt_info->base_addr = tswapal(base_addr); - target_ldt_info->limit = tswap32(limit); - target_ldt_info->flags = tswap32(flags); + __put_user(base_addr, &target_ldt_info->base_addr); + __put_user(limit, &target_ldt_info->limit); + __put_user(flags, &target_ldt_info->flags); unlock_user_struct(target_ldt_info, ptr, 1); return 0; } @@ -6286,6 +6449,11 @@ static void *clone_func(void *arg) ts = (TaskState *)cpu->opaque; info->tid = gettid(); task_settid(ts); +#ifdef TARGET_ABI_IRIX + /* TODO: which fields in the PRDA are filled in by the IRIX kernel? */ + __put_user(info->tid, (abi_int *)&ts->prda[0xe00]); /* t_pid */ + __put_user(info->tid, (abi_int *)&ts->prda[0xe40]); /* t_rpid */ +#endif if (info->child_tidptr) put_user_u32(info->tid, info->child_tidptr); if (info->parent_tidptr) @@ -6308,7 +6476,7 @@ static void *clone_func(void *arg) do_*() functions). */ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, abi_ulong parent_tidptr, target_ulong newtls, - abi_ulong child_tidptr) + abi_ulong child_tidptr, abi_ulong entry, abi_ulong arg) { CPUState *cpu = ENV_GET_CPU(env); int ret; @@ -6341,6 +6509,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, cpu_clone_regs(new_env, newsp); new_cpu = ENV_GET_CPU(new_env); new_cpu->opaque = ts; +#ifdef TARGET_ABI_IRIX + if (entry) { /* sproc */ + new_env->active_tc.PC = entry; + new_env->active_tc.gpr[4] = arg; + new_env->active_tc.gpr[29] = newsp; + } + ts->parent_task = parent_ts; + /* copy global parameters... */ + ts->exit_sig = parent_ts->exit_sig; + ts->is_pthread = parent_ts->is_pthread; +#endif ts->bprm = parent_ts->bprm; ts->info = parent_ts->info; ts->signal_mask = parent_ts->signal_mask; @@ -6411,16 +6590,18 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, return -TARGET_EINVAL; } - if (block_signals()) { + if (block_signals(env)) { return -TARGET_ERESTARTSYS; } - fork_start(); + fork_start(env); ret = fork(); if (ret == 0) { /* Child Process. */ cpu_clone_regs(env, newsp); - fork_end(1); + ts = (TaskState *)cpu->opaque; + task_settid(ts); + fork_end(env, 1); /* There is a race condition here. The parent process could theoretically read the TID in the child process before the child tid is set. This would require using either ptrace @@ -6431,18 +6612,106 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, put_user_u32(gettid(), child_tidptr); if (flags & CLONE_PARENT_SETTID) put_user_u32(gettid(), parent_tidptr); - ts = (TaskState *)cpu->opaque; if (flags & CLONE_SETTLS) cpu_set_tls (env, newtls); if (flags & CLONE_CHILD_CLEARTID) ts->child_tidptr = child_tidptr; } else { - fork_end(0); + fork_end(env, 0); } +#ifdef TARGET_ABI_SOLARIS + if (ret >= 0) + env->regwptr[1] = (ret == 0); + if (ret == 0) + ret = getppid(); +#endif +#ifdef TARGET_ABI_IRIX + if (entry && ret == 0) { /* sproc, child */ + env->active_tc.PC = entry; + env->active_tc.gpr[4] = arg; + env->active_tc.gpr[29] = newsp; + } else if (ret >= 0) + env->active_tc.gpr[3] = (ret == 0); +#endif } return ret; } +static int do_exit(CPUArchState *env, abi_int status) +{ + CPUState *cpu = ENV_GET_CPU(env); + + if (block_signals(env)) { + return -TARGET_ERESTARTSYS; + } + + /* In old applications this may be used to implement _exit(2). + However in threaded applictions it is used for thread termination, + and _exit_group is used for application termination. + Do thread termination if we have more then one thread. */ + + cpu_list_lock(); + + if (CPU_NEXT(first_cpu)) { + TaskState *ts; + + /* Remove the CPU from the list. */ + QTAILQ_REMOVE(&cpus, cpu, node); + + cpu_list_unlock(); + + ts = cpu->opaque; + if (ts->child_tidptr) { + put_user_u32(0, ts->child_tidptr); + sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX, + NULL, NULL, 0); + } +#ifdef TARGET_ABI_IRIX + /* send exit_sig to share group if set */ + if (ts->exit_sig) { + CPUState *p; + for (p = first_cpu; p; p = CPU_NEXT(p)) { + target_siginfo_t info = { 0 }; + info.si_signo = ts->exit_sig; + queue_signal((CPUArchState *)p->env_ptr, info.si_signo, + QEMU_SI_KILL, &info); + /* TODO: must process here because thread may be blocked? */ + process_pending_signals((CPUArchState *)p->env_ptr); + } + } + /* send termchild_sig to children if set */ + { + CPUState *p; TaskState *t; + for (p = first_cpu; p; p = CPU_NEXT(p)) { + t = (TaskState *)p->opaque; + if (t->parent_task == ts && t->termchild_sig) { + target_siginfo_t info = { 0 }; + info.si_signo = t->termchild_sig; + queue_signal((CPUArchState *)p->env_ptr, info.si_signo, + QEMU_SI_KILL, &info); + /* TODO: must process here because thread may be blocked? */ + process_pending_signals((CPUArchState *)p->env_ptr); + } + } + } +#endif + thread_cpu = NULL; + object_unref(OBJECT(cpu)); + g_free(ts); + rcu_unregister_thread(); + pthread_exit(NULL); + } + + cpu_list_unlock(); + /* either last thread, or unthreaded application */ +#ifdef TARGET_GPROF + _mcleanup(); +#endif + gdb_exit(env, status); + _exit(status); + return 0; +} + /* warning : doesn't handle linux specific flags... */ static int target_to_host_fcntl_cmd(int cmd) { @@ -6463,10 +6732,12 @@ static int target_to_host_fcntl_cmd(int cmd) return F_GETOWN; case TARGET_F_SETOWN: return F_SETOWN; +#ifdef TARGET_F_GETSIG case TARGET_F_GETSIG: return F_GETSIG; case TARGET_F_SETSIG: return F_SETSIG; +#endif #if TARGET_ABI_BITS == 32 case TARGET_F_GETLK64: return F_GETLK64; @@ -6485,11 +6756,11 @@ static int target_to_host_fcntl_cmd(int cmd) #endif case TARGET_F_NOTIFY: return F_NOTIFY; -#ifdef F_GETOWN_EX +#if defined F_GETOWN_EX && defined TARGET_F_GETOWN_EX case TARGET_F_GETOWN_EX: return F_GETOWN_EX; #endif -#ifdef F_SETOWN_EX +#if defined F_SETOWN_EX && defined TARGET_F_SETOWN_EX case TARGET_F_SETOWN_EX: return F_SETOWN_EX; #endif @@ -6643,13 +6914,53 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr, static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) { struct flock64 fl64; -#ifdef F_GETOWN_EX +#if defined F_GETOWN_EX && defined TARGET_F_GETOWN_EX struct f_owner_ex fox; struct target_f_owner_ex *target_fox; #endif abi_long ret; - int host_cmd = target_to_host_fcntl_cmd(cmd); + int host_cmd; +#ifdef TARGET_F_ALLOCSP + if (cmd == TARGET_F_FREESP || cmd == TARGET_F_ALLOCSP) + { + struct stat st; + int wh; + ret = copy_from_user_flock(&fl64, arg); + if (ret) { + return ret; + } + if (fl64.l_whence == SEEK_CUR) + fl64.l_start += lseek(fd, 0, SEEK_CUR); + if (fl64.l_whence == SEEK_END && fstat(fd, &st) >= 0) + fl64.l_start += st.st_size; + wh = (cmd == TARGET_F_FREESP || cmd == TARGET_F_FREESP64 ? FALLOC_FL_PUNCH_HOLE : 0); + return get_errno(fallocate(fd, wh, (fl64.l_len ? fl64.l_start : 0), (fl64.l_len ?: fl64.l_start))); + } + if (cmd == TARGET_F_FREESP64 || cmd == TARGET_F_ALLOCSP64) + { + struct stat st; + int wh; + ret = copy_from_user_flock64(&fl64, arg); + if (ret) { + return ret; + } + if (fl64.l_whence == SEEK_CUR) + fl64.l_start += lseek(fd, 0, SEEK_CUR); + if (fl64.l_whence == SEEK_END && fstat(fd, &st) >= 0) + fl64.l_start += st.st_size; + wh = (cmd == TARGET_F_FREESP || cmd == TARGET_F_FREESP64 ? FALLOC_FL_PUNCH_HOLE : 0); + return get_errno(fallocate(fd, wh, (fl64.l_len ? fl64.l_start : 0), (fl64.l_len ?: fl64.l_start))); + } +#endif +#ifdef TARGET_F_DUP2FD + if (cmd == TARGET_F_DUP2FD) + { + return get_errno(dup2(fd, arg)); + } +#endif + + host_cmd = target_to_host_fcntl_cmd(cmd); if (host_cmd == -TARGET_EINVAL) return host_cmd; @@ -6706,25 +7017,25 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fcntl_flags_tbl))); break; -#ifdef F_GETOWN_EX +#if defined F_GETOWN_EX && defined TARGET_F_GETOWN_EX case TARGET_F_GETOWN_EX: ret = get_errno(safe_fcntl(fd, host_cmd, &fox)); if (ret >= 0) { if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0)) return -TARGET_EFAULT; - target_fox->type = tswap32(fox.type); - target_fox->pid = tswap32(fox.pid); + __put_user(fox.type, &target_fox->type); + __put_user(fox.pid, &target_fox->pid); unlock_user_struct(target_fox, arg, 1); } break; #endif -#ifdef F_SETOWN_EX +#if defined F_SETOWN_EX && defined TARGET_F_SETOWN_EX case TARGET_F_SETOWN_EX: if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1)) return -TARGET_EFAULT; - fox.type = tswap32(target_fox->type); - fox.pid = tswap32(target_fox->pid); + __get_user(fox.type, &target_fox->type); + __get_user(fox.pid, &target_fox->pid); unlock_user_struct(target_fox, arg, 0); ret = get_errno(safe_fcntl(fd, host_cmd, &fox)); break; @@ -6732,8 +7043,10 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETOWN: case TARGET_F_GETOWN: +#ifdef TARGET_F_SETSIG case TARGET_F_SETSIG: case TARGET_F_GETSIG: +#endif case TARGET_F_SETLEASE: case TARGET_F_GETLEASE: case TARGET_F_SETPIPE_SZ: @@ -6843,10 +7156,18 @@ static inline int tswapid(int id) #define __NR_sys_setresgid __NR_setresgid #endif +#ifdef TARGET_NR_setuid32 _syscall1(int, sys_setuid, uid_t, uid) +#endif +#ifdef TARGET_NR_setgid32 _syscall1(int, sys_setgid, gid_t, gid) +#endif +#if defined(TARGET_NR_setresuid) || defined(TARGET_NR_setresuid32) _syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) +#endif +#if defined(TARGET_NR_setresgid) || defined(TARGET_NR_setresgid32) _syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) +#endif void syscall_init(void) { @@ -6922,11 +7243,10 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1, abi_long arg3, abi_long arg4) { - if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) { - arg2 = arg3; - arg3 = arg4; - } - return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); + if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) + return get_errno(truncate64(arg1, target_offset64(arg3, arg4))); + else + return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); } #endif @@ -6936,11 +7256,10 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, abi_long arg3, abi_long arg4) { - if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) { - arg2 = arg3; - arg3 = arg4; - } - return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); + if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) + return get_errno(ftruncate64(arg1, target_offset64(arg3, arg4))); + else + return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); } #endif @@ -6979,12 +7298,12 @@ static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec, return -TARGET_EFAULT; } - host_itspec->it_interval.tv_sec = - tswapal(target_itspec->it_interval.tv_sec); - host_itspec->it_interval.tv_nsec = - tswapal(target_itspec->it_interval.tv_nsec); - host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec); - host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec); + __get_user(host_itspec->it_interval.tv_sec, + &target_itspec->it_interval.tv_sec); + __get_user(host_itspec->it_interval.tv_nsec, + &target_itspec->it_interval.tv_nsec); + __get_user(host_itspec->it_value.tv_sec, &target_itspec->it_value.tv_sec); + __get_user(host_itspec->it_value.tv_nsec, &target_itspec->it_value.tv_nsec); unlock_user_struct(target_itspec, target_addr, 1); return 0; @@ -6999,11 +7318,11 @@ static inline abi_long host_to_target_itimerspec(abi_ulong target_addr, return -TARGET_EFAULT; } - target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec); - target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec); + __put_user(host_its->it_interval.tv_sec, &target_itspec->it_interval.tv_sec); + __put_user(host_its->it_interval.tv_nsec, &target_itspec->it_interval.tv_nsec); - target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec); - target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec); + __put_user(host_its->it_value.tv_sec, &target_itspec->it_value.tv_sec); + __put_user(host_its->it_value.tv_nsec, &target_itspec->it_value.tv_nsec); unlock_user_struct(target_itspec, target_addr, 0); return 0; @@ -7099,14 +7418,14 @@ static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr); host_sevp->sigev_signo = target_to_host_signal(tswap32(target_sevp->sigev_signo)); - host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify); - host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid); + __get_user(host_sevp->sigev_notify, &target_sevp->sigev_notify); + __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid); unlock_user_struct(target_sevp, target_addr, 1); return 0; } -#if defined(TARGET_NR_mlockall) +#if defined(TARGET_NR_mlockall) || defined(TARGET_NR_memcntl) static inline int target_to_host_mlockall_arg(int arg) { int result = 0; @@ -7121,6 +7440,39 @@ static inline int target_to_host_mlockall_arg(int arg) } #endif +static inline abi_long host_to_target_stat(void *cpu_env, + abi_ulong target_addr, + struct stat *host_st) +{ + struct target_stat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) + return -TARGET_EFAULT; + +#ifdef TARGET_ABI_IRIX + memset(target_st, 0, sizeof(*target_st)); +#else + memset(target_st, 0, offsetof(struct target_stat,st_blocks)); +#endif + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_atime, &target_st->target_st_atime); + __put_user(host_st->st_mtime, &target_st->target_st_mtime); + __put_user(host_st->st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + +#if defined(TARGET_NR_stat64) || defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat) || defined(TARGET_ABI_IRIX) static inline abi_long host_to_target_stat64(void *cpu_env, abi_ulong target_addr, struct stat *host_st) @@ -7183,7 +7535,9 @@ static inline abi_long host_to_target_stat64(void *cpu_env, return 0; } +#endif +#ifdef TARGET_NR_futex /* ??? Using host futex calls even when target atomic operations are not really atomic probably breaks things. However implementing futexes locally would make futexes shared between multiple processes @@ -7235,6 +7589,8 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, return -TARGET_ENOSYS; } } +#endif + #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname, abi_long handle, abi_long mount_id, @@ -7275,8 +7631,8 @@ static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname, */ memcpy(target_fh, fh, total_size); - target_fh->handle_bytes = tswap32(fh->handle_bytes); - target_fh->handle_type = tswap32(fh->handle_type); + __put_user(fh->handle_bytes, &target_fh->handle_bytes); + __put_user(fh->handle_type, &target_fh->handle_type); g_free(fh); unlock_user(target_fh, handle, total_size); @@ -7310,7 +7666,7 @@ static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle, fh = g_memdup(target_fh, total_size); fh->handle_bytes = size; - fh->handle_type = tswap32(target_fh->handle_type); + __get_user(fh->handle_type, &target_fh->handle_type); ret = get_errno(open_by_handle_at(mount_fd, fh, target_to_host_bitmask(flags, fcntl_flags_tbl))); @@ -7343,26 +7699,26 @@ host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo, tinfo->ssi_code == BUS_MCEERR_AO)) { uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1); uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1); - *tssi_addr_lsb = tswap16(*ssi_addr_lsb); + __put_user(*ssi_addr_lsb, tssi_addr_lsb); } #endif - tinfo->ssi_signo = tswap32(sig); - tinfo->ssi_errno = tswap32(tinfo->ssi_errno); - tinfo->ssi_code = tswap32(info->ssi_code); - tinfo->ssi_pid = tswap32(info->ssi_pid); - tinfo->ssi_uid = tswap32(info->ssi_uid); - tinfo->ssi_fd = tswap32(info->ssi_fd); - tinfo->ssi_tid = tswap32(info->ssi_tid); - tinfo->ssi_band = tswap32(info->ssi_band); - tinfo->ssi_overrun = tswap32(info->ssi_overrun); - tinfo->ssi_trapno = tswap32(info->ssi_trapno); - tinfo->ssi_status = tswap32(info->ssi_status); - tinfo->ssi_int = tswap32(info->ssi_int); - tinfo->ssi_ptr = tswap64(info->ssi_ptr); - tinfo->ssi_utime = tswap64(info->ssi_utime); - tinfo->ssi_stime = tswap64(info->ssi_stime); - tinfo->ssi_addr = tswap64(info->ssi_addr); + __put_user(sig, &tinfo->ssi_signo); + __put_user(info->ssi_errno, &tinfo->ssi_errno); + __put_user(info->ssi_code, &tinfo->ssi_code); + __put_user(info->ssi_pid, &tinfo->ssi_pid); + __put_user(info->ssi_uid, &tinfo->ssi_uid); + __put_user(info->ssi_fd, &tinfo->ssi_fd); + __put_user(info->ssi_tid, &tinfo->ssi_tid); + __put_user(info->ssi_band, &tinfo->ssi_band); + __put_user(info->ssi_overrun, &tinfo->ssi_overrun); + __put_user(info->ssi_trapno, &tinfo->ssi_trapno); + __put_user(info->ssi_status, &tinfo->ssi_status); + __put_user(info->ssi_int, &tinfo->ssi_int); + __put_user(info->ssi_ptr, &tinfo->ssi_ptr); + __put_user(info->ssi_utime, &tinfo->ssi_utime); + __put_user(info->ssi_stime, &tinfo->ssi_stime); + __put_user(info->ssi_addr, &tinfo->ssi_addr); } static abi_long host_to_target_data_signalfd(void *buf, size_t len) @@ -7705,6 +8061,7 @@ static target_timer_t get_timer_id(abi_long arg) return timerid; } +#if defined(TARGET_NR_eventfd) || defined(TARGET_NR_eventfd2) static abi_long swap_data_eventfd(void *buf, size_t len) { uint64_t *counter = buf; @@ -7726,6 +8083,7 @@ static TargetFdTrans target_eventfd_trans = { .host_to_target_data = swap_data_eventfd, .target_to_host_data = swap_data_eventfd, }; +#endif #if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \ (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \ @@ -7754,6 +8112,116 @@ static TargetFdTrans target_inotify_trans = { }; #endif +#ifdef TARGET_ABI_IRIX +/* IRIX usync stuff. usync synchronises accesses to an address */ +struct usync_ref { + abi_ulong addr; + pthread_mutex_t lock; + pthread_cond_t cond; + int waiters; + int count; + int handoffs; + struct usync_ref *next; +}; + +/* the usync list and the mutex protecting it */ +pthread_mutex_t usync_mutex = PTHREAD_MUTEX_INITIALIZER; +struct usync_ref *usync_list; + +/* get the usync reference for addr, or create one if it doesn't exist */ +static struct usync_ref *usync_get_sync(abi_ulong addr) +{ + struct usync_ref *p; + + pthread_mutex_lock(&usync_mutex); + for (p = usync_list; p; p = p->next) { + if (p->addr == addr) + break; + } + if (!p) { + p = malloc(sizeof(struct usync_ref)); + if (p) { + pthread_mutex_init(&p->lock, NULL); + pthread_cond_init(&p->cond, NULL); + p->waiters = p->count = p->handoffs = 0; + p->addr = addr; + p->next = usync_list; + usync_list = p; + } + } + pthread_mutex_unlock(&usync_mutex); + return p; +} + +/* IRIX psema stuff. POSIX semaphores */ +struct psema_ref { + char *name; + sem_t *sem; +}; + +/* the psema list and the mutex protecting it */ +#define PSEMA_MAX 30 +pthread_mutex_t psema_mutex = PTHREAD_MUTEX_INITIALIZER; +struct psema_ref psema_list[PSEMA_MAX]; + +/* get the pindex for sem or name, or -1 if it doesn't exist */ +static int psema_get_index(char *name, sem_t *sem, int create) +{ + struct psema_ref *p; + int i, empty = -1; + + pthread_mutex_lock(&psema_mutex); + for (i = 0, p = psema_list; i < PSEMA_MAX; i++, p++) { + if (p->sem) { + if (p->sem == sem || (name && p->name && !strcmp(p->name, name))) { + pthread_mutex_unlock(&psema_mutex); + return i; + } + } else if (empty < 0) + empty = i; + } + if (create && empty >= 0) { + psema_list[empty].name = name ? strdup(name) : NULL; + psema_list[empty].sem = sem; + i = empty; + } else + i = -1; + pthread_mutex_unlock(&psema_mutex); + return i; +} + +/* get sem_t for index */ +static sem_t *psema_get_sem(int index) +{ + if (index >= 0 && index < PSEMA_MAX) + return psema_list[index].sem; + return NULL; +} + +/* drop semaphore from list */ +static void psema_remove_index(int index) +{ + if (index >= 0 && index < PSEMA_MAX) { + if (psema_list[index].name) + free(psema_list[index].name); + psema_list[index].name = NULL; + psema_list[index].sem = NULL; + } +} + +/* remove name from semaphore */ +static void psema_unlink_index(char *name) +{ + int index = psema_get_index(name, NULL, 0); + + if (index >= 0 && index < PSEMA_MAX) { + free(psema_list[index].name); + psema_list[index].name = NULL; + } +} +#endif + +#ifdef TARGET_NR_sched_getaffinity static int target_to_host_cpu_mask(unsigned long *host_mask, size_t host_size, abi_ulong target_addr, @@ -7820,6 +8288,7 @@ static int host_to_target_cpu_mask(const unsigned long *host_mask, unlock_user(target_mask, target_addr, target_size); return 0; } +#endif /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. @@ -7833,6 +8302,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long ret; struct stat st; struct statfs stfs; +#ifdef TARGET_NR_statvfs + struct statvfs stvfs; +#endif void *p; #if defined(DEBUG_ERESTARTSYS) @@ -7859,46 +8331,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, switch(num) { case TARGET_NR_exit: - /* In old applications this may be used to implement _exit(2). - However in threaded applictions it is used for thread termination, - and _exit_group is used for application termination. - Do thread termination if we have more then one thread. */ - - if (block_signals()) { - ret = -TARGET_ERESTARTSYS; - break; - } - - cpu_list_lock(); - - if (CPU_NEXT(first_cpu)) { - TaskState *ts; - - /* Remove the CPU from the list. */ - QTAILQ_REMOVE(&cpus, cpu, node); - - cpu_list_unlock(); - - ts = cpu->opaque; - if (ts->child_tidptr) { - put_user_u32(0, ts->child_tidptr); - sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX, - NULL, NULL, 0); - } - thread_cpu = NULL; - object_unref(OBJECT(cpu)); - g_free(ts); - rcu_unregister_thread(); - pthread_exit(NULL); - } - - cpu_list_unlock(); -#ifdef TARGET_GPROF - _mcleanup(); +#if defined(TARGET_ABI_IRIX) && defined(__NR_exit_group) + /* IRIX terminates all threads if this is a pthread */ + if(((TaskState *)cpu->opaque)->is_pthread) + ret = get_errno(syscall(__NR_exit_group, arg1)); + else #endif - gdb_exit(cpu_env, arg1); - _exit(arg1); - ret = 0; /* avoid warning */ + ret = do_exit(cpu_env, arg1); break; case TARGET_NR_read: if (arg3 == 0) @@ -7941,6 +8380,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; #endif +#ifdef TARGET_NR_open64 + case TARGET_NR_open64: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(do_openat(cpu_env, AT_FDCWD, p, + target_to_host_bitmask(arg2 | TARGET_O_LARGEFILE, fcntl_flags_tbl), + arg3)); + fd_trans_unregister(ret); + unlock_user(p, arg1, 0); + break; +#endif +#ifdef TARGET_NR_openat case TARGET_NR_openat: if (!(p = lock_user_string(arg2))) goto efault; @@ -7950,6 +8401,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, fd_trans_unregister(ret); unlock_user(p, arg2, 0); break; +#endif +#ifdef TARGET_NR_openat64 + case TARGET_NR_openat64: + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(do_openat(cpu_env, arg1, p, + target_to_host_bitmask(arg3 | TARGET_O_LARGEFILE, fcntl_flags_tbl), + arg4)); + fd_trans_unregister(ret); + unlock_user(p, arg2, 0); +#endif #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) case TARGET_NR_name_to_handle_at: ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); @@ -7963,6 +8425,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_close: fd_trans_unregister(arg1); +#ifdef TARGET_ABI_IRIX + /* TODO: is there something special for closing a negative fd in IRIX? + * Some software does this, and it isn't working without waiting some. + * Maybe a scheduling issue? + */ + if (arg1 < 0) usleep(10000); +#endif ret = get_errno(close(arg1)); break; case TARGET_NR_brk: @@ -7970,7 +8439,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_fork case TARGET_NR_fork: - ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0)); + ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0, 0, 0)); break; #endif #ifdef TARGET_NR_waitpid @@ -7989,13 +8458,30 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { siginfo_t info; info.si_pid = 0; +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + /* TODO: this should go to something like target_to_host_waitopts */ + int opt = arg4; + switch (arg1) { + case TARGET_P_PID: arg1 = P_PID; break; + case TARGET_P_PGID: arg1 = P_PGID; break; + case TARGET_P_ALL: arg1 = P_ALL; break; + default: arg1 = P_ALL; break; + } + arg4 = 0; + if (opt & TARGET_WNOHANG) arg4 |= WNOHANG; + if (opt & TARGET_WSTOPPED) arg4 |= WSTOPPED; + if (opt & TARGET_WEXITED) arg4 |= WEXITED; + if (opt & TARGET_WCONTINUED) arg4 |= WCONTINUED; + if (opt & TARGET_WNOWAIT) arg4 |= WNOWAIT; +#endif + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0))) + goto efault; ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL)); if (!is_error(ret) && arg3 && info.si_pid != 0) { - if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0))) - goto efault; host_to_target_siginfo(p, &info); - unlock_user(p, arg3, sizeof(target_siginfo_t)); - } + } else + memset(p, 0, sizeof(target_siginfo_t)); + unlock_user(p, arg3, sizeof(target_siginfo_t)); } break; #endif @@ -8008,6 +8494,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; #endif +#ifdef TARGET_NR_creat64 + case TARGET_NR_creat64: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(open(p, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, arg2)); + fd_trans_unregister(ret); + unlock_user(p, arg1, 0); + break; +#endif #ifdef TARGET_NR_link case TARGET_NR_link: { @@ -8055,6 +8550,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(unlinkat(arg1, p, arg3)); unlock_user(p, arg2, 0); break; +#endif +#ifdef TARGET_NR_execv + case TARGET_NR_execv: + arg3 = 0; /* presumably unused. same as execve, but no environment */ #endif case TARGET_NR_execve: { @@ -8125,7 +8624,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, * before the execve completes and makes it the other * program's problem. */ - ret = get_errno(safe_execve(p, argp, envp)); + ret = get_errno(safe_execve(path(p), argp, envp)); unlock_user(p, arg1, 0); goto execve_end; @@ -8164,13 +8663,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { time_t host_time; ret = get_errno(time(&host_time)); +#ifndef TARGET_ABI_IRIX if (!is_error(ret) && arg1 && put_user_sal(host_time, arg1)) goto efault; +#endif } break; #endif +#ifdef TARGET_NR_xmknod + case TARGET_NR_xmknod: + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(mknod(p, arg3, arg4)); + unlock_user(p, arg2, 0); + break; +#endif #ifdef TARGET_NR_mknod case TARGET_NR_mknod: if (!(p = lock_user_string(arg1))) @@ -8206,6 +8715,41 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_lseek: ret = get_errno(lseek(arg1, arg2, arg3)); break; +#ifdef TARGET_NR_lseek64 + case TARGET_NR_lseek64: + { + int64_t off = arg2, res; +#if TARGET_ABI_BITS == 32 + if (regpairs_aligned(cpu_env, num)) { + off = target_offset64(arg3, arg4); + arg3 = arg5; + } else { + off = target_offset64(arg2, arg3); + arg3 = arg4; + } +#endif +#if !defined(__NR_llseek) + res = lseek(arg1, off, arg3); + if (res == -1) + ret = get_errno(res); + else + ret = 0; +#else + ret = get_errno(_llseek(arg1, (ulong)(off >> 32), (ulong)off, &res, arg3)); +#endif + if (ret < 0) { + res = ret; + } +#if defined(TARGET_ABI_IRIX) && TARGET_ABI_BITS == 32 + /* split the 64 bit return value */ + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = (abi_int) res; + ret = (abi_int) (res >> 32); +#else + ret = res; +#endif + } + break; +#endif #if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxpid: @@ -8215,6 +8759,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_getpid case TARGET_NR_getpid: +#ifdef TARGET_ABI_SOLARIS + ((CPUSPARCState*)cpu_env)->regwptr[1] = getppid(); +#endif +#ifdef TARGET_ABI_IRIX + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = getppid(); +#endif ret = get_errno(getpid()); break; #endif @@ -8291,8 +8841,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_ptrace case TARGET_NR_ptrace: goto unimplemented; +#endif #ifdef TARGET_NR_alarm /* not on alpha */ case TARGET_NR_alarm: ret = alarm(arg1); @@ -8304,7 +8856,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pause /* not on alpha */ case TARGET_NR_pause: - if (!block_signals()) { + if (!block_signals(cpu_env)) { sigsuspend(&((TaskState *)cpu->opaque)->signal_mask); } ret = -TARGET_EINTR; @@ -8318,8 +8870,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (arg2) { if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1)) goto efault; - tbuf.actime = tswapal(target_tbuf->actime); - tbuf.modtime = tswapal(target_tbuf->modtime); + __get_user(tbuf.actime, &target_tbuf->actime); + __get_user(tbuf.modtime, &target_tbuf->modtime); unlock_user_struct(target_tbuf, arg2, 0); host_tbuf = &tbuf; } else { @@ -8384,7 +8936,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_access: if (!(p = lock_user_string(arg1))) goto efault; - ret = get_errno(access(path(p), arg2)); +#if defined TARGET_E_OK + if (arg2 & TARGET_E_OK) + ret = get_errno(euidaccess(path(p), arg2 & ~TARGET_E_OK)); + else +#endif + ret = get_errno(access(path(p), arg2)); unlock_user(p, arg1, 0); break; #endif @@ -8513,10 +9070,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0); if (!tmsp) goto efault; - tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime)); - tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime)); - tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime)); - tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime)); + __put_user(host_to_target_clock_t(tms.tms_utime), &tmsp->tms_utime); + __put_user(host_to_target_clock_t(tms.tms_stime), &tmsp->tms_stime); + __put_user(host_to_target_clock_t(tms.tms_cutime), &tmsp->tms_cutime); + __put_user(host_to_target_clock_t(tms.tms_cstime), &tmsp->tms_cstime); } if (!is_error(ret)) ret = host_to_target_clock_t(ret); @@ -8557,6 +9114,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_fcntl case TARGET_NR_fcntl: +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN32) + /* for N32 map everything using struct flock to its 64 bit version */ + if (arg2 == TARGET_F_ALLOCSP) arg2 = TARGET_F_ALLOCSP64; + else if (arg2 == TARGET_F_FREESP) arg2 = TARGET_F_FREESP64; + else if (arg2 == TARGET_F_GETLK) arg2 = TARGET_F_GETLK64; + else if (arg2 == TARGET_F_SETLK) arg2 = TARGET_F_SETLK64; + else if (arg2 == TARGET_F_SETLKW) arg2 = TARGET_F_SETLKW64; +#endif ret = do_fcntl(arg1, arg2, arg3); break; #endif @@ -8564,12 +9129,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_mpx: goto unimplemented; #endif +#ifdef TARGET_NR_setpgid case TARGET_NR_setpgid: ret = get_errno(setpgid(arg1, arg2)); break; +#endif #ifdef TARGET_NR_ulimit case TARGET_NR_ulimit: - goto unimplemented; + if (arg1 != UL_SETFSIZE) + ret = get_errno(ulimit(arg1, arg2, arg3)); + else ret = -TARGET_EPERM; + break; #endif #ifdef TARGET_NR_oldolduname case TARGET_NR_oldolduname: @@ -8622,9 +9192,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getpgrp()); break; #endif +#ifdef TARGET_NR_setsid case TARGET_NR_setsid: ret = get_errno(setsid()); break; +#endif #ifdef TARGET_NR_sigaction case TARGET_NR_sigaction: { @@ -8641,7 +9213,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(old_act, arg2, 0); pact = &act; } - ret = get_errno(do_sigaction(arg1, pact, &oact)); + ret = get_errno(do_sigaction(cpu_env, arg1, pact, &oact)); if (!is_error(ret) && arg3) { if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) goto efault; @@ -8650,7 +9222,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, old_act->sa_flags = oact.sa_flags; unlock_user_struct(old_act, arg3, 1); } -#elif defined(TARGET_MIPS) +#elif defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) struct target_sigaction act, oact, *pact, *old_act; if (arg2) { @@ -8665,19 +9237,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, pact = NULL; } - ret = get_errno(do_sigaction(arg1, pact, &oact)); + ret = get_errno(do_sigaction(cpu_env, arg1, pact, &oact)); - if (!is_error(ret) && arg3) { +#ifdef TARGET_ABI_IRIX + /* IRIX libc hands down its signal trampoline, such that the kernel + * needn't bother with installing one for the different ABIs + */ + if (!is_error(ret)) + ((TaskState*)cpu->opaque)->sigtramp = arg4; +#endif + if (!is_error(ret) && arg3) { if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) goto efault; - old_act->_sa_handler = oact._sa_handler; - old_act->sa_flags = oact.sa_flags; - old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; - old_act->sa_mask.sig[1] = 0; - old_act->sa_mask.sig[2] = 0; - old_act->sa_mask.sig[3] = 0; - unlock_user_struct(old_act, arg3, 1); - } + old_act->_sa_handler = oact._sa_handler; + old_act->sa_flags = oact.sa_flags; + old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; + old_act->sa_mask.sig[1] = 0; + old_act->sa_mask.sig[2] = 0; + old_act->sa_mask.sig[3] = 0; + unlock_user_struct(old_act, arg3, 1); + } #else struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; @@ -8693,7 +9272,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { pact = NULL; } - ret = get_errno(do_sigaction(arg1, pact, &oact)); + ret = get_errno(do_sigaction(cpu_env, arg1, pact, &oact)); if (!is_error(ret) && arg3) { if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) goto efault; @@ -8707,6 +9286,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_rt_sigaction case TARGET_NR_rt_sigaction: { #if defined(TARGET_ALPHA) @@ -8735,7 +9315,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(rt_act, arg2, 0); pact = &act; } - ret = get_errno(do_sigaction(arg1, pact, &oact)); + ret = get_errno(do_sigaction(cpu_env, arg1, pact, &oact)); if (!is_error(ret) && arg3) { if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0)) goto efault; @@ -8775,7 +9355,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } else oact = NULL; - ret = get_errno(do_sigaction(arg1, act, oact)); + ret = get_errno(do_sigaction(cpu_env, arg1, act, oact)); rt_sigaction_fail: if (act) unlock_user_struct(act, arg2, 0); @@ -8784,12 +9364,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif } break; +#endif #ifdef TARGET_NR_sgetmask /* not on alpha */ case TARGET_NR_sgetmask: { sigset_t cur_set; abi_ulong target_set; - ret = do_sigprocmask(0, NULL, &cur_set); + ret = do_sigprocmask(cpu_env, 0, NULL, &cur_set); if (!ret) { host_to_target_old_sigset(&target_set, &cur_set); ret = target_set; @@ -8803,7 +9384,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set, oset; abi_ulong target_set = arg1; target_to_host_old_sigset(&set, &target_set); - ret = do_sigprocmask(SIG_SETMASK, &set, &oset); + ret = do_sigprocmask(cpu_env, SIG_SETMASK, &set, &oset); if (!ret) { host_to_target_old_sigset(&target_set, &oset); ret = target_set; @@ -8836,7 +9417,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, mask = arg2; target_to_host_old_sigset(&set, &mask); - ret = do_sigprocmask(how, &set, &oldset); + ret = do_sigprocmask(cpu_env, how, &set, &oldset); if (!is_error(ret)) { host_to_target_old_sigset(&mask, &oldset); ret = mask; @@ -8870,7 +9451,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, how = 0; set_ptr = NULL; } - ret = do_sigprocmask(how, set_ptr, &oldset); + ret = do_sigprocmask(cpu_env, how, set_ptr, &oldset); if (!is_error(ret) && arg3) { if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) goto efault; @@ -8881,6 +9462,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_rt_sigprocmask case TARGET_NR_rt_sigprocmask: { int how = arg1; @@ -8915,7 +9497,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, how = 0; set_ptr = NULL; } - ret = do_sigprocmask(how, set_ptr, &oldset); + ret = do_sigprocmask(cpu_env, how, set_ptr, &oldset); if (!is_error(ret) && arg3) { if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) goto efault; @@ -8924,6 +9506,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif #ifdef TARGET_NR_sigpending case TARGET_NR_sigpending: { @@ -8938,6 +9521,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_rt_sigpending case TARGET_NR_rt_sigpending: { sigset_t set; @@ -8961,6 +9545,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif #ifdef TARGET_NR_sigsuspend case TARGET_NR_sigsuspend: { @@ -8982,6 +9567,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_rt_sigsuspend case TARGET_NR_rt_sigsuspend: { TaskState *ts = cpu->opaque; @@ -9001,6 +9587,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#ifdef TARGET_NR_rt_sigtimedwait case TARGET_NR_rt_sigtimedwait: { sigset_t set; @@ -9038,6 +9626,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#ifdef TARGET_NR_rt_sigqueueinfo case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; @@ -9064,33 +9654,44 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo)); } break; +#endif #ifdef TARGET_NR_sigreturn case TARGET_NR_sigreturn: - if (block_signals()) { + if (block_signals(cpu_env)) { ret = -TARGET_ERESTARTSYS; } else { - ret = do_sigreturn(cpu_env); +#ifdef TARGET_ABI_IRIX + if (!((CPUMIPSState*)cpu_env)->active_tc.gpr[4]) + ret = do_rt_sigreturn(cpu_env); + else +#endif + ret = do_sigreturn(cpu_env); } break; #endif +#ifdef TARGET_NR_rt_sigreturn case TARGET_NR_rt_sigreturn: - if (block_signals()) { + if (block_signals(cpu_env)) { ret = -TARGET_ERESTARTSYS; } else { ret = do_rt_sigreturn(cpu_env); } break; +#endif +#ifdef TARGET_NR_sethostname case TARGET_NR_sethostname: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(sethostname(p, arg2)); unlock_user(p, arg1, 0); break; +#endif case TARGET_NR_setrlimit: { int resource = target_to_host_resource(arg1); struct target_rlimit *target_rlim; struct rlimit rlim; + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) goto efault; rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur); @@ -9099,6 +9700,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(setrlimit(resource, &rlim)); } break; +#ifdef TARGET_NR_setrlimit64 + case TARGET_NR_setrlimit64: + { + int resource = target_to_host_resource(arg1); + struct target_rlimit64 *target_rlim; + struct rlimit rlim; + + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) + goto efault; + rlim.rlim_cur = target_to_host_rlim64(target_rlim->rlim_cur); + rlim.rlim_max = target_to_host_rlim64(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 0); + ret = get_errno(setrlimit(resource, &rlim)); + } + break; +#endif case TARGET_NR_getrlimit: { int resource = target_to_host_resource(arg1); @@ -9115,6 +9732,25 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#ifdef TARGET_NR_getrlimit64 + case TARGET_NR_getrlimit64: + { + int resource = target_to_host_resource(arg1); + struct target_rlimit64 *target_rlim; + struct rlimit rlim; + + ret = get_errno(getrlimit(resource, &rlim)); + if (!is_error(ret)) { + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; + target_rlim->rlim_cur = host_to_target_rlim64(rlim.rlim_cur); + target_rlim->rlim_max = host_to_target_rlim64(rlim.rlim_max); + unlock_user_struct(target_rlim, arg2, 1); + } + } + break; +#endif +#ifdef TARGET_NR_getrusage case TARGET_NR_getrusage: { struct rusage rusage; @@ -9124,6 +9760,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#ifdef TARGET_NR_gettimeofday case TARGET_NR_gettimeofday: { struct timeval tv; @@ -9134,6 +9772,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#ifdef TARGET_NR_settimeofday case TARGET_NR_settimeofday: { struct timeval tv, *ptv = NULL; @@ -9156,6 +9796,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(settimeofday(ptv, ptz)); } break; +#endif #if defined(TARGET_NR_select) case TARGET_NR_select: #if defined(TARGET_WANT_NI_OLD_SELECT) @@ -9232,8 +9873,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!arg7) { goto efault; } - arg_sigset = tswapal(arg7[0]); - arg_sigsize = tswapal(arg7[1]); + __get_user(arg_sigset, &arg7[0]); + __get_user(arg_sigsize, &arg7[1]); unlock_user(arg7, arg6, 0); if (arg_sigset) { @@ -9373,6 +10014,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; #endif +#ifdef TARGET_NR_reboot case TARGET_NR_reboot: if (arg3 == LINUX_REBOOT_CMD_RESTART2) { /* arg4 must be ignored in all other cases */ @@ -9386,6 +10028,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(reboot(arg1, arg2, arg3, NULL)); } break; +#endif #ifdef TARGET_NR_readdir case TARGET_NR_readdir: goto unimplemented; @@ -9401,25 +10044,52 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_ulong v1, v2, v3, v4, v5, v6; if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1))) goto efault; - v1 = tswapal(v[0]); - v2 = tswapal(v[1]); - v3 = tswapal(v[2]); - v4 = tswapal(v[3]); - v5 = tswapal(v[4]); - v6 = tswapal(v[5]); + __get_user(v1, &v[0]); + __get_user(v2, &v[1]); + __get_user(v3, &v[2]); + __get_user(v4, &v[3]); + __get_user(v5, &v[4]); + __get_user(v6, &v[5]); unlock_user(v, arg1, 0); ret = get_errno(target_mmap(v1, v2, v3, target_to_host_bitmask(v4, mmap_flags_tbl), v5, v6)); } #else +#ifdef TARGET_ABI_IRIX + /* TODO: no MAP_AUTOGROW in linux. as a kludge resize the file */ + if ((arg4 & TARGET_MAP_AUTOGROW) && + arg5 >= 0 && fstat(arg5, &st) >= 0 && st.st_size < arg6+arg2) + ret = get_errno(ftruncate(arg5, arg6+arg2)); +#endif ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + arg5, arg6)); #endif break; #endif +#ifdef TARGET_NR_mmap64 + case TARGET_NR_mmap64: + { + off64_t off = arg6; +#if TARGET_ABI_BITS == 32 + if (regpairs_aligned(cpu_env, num)) + off = target_offset64(arg7, arg8); + else + off = target_offset64(arg6, arg7); +#endif +#ifdef TARGET_ABI_IRIX + /* TODO: no MAP_AUTOGROW in linux. as a kludge resize the file */ + if ((arg4 & TARGET_MAP_AUTOGROW) && + arg5 >= 0 && fstat(arg5, &st) >= 0 && st.st_size < off+arg2) + ret = get_errno(ftruncate64(arg5, off+arg2)); +#endif + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, off)); + } + break; +#endif #ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: #ifndef MMAP_SHIFT @@ -9479,15 +10149,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(munlockall()); break; #endif +#ifdef TARGET_NR_truncate case TARGET_NR_truncate: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(truncate(p, arg2)); unlock_user(p, arg1, 0); break; +#endif +#ifdef TARGET_NR_ftruncate case TARGET_NR_ftruncate: ret = get_errno(ftruncate(arg1, arg2)); break; +#endif case TARGET_NR_fchmod: ret = get_errno(fchmod(arg1, arg2)); break; @@ -9499,6 +10173,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg2, 0); break; #endif +#ifdef TARGET_NR_getpriority case TARGET_NR_getpriority: /* Note that negative values are valid for getpriority, so we must differentiate based on errno settings. */ @@ -9516,9 +10191,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = 20 - ret; #endif break; +#endif +#ifdef TARGET_NR_setpriority case TARGET_NR_setpriority: ret = get_errno(setpriority(arg1, arg2, arg3)); break; +#endif #ifdef TARGET_NR_profil case TARGET_NR_profil: goto unimplemented; @@ -9529,11 +10207,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs: +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN32) + goto convert_statfs64; +#else if (!is_error(ret)) { struct target_statfs *target_stfs; - +#ifdef TARGET_ABI_IRIX /* IRIX has a length and a fs type arg */ + struct target_statfs tmp_stfs; + if (arg3 > sizeof(tmp_stfs)) + arg3 = sizeof(tmp_stfs); + target_stfs = &tmp_stfs; +#else if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0)) goto efault; +#endif __put_user(stfs.f_type, &target_stfs->f_type); __put_user(stfs.f_bsize, &target_stfs->f_bsize); __put_user(stfs.f_blocks, &target_stfs->f_blocks); @@ -9546,8 +10233,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, __put_user(stfs.f_namelen, &target_stfs->f_namelen); __put_user(stfs.f_frsize, &target_stfs->f_frsize); memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare)); +#ifdef TARGET_ABI_IRIX + ret = copy_to_user(arg2, target_stfs, arg3); +#else unlock_user_struct(target_stfs, arg2, 1); +#endif } +#endif break; case TARGET_NR_fstatfs: ret = get_errno(fstatfs(arg1, &stfs)); @@ -9558,12 +10250,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); +#endif +#if defined(TARGET_NR_statfs64) || (defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN32)) convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; +#ifdef TARGET_ABI_IRIX /* IRIX has a length and a fs type arg */ + struct target_statfs64 tmp_stfs; + if (arg3 > sizeof(tmp_stfs)) + arg3 = sizeof(tmp_stfs); + target_stfs = &tmp_stfs; +#else if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0)) goto efault; +#endif __put_user(stfs.f_type, &target_stfs->f_type); __put_user(stfs.f_bsize, &target_stfs->f_bsize); __put_user(stfs.f_blocks, &target_stfs->f_blocks); @@ -9576,9 +10277,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, __put_user(stfs.f_namelen, &target_stfs->f_namelen); __put_user(stfs.f_frsize, &target_stfs->f_frsize); memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare)); +#ifdef TARGET_ABI_IRIX + ret = copy_to_user(arg2, target_stfs, arg3); +#else unlock_user_struct(target_stfs, arg3, 1); +#endif } break; +#endif +#ifdef TARGET_NR_fstatfs64 case TARGET_NR_fstatfs64: ret = get_errno(fstatfs(arg1, &stfs)); goto convert_statfs64; @@ -9587,6 +10294,74 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_ioperm: goto unimplemented; #endif +#ifdef TARGET_NR_fstatvfs + case TARGET_NR_fstatvfs: + ret = get_errno(fstatvfs(arg1, &stvfs)); + goto convert_statvfs; +#endif +#ifdef TARGET_NR_statvfs + case TARGET_NR_statvfs: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(statvfs(path(p), &stvfs)); + unlock_user(p, arg1, 0); + + convert_statvfs: + if (!is_error(ret)) { + { + struct target_statvfs *target_stvfs; + + if (!lock_user_struct(VERIFY_WRITE, target_stvfs, arg2, 0)) + goto efault; + __put_user(stvfs.f_bsize, &target_stvfs->f_bsize); + __put_user(stvfs.f_frsize, &target_stvfs->f_frsize); + __put_user(stvfs.f_blocks, &target_stvfs->f_blocks); + __put_user(stvfs.f_bfree, &target_stvfs->f_bfree); + __put_user(stvfs.f_bavail, &target_stvfs->f_bavail); + __put_user(stvfs.f_files, &target_stvfs->f_files); + __put_user(stvfs.f_ffree, &target_stvfs->f_ffree); + __put_user(stvfs.f_favail, &target_stvfs->f_favail); + __put_user(stvfs.f_fsid, &target_stvfs->f_fsid); + __put_user(stvfs.f_flag, &target_stvfs->f_flag); + __put_user(stvfs.f_namemax, &target_stvfs->f_namemax); + unlock_user_struct(target_stvfs, arg2, 1); + } + } + break; +#ifdef TARGET_NR_fstatvfs64 + case TARGET_NR_fstatvfs64: + ret = get_errno(fstatvfs(arg1, &stvfs)); + goto convert_statvfs64; +#endif +#ifdef TARGET_NR_statvfs64 + case TARGET_NR_statvfs64: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(statvfs(path(p), &stvfs)); + unlock_user(p, arg1, 0); + + convert_statvfs64: + if (!is_error(ret)) { + struct target_statvfs64 *target_stvfs; + + if (!lock_user_struct(VERIFY_WRITE, target_stvfs, arg2, 0)) + goto efault; + __put_user(stvfs.f_bsize, &target_stvfs->f_bsize); + __put_user(stvfs.f_frsize, &target_stvfs->f_frsize); + __put_user(stvfs.f_blocks, &target_stvfs->f_blocks); + __put_user(stvfs.f_bfree, &target_stvfs->f_bfree); + __put_user(stvfs.f_bavail, &target_stvfs->f_bavail); + __put_user(stvfs.f_files, &target_stvfs->f_files); + __put_user(stvfs.f_ffree, &target_stvfs->f_ffree); + __put_user(stvfs.f_favail, &target_stvfs->f_favail); + __put_user(stvfs.f_fsid, &target_stvfs->f_fsid); + __put_user(stvfs.f_flag, &target_stvfs->f_flag); + __put_user(stvfs.f_namemax, &target_stvfs->f_namemax); + unlock_user_struct(target_stvfs, arg2, 1); + } + break; +#endif +#endif #ifdef TARGET_NR_socketcall case TARGET_NR_socketcall: ret = do_socketcall(arg1, arg2); @@ -9783,6 +10558,51 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#ifdef TARGET_NR_xstat + case TARGET_NR_xstat: + if (!(p = lock_user_string(arg2))) + goto efault; +#ifdef TARGET_ABI_IRIX + /* TODO: IRIX creates a virtual semaphore file, and libc checks it with + * xstat :-( As a kludge, check here for a named semaphore and return + * fake stat information. */ + ret = psema_get_index(p, NULL, 0); + if (ret >= 0) { + memset(&st, 0, sizeof(st)); + st.st_ino = ret; /* generate fake stat info for a semaphore */ + } else +#endif + ret = get_errno(stat(path(p), &st)); + unlock_user(p, arg2, 0); + goto do_xstat; +#endif +#ifdef TARGET_NR_lxstat + case TARGET_NR_lxstat: + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(lstat(path(p), &st)); + unlock_user(p, arg2, 0); + goto do_xstat; +#endif +#ifdef TARGET_NR_fxstat + case TARGET_NR_fxstat: + ret = get_errno(fstat(arg2, &st)); + goto do_xstat; +#endif +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + do_xstat: +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN32) + arg1 = TARGET_STAT64_VER; +#endif +#if defined(TARGET_ABI_IRIX) && TARGET_ABI_BITS == 32 + if (!is_error(ret) && arg1 == TARGET_STAT64_VER) { + ret = host_to_target_stat64(cpu_env, arg3, &st); + break; + } +#endif + arg2 = arg3; + goto do_stat; +#endif #ifdef TARGET_NR_stat case TARGET_NR_stat: if (!(p = lock_user_string(arg1))) @@ -9799,35 +10619,24 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); goto do_stat; #endif +#ifdef TARGET_NR_fstat case TARGET_NR_fstat: - { - ret = get_errno(fstat(arg1, &st)); -#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat) - do_stat: + ret = get_errno(fstat(arg1, &st)); + goto do_stat; #endif - if (!is_error(ret)) { - struct target_stat *target_st; - - if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) - goto efault; - memset(target_st, 0, sizeof(*target_st)); - __put_user(st.st_dev, &target_st->st_dev); - __put_user(st.st_ino, &target_st->st_ino); - __put_user(st.st_mode, &target_st->st_mode); - __put_user(st.st_uid, &target_st->st_uid); - __put_user(st.st_gid, &target_st->st_gid); - __put_user(st.st_nlink, &target_st->st_nlink); - __put_user(st.st_rdev, &target_st->st_rdev); - __put_user(st.st_size, &target_st->st_size); - __put_user(st.st_blksize, &target_st->st_blksize); - __put_user(st.st_blocks, &target_st->st_blocks); - __put_user(st.st_atime, &target_st->target_st_atime); - __put_user(st.st_mtime, &target_st->target_st_mtime); - __put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 1); - } + do_stat: + if (!is_error(ret)) { + ret = host_to_target_stat(cpu_env, arg2, &st); } break; +#ifdef TARGET_NR_fstatat + case TARGET_NR_fstatat: + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(fstatat(arg1, path(p), &st, arg4)); + unlock_user(p, arg2, 0); + goto do_stat; +#endif #ifdef TARGET_NR_olduname case TARGET_NR_olduname: goto unimplemented; @@ -9849,6 +10658,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, arg6, arg7, arg8, 0); break; #endif +#ifdef TARGET_NR_wait4 case TARGET_NR_wait4: { int status; @@ -9876,6 +10686,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif #ifdef TARGET_NR_swapoff case TARGET_NR_swapoff: if (!(p = lock_user_string(arg1))) @@ -9884,6 +10695,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; #endif +#ifdef TARGET_NR_sysinfo case TARGET_NR_sysinfo: { struct target_sysinfo *target_value; @@ -9911,6 +10723,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif #ifdef TARGET_NR_ipc case TARGET_NR_ipc: ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); @@ -9971,9 +10784,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_shmdt(arg1); break; #endif +#ifdef TARGET_NR_fsync case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; +#endif +#ifdef TARGET_NR_clone case TARGET_NR_clone: /* Linux manages to have three different orderings for its * arguments to clone(); the BACKWARDS and BACKWARDS2 defines @@ -9982,16 +10798,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, * implicit argument to clone for the TLS pointer. */ #if defined(TARGET_MICROBLAZE) - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5)); + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5, 0, 0)); #elif defined(TARGET_CLONE_BACKWARDS) - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5, 0, 0)); #elif defined(TARGET_CLONE_BACKWARDS2) - ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); + ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4, 0, 0)); #else - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4, 0, 0)); #endif break; -#ifdef __NR_exit_group +#endif +#if defined __NR_exit_group && defined TARGET_NR_exit_group /* new thread calls */ case TARGET_NR_exit_group: #ifdef TARGET_GPROF @@ -10001,12 +10818,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(exit_group(arg1)); break; #endif +#ifdef TARGET_NR_setdomainname case TARGET_NR_setdomainname: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(setdomainname(p, arg2)); unlock_user(p, arg1, 0); break; +#endif +#ifdef TARGET_NR_uname case TARGET_NR_uname: /* no need to transcode because we use the linux syscall */ { @@ -10028,6 +10848,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(buf, arg1, 1); } break; +#endif #ifdef TARGET_I386 case TARGET_NR_modify_ldt: ret = do_modify_ldt(cpu_env, arg1, arg2, arg3); @@ -10040,6 +10861,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif #endif +#ifdef TARGET_NR_adjtimex case TARGET_NR_adjtimex: { struct timex host_buf; @@ -10055,6 +10877,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif #if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME) case TARGET_NR_clock_adjtime: { @@ -10074,18 +10897,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_create_module case TARGET_NR_create_module: -#endif case TARGET_NR_init_module: case TARGET_NR_delete_module: + goto unimplemented; +#endif #ifdef TARGET_NR_get_kernel_syms case TARGET_NR_get_kernel_syms: -#endif goto unimplemented; +#endif +#ifdef TARGET_NR_quotactl case TARGET_NR_quotactl: goto unimplemented; +#endif +#ifdef TARGET_NR_getpgid case TARGET_NR_getpgid: ret = get_errno(getpgid(arg1)); break; +#endif case TARGET_NR_fchdir: ret = get_errno(fchdir(arg1)); break; @@ -10097,9 +10925,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sysfs: goto unimplemented; #endif +#ifdef TARGET_NR_personality case TARGET_NR_personality: ret = get_errno(personality(arg1)); break; +#endif #ifdef TARGET_NR_afs_syscall case TARGET_NR_afs_syscall: goto unimplemented; @@ -10108,26 +10938,36 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR__llseek: { int64_t res; +#ifdef TARGET_ABI_SOLARIS + int whence = arg4; /* no "loff_t *result" on Solaris */ +#else + int whence = arg5; +#endif #if !defined(__NR_llseek) - res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5); + /* llseek has 2 args for offset, so no target_offset64 here */ + res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, whence); if (res == -1) { ret = get_errno(res); } else { ret = 0; } #else - ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); + ret = get_errno(_llseek(arg1, arg2, arg3, &res, whence)); #endif +#ifndef TARGET_ABI_SOLARIS if ((ret == 0) && put_user_s64(res, arg4)) { goto efault; } +#endif } break; #endif +#ifdef TARGET_NR_ngetdents + case TARGET_NR_ngetdents: +#endif #ifdef TARGET_NR_getdents case TARGET_NR_getdents: #ifdef __NR_getdents -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 { struct target_dirent *target_dirp; struct linux_dirent *dirp; @@ -10155,12 +10995,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, while (len > 0) { reclen = de->d_reclen; tnamelen = reclen - offsetof(struct linux_dirent, d_name); + tnamelen = strnlen(de->d_name, tnamelen) + 1; assert(tnamelen >= 0); treclen = tnamelen + offsetof(struct target_dirent, d_name); - assert(count1 + treclen <= count); - tde->d_reclen = tswap16(treclen); - tde->d_ino = tswapal(de->d_ino); - tde->d_off = tswapal(de->d_off); + /* XXX: avoid buffer overflow, for the price of lost entries */ + if (count1 + treclen > count) + break; + __put_user(treclen, &tde->d_reclen); + __put_user(de->d_ino, &tde->d_ino); + __put_user(de->d_off, &tde->d_off); memcpy(tde->d_name, de->d_name, tnamelen); de = (struct linux_dirent *)((char *)de + reclen); len -= reclen; @@ -10172,33 +11015,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } g_free(dirp); } -#else - { - struct linux_dirent *dirp; - abi_long count = arg3; - - if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) - goto efault; - ret = get_errno(sys_getdents(arg1, dirp, count)); - if (!is_error(ret)) { - struct linux_dirent *de; - int len = ret; - int reclen; - de = dirp; - while (len > 0) { - reclen = de->d_reclen; - if (reclen > len) - break; - de->d_reclen = tswap16(reclen); - tswapls(&de->d_ino); - tswapls(&de->d_off); - de = (struct linux_dirent *)((char *)de + reclen); - len -= reclen; - } - } - unlock_user(dirp, arg2, ret); - } -#endif #else /* Implement getdents in terms of getdents64 */ { @@ -10230,20 +11046,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int64_t off = de->d_off; uint8_t type = de->d_type; - namelen = strlen(de->d_name); + namelen = de->d_reclen - offsetof(struct linux_dirent64, d_name); + namelen = strnlen(de->d_name, namelen); treclen = offsetof(struct target_dirent, d_name) + namelen + 2; treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long)); memmove(tde->d_name, de->d_name, namelen + 1); - tde->d_ino = tswapal(ino); - tde->d_off = tswapal(off); - tde->d_reclen = tswap16(treclen); + __put_user(ino, &tde->d_ino); + __put_user(off, &tde->d_off); + __put_user(treclen, &tde->d_reclen); +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS /* The target_dirent type is in what was formerly a padding * byte at the end of the structure: */ *(((char *)tde) + treclen - 1) = type; - +#endif de = (struct linux_dirent64 *)((char *)de + reclen); tde = (struct target_dirent *)((char *)tde + treclen); len -= reclen; @@ -10253,11 +11071,71 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } unlock_user(dirp, arg2, ret); } +#endif +#ifdef TARGET_NR_ngetdents + if (ret >= 0 && num == TARGET_NR_ngetdents) { + abi_long *p = lock_user(VERIFY_WRITE, arg4, sizeof(abi_long), 0); + __put_user(ret == 0, &p); + unlock_user(p, arg4, 0); + } #endif break; #endif /* TARGET_NR_getdents */ +#ifdef TARGET_NR_ngetdents64 + case TARGET_NR_ngetdents64: +#endif #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) case TARGET_NR_getdents64: +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + { + struct target_dirent64 *target_dirp; + struct linux_dirent64 *dirp; + abi_long count = arg3; + + dirp = malloc(count); + if (!dirp) { + ret = -TARGET_ENOMEM; + goto fail; + } + + ret = get_errno(sys_getdents64(arg1, dirp, count)); + if (!is_error(ret)) { + struct linux_dirent64 *de; + struct target_dirent64 *tde; + int len = ret; + int reclen, treclen; + int count1, tnamelen; + + count1 = 0; + de = dirp; + if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; + tde = target_dirp; + while (len > 0) { + reclen = de->d_reclen; + tnamelen = reclen - offsetof(struct linux_dirent64, d_name); + tnamelen = strnlen(de->d_name, tnamelen) + 1; + assert(tnamelen > 0); + treclen = tnamelen + offsetof(struct target_dirent64, d_name); + treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_llong)); + /* XXX: avoid buffer overflow, for the price of lost entries */ + if (count1 + treclen > count) + break; + __put_user(treclen, &tde->d_reclen); + __put_user(de->d_ino, &tde->d_ino); + __put_user(de->d_off, &tde->d_off); + memcpy(tde->d_name, de->d_name, tnamelen); + de = (struct linux_dirent64 *)((char *)de + reclen); + len -= reclen; + tde = (struct target_dirent64 *)((char *)tde + treclen); + count1 += treclen; + } + ret = count1; + unlock_user(target_dirp, arg2, ret); + } + free(dirp); + } +#else { struct linux_dirent64 *dirp; abi_long count = arg3; @@ -10273,7 +11151,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, reclen = de->d_reclen; if (reclen > len) break; - de->d_reclen = tswap16(reclen); + __put_user(reclen, &de->d_reclen); tswap64s((uint64_t *)&de->d_ino); tswap64s((uint64_t *)&de->d_off); de = (struct linux_dirent64 *)((char *)de + reclen); @@ -10282,6 +11160,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } unlock_user(dirp, arg2, ret); } +#endif +#ifdef TARGET_NR_ngetdents64 + if (ret >= 0 && num == TARGET_NR_ngetdents64) { + abi_long *p = lock_user(VERIFY_WRITE, arg4, sizeof(abi_long), 0); + __put_user(ret == 0, &p); + unlock_user(p, arg4, 0); + } +#endif break; #endif /* TARGET_NR_getdents64 */ #if defined(TARGET_NR__newselect) @@ -10318,8 +11204,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, pfd = alloca(sizeof(struct pollfd) * nfds); for (i = 0; i < nfds; i++) { - pfd[i].fd = tswap32(target_pfd[i].fd); - pfd[i].events = tswap16(target_pfd[i].events); + __get_user(pfd[i].fd, &target_pfd[i].fd); + __get_user(pfd[i].events, &target_pfd[i].events); } } @@ -10393,18 +11279,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { for(i = 0; i < nfds; i++) { - target_pfd[i].revents = tswap16(pfd[i].revents); + __put_user(pfd[i].revents, &target_pfd[i].revents); } } unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds); } break; #endif +#ifdef TARGET_NR_flock case TARGET_NR_flock: /* NOTE: the flock constant seems to be the same for every Linux platform */ ret = get_errno(safe_flock(arg1, arg2)); break; +#endif case TARGET_NR_readv: { struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); @@ -10453,10 +11341,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_getsid case TARGET_NR_getsid: ret = get_errno(getsid(arg1)); break; -#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */ +#endif +#ifdef TARGET_NR_fdatasync /* Not on alpha (osf_datasync ?) */ case TARGET_NR_fdatasync: ret = get_errno(fdatasync(arg1)); break; @@ -10468,6 +11358,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_ENOTDIR; break; #endif +#ifdef TARGET_NR_sched_getaffinity case TARGET_NR_sched_getaffinity: { unsigned int mask_size; @@ -10534,6 +11425,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask)); } break; +#endif +#ifdef TARGET_NR_getcpu case TARGET_NR_getcpu: { unsigned cpu, node; @@ -10551,6 +11444,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#ifdef TARGET_NR_sched_setparam case TARGET_NR_sched_setparam: { struct sched_param *target_schp; @@ -10561,7 +11456,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) goto efault; - schp.sched_priority = tswap32(target_schp->sched_priority); + __get_user(schp.sched_priority, &target_schp->sched_priority); unlock_user_struct(target_schp, arg2, 0); ret = get_errno(sched_setparam(arg1, &schp)); } @@ -10578,7 +11473,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) goto efault; - target_schp->sched_priority = tswap32(schp.sched_priority); + __put_user(schp.sched_priority, &target_schp->sched_priority); unlock_user_struct(target_schp, arg2, 1); } } @@ -10592,7 +11487,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) goto efault; - schp.sched_priority = tswap32(target_schp->sched_priority); + __get_user(schp.sched_priority, &target_schp->sched_priority); unlock_user_struct(target_schp, arg3, 0); ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); } @@ -10603,12 +11498,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sched_yield: ret = get_errno(sched_yield()); break; +#ifdef TARGET_NR_sched_get_priority_max case TARGET_NR_sched_get_priority_max: ret = get_errno(sched_get_priority_max(arg1)); break; case TARGET_NR_sched_get_priority_min: ret = get_errno(sched_get_priority_min(arg1)); break; +#endif case TARGET_NR_sched_rr_get_interval: { struct timespec ts; @@ -10618,6 +11515,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif case TARGET_NR_nanosleep: { struct timespec req, rem; @@ -10636,6 +11534,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_nfsservctl: goto unimplemented; #endif +#ifdef TARGET_NR_prctl case TARGET_NR_prctl: switch (arg1) { case PR_GET_PDEATHSIG: @@ -10684,6 +11583,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; } break; +#endif #ifdef TARGET_NR_arch_prctl case TARGET_NR_arch_prctl: #if defined(TARGET_I386) && !defined(TARGET_ABI32) @@ -10695,32 +11595,59 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pread64 case TARGET_NR_pread64: - if (regpairs_aligned(cpu_env, num)) { - arg4 = arg5; - arg5 = arg6; + { + int64_t off = arg4; + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; +#if TARGET_ABI_BITS == 32 + if (regpairs_aligned(cpu_env, num)) + off = target_offset64(arg5, arg6); + else + off = target_offset64(arg4, arg5); +#endif + ret = get_errno(pread64(arg1, p, arg3, off)); + unlock_user(p, arg2, ret); } - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - goto efault; - ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); - unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite64: - if (regpairs_aligned(cpu_env, num)) { - arg4 = arg5; - arg5 = arg6; + { + int64_t off = arg4; + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; +#if TARGET_ABI_BITS == 32 + if (regpairs_aligned(cpu_env, num)) + off = target_offset64(arg5, arg6); + else + off = target_offset64(arg4, arg5); +#endif + ret = get_errno(pwrite64(arg1, p, arg3, off)); + unlock_user(p, arg2, 0); } + break; +#endif +#ifdef TARGET_NR_pread + case TARGET_NR_pread: + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + ret = get_errno(pread(arg1, p, arg3, arg4)); + unlock_user(p, arg2, ret); + break; + case TARGET_NR_pwrite: if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; - ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); + ret = get_errno(pwrite64(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif +#ifdef TARGET_NR_getcwd case TARGET_NR_getcwd: if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) goto efault; ret = get_errno(sys_getcwd1(p, arg2)); unlock_user(p, arg1, ret); break; +#endif +#ifdef TARGET_NR_capget case TARGET_NR_capget: case TARGET_NR_capset: { @@ -10735,8 +11662,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) { goto efault; } - header.version = tswap32(target_header->version); - header.pid = tswap32(target_header->pid); + __get_user(header.version, &target_header->version); + __get_user(header.pid, &target_header->pid); if (header.version != _LINUX_CAPABILITY_VERSION) { /* Version 2 and up takes pointer to two user_data structs */ @@ -10758,9 +11685,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (num == TARGET_NR_capset) { for (i = 0; i < data_items; i++) { - data[i].effective = tswap32(target_data[i].effective); - data[i].permitted = tswap32(target_data[i].permitted); - data[i].inheritable = tswap32(target_data[i].inheritable); + __get_user(data[i].effective, &target_data[i].effective); + __get_user(data[i].permitted, &target_data[i].permitted); + __get_user(data[i].inheritable, &target_data[i].inheritable); } } @@ -10774,15 +11701,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } /* The kernel always updates version for both capget and capset */ - target_header->version = tswap32(header.version); + __put_user(header.version, &target_header->version); unlock_user_struct(target_header, arg1, 1); if (arg2) { if (num == TARGET_NR_capget) { for (i = 0; i < data_items; i++) { - target_data[i].effective = tswap32(data[i].effective); - target_data[i].permitted = tswap32(data[i].permitted); - target_data[i].inheritable = tswap32(data[i].inheritable); + __put_user(data[i].effective, &target_data[i].effective); + __put_user(data[i].permitted, &target_data[i].permitted); + __put_user(data[i].inheritable, &target_data[i].inheritable); } unlock_user(target_data, arg2, target_datalen); } else { @@ -10791,11 +11718,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; } +#endif case TARGET_NR_sigaltstack: - ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env)); + ret = do_sigaltstack(cpu_env, arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env)); break; #ifdef CONFIG_SENDFILE +#ifdef TARGET_NR_sendfile case TARGET_NR_sendfile: { off_t *offp = NULL; @@ -10816,6 +11745,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; } +#endif #ifdef TARGET_NR_sendfile64 case TARGET_NR_sendfile64: { @@ -10858,7 +11788,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_vfork: ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD, - 0, 0, 0, 0)); + 0, 0, 0, 0, 0, 0)); break; #endif #ifdef TARGET_NR_ugetrlimit @@ -10942,11 +11872,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_getuid case TARGET_NR_getuid: +#ifdef TARGET_ABI_SOLARIS + ((CPUSPARCState*)cpu_env)->regwptr[1] = high2lowuid(geteuid()); +#endif +#ifdef TARGET_ABI_IRIX + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = high2lowuid(geteuid()); +#endif ret = get_errno(high2lowuid(getuid())); break; #endif #ifdef TARGET_NR_getgid case TARGET_NR_getgid: +#ifdef TARGET_ABI_SOLARIS + ((CPUSPARCState*)cpu_env)->regwptr[1] = high2lowuid(getegid()); +#endif +#ifdef TARGET_ABI_IRIX + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = high2lowuid(getegid()); +#endif ret = get_errno(high2lowgid(getgid())); break; #endif @@ -10966,6 +11908,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_setregid: ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); break; +#ifdef TARGET_NR_getgroups case TARGET_NR_getgroups: { int gidsetsize = arg1; @@ -11008,6 +11951,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(setgroups(gidsetsize, grouplist)); } break; +#endif case TARGET_NR_fchown: ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); break; @@ -11071,18 +12015,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_setuid: - ret = get_errno(sys_setuid(low2highuid(arg1))); + ret = get_errno(setuid(low2highuid(arg1))); break; case TARGET_NR_setgid: - ret = get_errno(sys_setgid(low2highgid(arg1))); + ret = get_errno(setgid(low2highgid(arg1))); break; +#ifdef TARGET_NR_seteuid + case TARGET_NR_seteuid: + ret = get_errno(seteuid(low2highuid(arg1))); + break; + case TARGET_NR_setegid: + ret = get_errno(setegid(low2highgid(arg1))); + break; +#endif +#ifdef TARGET_NR_setfsuid case TARGET_NR_setfsuid: ret = get_errno(setfsuid(arg1)); break; case TARGET_NR_setfsgid: ret = get_errno(setfsgid(arg1)); break; - +#endif #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: if (!(p = lock_user_string(arg1))) @@ -11228,7 +12181,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (si_code != 0) { target_siginfo_t info; - info.si_signo = SIGFPE; + info.si_signo = TARGET_SIGFPE; info.si_errno = 0; info.si_code = si_code; info._sifields._sigfault._addr @@ -11272,7 +12225,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } mask = arg2; target_to_host_old_sigset(&set, &mask); - ret = do_sigprocmask(how, &set, &oldset); + ret = do_sigprocmask(cpu_env, how, &set, &oldset); if (!ret) { host_to_target_old_sigset(&mask, &oldset); ret = mask; @@ -11280,7 +12233,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif - #ifdef TARGET_NR_getgid32 case TARGET_NR_getgid32: ret = get_errno(getgid()); @@ -11325,7 +12277,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto fail; } for(i = 0;i < ret; i++) - target_grouplist[i] = tswap32(grouplist[i]); + __put_user(grouplist[i], &target_grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 4); } } @@ -11346,7 +12298,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto fail; } for(i = 0;i < gidsetsize; i++) - grouplist[i] = tswap32(target_grouplist[i]); + __get_user(grouplist[i], &target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); ret = get_errno(setgroups(gidsetsize, grouplist)); } @@ -11423,9 +12375,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(setfsgid(arg1)); break; #endif - +#ifdef TARGET_NR_pivot_root case TARGET_NR_pivot_root: goto unimplemented; +#endif #ifdef TARGET_NR_mincore case TARGET_NR_mincore: { @@ -11538,7 +12491,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(0); break; #endif -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && defined TARGET_NR_fcntl64 case TARGET_NR_fcntl64: { int cmd; @@ -11601,18 +12554,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = TARGET_PAGE_SIZE; break; #endif +#ifdef TARGET_NR_gettid case TARGET_NR_gettid: ret = get_errno(gettid()); break; +#endif #ifdef TARGET_NR_readahead case TARGET_NR_readahead: #if TARGET_ABI_BITS == 32 - if (regpairs_aligned(cpu_env, num)) { - arg2 = arg3; - arg3 = arg4; - arg4 = arg5; - } - ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4)); + if (regpairs_aligned(cpu_env, num)) + ret = get_errno(readahead(arg1, target_offset64(arg3, arg4), arg5)); + else + ret = get_errno(readahead(arg1, target_offset64(arg2, arg3), arg4)); #else ret = get_errno(readahead(arg1, arg2, arg3)); #endif @@ -11831,7 +12784,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_getdomainname case TARGET_NR_getdomainname: - goto unimplemented_nowarn; + if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) + goto efault; + ret = get_errno(getdomainname(p, arg2)); + unlock_user(p, arg1, arg2); + break; #endif #ifdef TARGET_NR_clock_gettime @@ -11882,15 +12839,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(set_tid_address((int *)g2h(arg1))); break; #endif - +#if defined(TARGET_NR_tkill) && defined(__NR_tkill) case TARGET_NR_tkill: ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2))); break; +#endif +#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) case TARGET_NR_tgkill: ret = get_errno(safe_tgkill((int)arg1, (int)arg2, target_to_host_signal(arg3))); break; +#endif #ifdef TARGET_NR_set_robust_list case TARGET_NR_set_robust_list: @@ -11934,9 +12894,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_futex case TARGET_NR_futex: ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6); break; +#endif #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init) case TARGET_NR_inotify_init: ret = get_errno(sys_inotify_init()); @@ -12155,13 +13117,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_sync_file_range) case TARGET_NR_sync_file_range: #if TARGET_ABI_BITS == 32 -#if defined(TARGET_MIPS) - ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), - target_offset64(arg5, arg6), arg7)); -#else - ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3), - target_offset64(arg4, arg5), arg6)); -#endif /* !TARGET_MIPS */ + if (regpairs_aligned(cpu_env, num)) + ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), + target_offset64(arg5, arg6), arg7)); + else + ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3), + target_offset64(arg4, arg5), arg6)); #else ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4)); #endif @@ -12210,12 +13171,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) { goto efault; } - ep.events = tswap32(target_ep->events); + __get_user(ep.events, &target_ep->events); /* The epoll_data_t union is just opaque data to the kernel, * so we transfer all 64 bits across and need not worry what * actual data type it is. */ - ep.data.u64 = tswap64(target_ep->data.u64); + __get_user(ep.data.u64, &target_ep->data.u64); unlock_user_struct(target_ep, arg4, 0); epp = &ep; } @@ -12298,8 +13259,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { int i; for (i = 0; i < ret; i++) { - target_ep[i].events = tswap32(ep[i].events); - target_ep[i].data.u64 = tswap64(ep[i].data.u64); + __put_user(ep[i].events, &target_ep[i].events); + __put_user(ep[i].data.u64, &target_ep[i].data.u64); } unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event)); @@ -12322,8 +13283,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) { goto efault; } - rnew.rlim_cur = tswap64(target_rnew->rlim_cur); - rnew.rlim_max = tswap64(target_rnew->rlim_max); + __get_user(rnew.rlim_cur, &target_rnew->rlim_cur); + __get_user(rnew.rlim_max, &target_rnew->rlim_max); unlock_user_struct(target_rnew, arg3, 0); rnewp = &rnew; } @@ -12333,8 +13294,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) { goto efault; } - target_rold->rlim_cur = tswap64(rold.rlim_cur); - target_rold->rlim_max = tswap64(rold.rlim_max); + __put_user(rold.rlim_cur, &target_rold->rlim_cur); + __put_user(rold.rlim_max, &target_rold->rlim_max); unlock_user_struct(target_rold, arg4, 1); } break; @@ -12360,7 +13321,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_ulong mem_value; if (get_user_u32(mem_value, arg6)) { target_siginfo_t info; - info.si_signo = SIGSEGV; + info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = arg6; @@ -12576,11 +13537,1209 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5)); break; #endif +#ifdef TARGET_NR_gethostid + case TARGET_NR_gethostid: + ret = get_errno(gethostid()); + break; + case TARGET_NR_sethostid: + ret = get_errno(sethostid(arg1)); + break; +#endif +/* SVR4 specific system calls */ +#if defined TARGET_NR_getcontext + case TARGET_NR_getcontext: + { + struct target_ucontext *target_uc; + TaskState *ts = cpu->opaque; + + if (!lock_user_struct(VERIFY_WRITE, target_uc, arg1, 1)) { + goto efault; + } + save_context(cpu_env, &target_uc->tuc_mcontext, 1); + __put_user( ts->ctx_link, (uint32_t *)&target_uc->tuc_link ); + __put_user( 0xc, &target_uc->tuc_flags ); + unlock_user_struct(target_uc, arg1, 1); + ret = 0; + break; + } + case TARGET_NR_setcontext: + { + struct target_ucontext *target_uc; + TaskState *ts = cpu->opaque; + target_sigset_t target_set; + sigset_t set; + int flags, i; + + if (!lock_user_struct(VERIFY_READ, target_uc, arg1, 1)) { + goto efault; + } + restore_context(cpu_env, &target_uc->tuc_mcontext); + __get_user( flags, &target_uc->tuc_flags ); + if (flags & 1) { + for (i = 0; i < TARGET_NSIG_WORDS; i++) + __get_user(target_set.sig[i], &target_uc->tuc_sigmask.sig[i]); + target_to_host_sigset(&set, &target_set); + do_sigprocmask(cpu_env, SIG_SETMASK, &set, NULL); + } + __get_user( ts->ctx_link, (uint32_t *)&target_uc->tuc_link ); + unlock_user_struct(target_uc, arg1, 0); + ret = -TARGET_QEMU_ESIGRETURN; + break; + } +#endif +#ifdef TARGET_NR_msgsys + case TARGET_NR_msgsys: { + abi_ulong flags = 0; + switch (arg1) { + case TARGET_NR_msgsys_msgget: + flags |= arg3 & 0777; + if (arg3 & TARGET_IPC_CREAT) flags |= IPC_CREAT; + if (arg3 & TARGET_IPC_EXCL) flags |= IPC_EXCL; + ret = get_errno(msgget(arg2, flags)); + break; + case TARGET_NR_msgsys_msgctl: + switch (arg3) { + case TARGET_IPC_RMID: arg3 = IPC_RMID; break; + /* TODO: IPC_STAT, IPC_SET - structure different */ + } + ret = do_msgctl(arg2, arg3, arg4); + break; + case TARGET_NR_msgsys_msgrcv: + if (arg6 & TARGET_IPC_NOWAIT) flags |= IPC_NOWAIT; + if (arg6 & TARGET_MSG_NOERROR) flags |= MSG_NOERROR; + ret = do_msgrcv(arg2, arg3, arg4, arg5, flags); + break; + case TARGET_NR_msgsys_msgsnd: + if (arg5 & TARGET_IPC_NOWAIT) flags |= IPC_NOWAIT; + if (arg5 & TARGET_MSG_NOERROR) flags |= MSG_NOERROR; + ret = do_msgsnd(arg2, arg3, arg4, flags); + break; + default: + ret = -TARGET_EINVAL; + } + break; + } +#endif +#ifdef TARGET_NR_shmsys + case TARGET_NR_shmsys: { + abi_ulong flags = 0; + switch (arg1) { + case TARGET_NR_shmsys_shmat: + if (arg4 & TARGET_SHM_RDONLY) flags |= SHM_RDONLY; + if (arg4 & TARGET_SHM_RND) flags |= SHM_RND; + ret = do_shmat(cpu_env, arg2, arg3, flags); + break; + case TARGET_NR_shmsys_shmctl: + switch (arg3) { + case TARGET_SHM_LOCK: arg3 = SHM_LOCK; break; + case TARGET_SHM_UNLOCK: arg3 = SHM_UNLOCK; break; + case TARGET_IPC_RMID: arg3 = IPC_RMID; break; + /* TODO: IPC_STAT, IPC_SET - structure different */ + } + ret = do_shmctl(arg2, arg3, arg4); + break; + case TARGET_NR_shmsys_shmdt: + ret = do_shmdt(arg2); + break; + case TARGET_NR_shmsys_shmget: + flags |= arg4 & 0777; + if (arg4 & TARGET_IPC_CREAT) flags |= IPC_CREAT; + if (arg4 & TARGET_IPC_EXCL) flags |= IPC_EXCL; + ret = get_errno(shmget(arg2, arg3, flags)); + break; + default: + ret = -TARGET_EINVAL; + } + break; + } +#endif +#ifdef TARGET_NR_semsys + case TARGET_NR_semsys: { + abi_ulong flags = 0; + switch (arg1) { + case TARGET_NR_semsys_semctl: + switch (arg4) { + case TARGET_SEM_GETNCNT:arg4 = GETNCNT; break; + case TARGET_SEM_GETPID: arg4 = GETPID; break; + case TARGET_SEM_GETVAL: arg4 = GETVAL; break; + case TARGET_SEM_GETALL: arg4 = GETALL; break; + case TARGET_SEM_GETZCNT:arg4 = GETZCNT; break; + case TARGET_SEM_SETVAL: arg4 = SETVAL; break; + case TARGET_SEM_SETALL: arg4 = SETALL; break; + case TARGET_IPC_RMID: arg4 = IPC_RMID; break; + /* TODO: IPC_STAT, IPC_SET, structure rather different */ + } + ret = do_semctl(arg2, arg3, arg4, arg5); + break; + case TARGET_NR_semsys_semget: + flags |= arg4 & 0777; + if (arg4 & TARGET_IPC_CREAT) flags |= IPC_CREAT; + if (arg4 & TARGET_IPC_EXCL) flags |= IPC_EXCL; + ret = get_errno(semget(arg2, arg3, flags)); + break; + case TARGET_NR_semsys_semop: + ret = do_semop(arg2, arg3, arg4); + break; + default: + ret = -TARGET_EINVAL; + break; + } + break; + } +#endif +/* Solaris/SysV specific syscalls */ +#ifdef TARGET_NR_forksys + case TARGET_NR_forksys: + switch (arg1) { + case TARGET_NR_forksys_forkx: + ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0, 0, 0)); + break; + case TARGET_NR_forksys_vforkx: + ret = get_errno(do_fork(cpu_env, + CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD, 0, 0, 0, 0, 0, 0)); + break; + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_pgrpsys + case TARGET_NR_pgrpsys: + switch (arg1) { + case TARGET_NR_pgrpsys_getpgrp: + ret = get_errno(getpgrp()); + break; + case TARGET_NR_pgrpsys_setpgrp: + ret = get_errno(setpgrp()); + break; +#ifdef TARGET_ABI_SOLARIS + case TARGET_NR_pgrpsys_getsid: + ret = get_errno(getsid(arg2)); + break; + case TARGET_NR_pgrpsys_setsid: + ret = get_errno(setsid()); + break; + case TARGET_NR_pgrpsys_getpgid: + ret = get_errno(getpgid(arg2)); + break; + case TARGET_NR_pgrpsys_setpgid: + ret = get_errno(setpgid(arg2, arg3)); + break; +#endif + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_sigpendingsys + case TARGET_NR_sigpendingsys: + switch (arg1) { + case TARGET_NR_sigpsys_sigpending: + { + sigset_t set; + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + if (!(p = lock_user(VERIFY_WRITE, arg2, + sizeof(target_sigset_t), 0))) + goto efault; + host_to_target_old_sigset(p, &set); + unlock_user(p, arg2, sizeof(target_sigset_t)); + } + break; + } + case TARGET_NR_sigpsys_sigfillset: + { + if (!(p = lock_user(VERIFY_WRITE, arg2, + sizeof(target_sigset_t), 0))) + goto efault; + memset(p, 0xff, sizeof(target_sigset_t)); + unlock_user(p, arg2, sizeof(target_sigset_t)); + ret = 0; + break; + } + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_memcntl + case TARGET_NR_memcntl: + switch (arg3) { + case TARGET_NR_memcntl_msync: + ret = get_errno(msync(g2h(arg1), arg2, arg4)); + break; + case TARGET_NR_memcntl_mlock: + ret = get_errno(mlock(g2h(arg1), arg2)); + break; + case TARGET_NR_memcntl_munlock: + ret = get_errno(munlock(g2h(arg1), arg2)); + break; + case TARGET_NR_memcntl_mlockall: + ret = get_errno(mlockall(target_to_host_mlockall_arg(arg4))); + break; + case TARGET_NR_memcntl_munlockall: + ret = get_errno(munlockall()); + break; + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_fsat + case TARGET_NR_fsat: + if (!(p = lock_user_string(arg3))) + goto efault; + switch (arg1) { + case TARGET_NR_fsat_openat: + case TARGET_NR_fsat_openat64: + ret = do_openat(cpu_env, arg2, p, + target_to_host_bitmask(arg4, fcntl_flags_tbl), arg5); + break; + case TARGET_NR_fsat_fstatat: + ret = get_errno(fstatat(arg2, path(p), &st, arg5)); + if (!is_error(ret)) + ret = host_to_target_stat(cpu_env, arg4, &st); + break; + case TARGET_NR_fsat_fstatat64: + ret = get_errno(fstatat(arg2, path(p), &st, arg5)); + if (!is_error(ret)) + ret = host_to_target_stat64(cpu_env, arg4, &st); + break; + case TARGET_NR_fsat_renameat: + { + void *p2; + p2 = lock_user_string(arg5); + if (!p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(renameat(arg2, p, arg4, p2)); + unlock_user(p2, arg5, 0); + break; + } + case TARGET_NR_fsat_fchownat: + ret = get_errno(fchownat(arg2, p, + low2highuid(arg4), low2highgid(arg5), arg6)); + break; + case TARGET_NR_fsat_unlinkat: + ret = get_errno(unlinkat(arg2, p, arg4)); + break; + case TARGET_NR_fsat_futimesat: + { + struct timeval *tvp, tv[2]; + if (arg4) { + if (copy_from_user_timeval(&tv[0], arg4) || + copy_from_user_timeval(&tv[1], + arg4 + sizeof(struct target_timeval))) + unlock_user(p, arg3, 0); + goto efault; + tvp = tv; + } else { + tvp = NULL; + } + ret = get_errno(futimesat(arg2, path(p), tvp)); + } + break; + default: + ret = -TARGET_EINVAL; + } + unlock_user(p, arg3, 0); + break; +#endif +#ifdef TARGET_NR_rusagesys + case TARGET_NR_rusagesys: + { + switch (arg1) { + case TARGET_NR_rusagesys_rusage: + ret = RUSAGE_SELF; + break; + case TARGET_NR_rusagesys_rusagecld: + ret = RUSAGE_CHILDREN; + break; + case TARGET_NR_rusagesys_rusagelwp: + ret = RUSAGE_THREAD; + break; + default: + ret = -TARGET_EINVAL; + } + if (!is_error(ret)) { + struct rusage rusage; + ret = get_errno(getrusage(ret, &rusage)); + if (!is_error(ret)) { + ret = host_to_target_rusage(arg2, &rusage); + } + } + } + break; +#endif +#ifdef TARGET_NR_resolvepath + case TARGET_NR_resolvepath: + { + char *target_path, *target_buf, resolved_path[PATH_MAX]; + if (!(target_path = lock_user_string(arg1))) + goto efault; + if (!(target_buf = lock_user(VERIFY_WRITE, arg2, arg3, 0))) { + unlock_user(target_path, arg1, 0); + goto efault; + } + if (realpath(path(target_path), resolved_path)) { + target_buf[arg3-1] = 0; + strncpy(target_buf, resolved_path, arg3-1); + ret = strlen(target_buf)+1; + } else + ret = -host_to_target_errno(errno); + unlock_user(target_path, arg1, 0); + unlock_user(target_buf, arg2, arg3); + break; + } +#endif +#ifdef TARGET_NR_fdsync + case TARGET_NR_fdsync: + if (arg2 & 0x10) + ret = get_errno(fsync(arg1)); + else + ret = get_errno(fdatasync(arg1)); + break; +#endif +#ifdef TARGET_NR_context + case TARGET_NR_context: + switch (arg1) { + case TARGET_NR_context_getcontext: + { + struct target_ucontext *target_uc; + TaskState *ts = cpu->opaque; + + if (!lock_user_struct(VERIFY_WRITE, target_uc, arg2, 1)) { + goto efault; + } + /* UC_MCONTEXT */ + save_context(cpu_env, &target_uc->tuc_mcontext, 1); + __put_user( ts->ctx_link, (uint32_t *)&target_uc->tuc_link ); + __put_user( 0xc, &target_uc->tuc_flags ); + unlock_user_struct(target_uc, arg2, 1); + ret = 0; + break; + } + case TARGET_NR_context_setcontext: + { + struct target_ucontext *target_uc; + TaskState *ts = cpu->opaque; + target_sigset_t target_set; + sigset_t set; + int flags, i; + + /* Note: Solaris uses setcontext instead of sigreturn */ + if (!lock_user_struct(VERIFY_READ, target_uc, arg2, 1)) { + goto efault; + } + __get_user( flags, &target_uc->tuc_flags ); + + /* UC_MCONTEXT */ + restore_context(cpu_env, &target_uc->tuc_mcontext); + /* UC_SIGMASK */ + if (flags & 1) { + for (i = 0; i < TARGET_NSIG_WORDS; i++) + __get_user(target_set.sig[i], + &target_uc->tuc_sigmask.sig[i]); + target_to_host_sigset(&set, &target_set); + do_sigprocmask(cpu_env, SIG_SETMASK, &set, NULL); + } + + __get_user( ts->ctx_link, (uint32_t *)&target_uc->tuc_link ); + unlock_user_struct(target_uc, arg2, 0); + ret = -TARGET_QEMU_ESIGRETURN; + break; + } + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_so_socket + case TARGET_NR_so_socket: + /* TODO: how to handle arg4=devpath and arg5=version? */ + ret = do_socket(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_pathconf + case TARGET_NR_pathconf: + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(pathconf(path(p), target_to_host_pathconf(arg2))); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_fpathconf: + ret = get_errno(fpathconf(arg1, target_to_host_pathconf(arg2))); + break; +#endif +#ifdef TARGET_NR_sysconfig + case TARGET_NR_sysconfig: + switch (arg1) { + case TARGET_NR_sysconf_childmax: + ret = get_errno(sysconf(_SC_CHILD_MAX)); + break; + case TARGET_NR_sysconf_openmax: + ret = get_errno(sysconf(_SC_OPEN_MAX)); + break; + case TARGET_NR_sysconf_pagesize: + ret = TARGET_PAGE_SIZE; + break; + case TARGET_NR_sysconf_clktick: + ret = get_errno(sysconf(_SC_CLK_TCK)); + break; + case TARGET_NR_sysconf_nprocs: + ret = 1; + break; + case TARGET_NR_sysconf_physmem: + ret = 1024*1024*1024/TARGET_PAGE_SIZE; + break; + case TARGET_NR_sysconf_stckprot: + ret = R_OK|W_OK|X_OK; + break; + default: + ret = -TARGET_EINVAL; + } + break; +#endif +#ifdef TARGET_NR_sysinfosunos + case TARGET_NR_sysinfosunos: + { + char *target_buf; + + if (!(target_buf = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + + ret = 0; + target_buf[arg3-1] = 0; + switch (arg1) { + case TARGET_NR_sysinfo_gethostname: + ret = get_errno(gethostname(target_buf, arg3-1)); + break; + case TARGET_NR_sysinfo_sethostname: + ret = get_errno(sethostname(target_buf, arg3-1)); + break; + case TARGET_NR_sysinfo_getsrpcdomain: + strncpy(target_buf, "", arg3-1); + break; + + case TARGET_NR_sysinfo_sysname: + strncpy(target_buf, "SunOS", arg3-1); + break; + case TARGET_NR_sysinfo_release: + strncpy(target_buf, "5.7", arg3-1); + break; + case TARGET_NR_sysinfo_version: + strncpy(target_buf, "Generic", arg3-1); + break; + case TARGET_NR_sysinfo_machine: + strncpy(target_buf, "sun4m", arg3-1); + break; + case TARGET_NR_sysinfo_hwserial: + strncpy(target_buf, "0", arg3-1); + break; + case TARGET_NR_sysinfo_hwproducer: + strncpy(target_buf, "Qemu", arg3-1); + break; + case TARGET_NR_sysinfo_platform: + strncpy(target_buf, "sun4m", arg3-1); + break; + case TARGET_NR_sysinfo_isalist: + strncpy(target_buf, "sparcv7 sparc", arg3-1); + break; + case TARGET_NR_sysinfo_arch32: + case TARGET_NR_sysinfo_archkern: + case TARGET_NR_sysinfo_archnative: + case TARGET_NR_sysinfo_cpuarch: + strncpy(target_buf, "sparc", arg3-1); + break; + default: + ret = -TARGET_EINVAL; + } + ret = (ret ?: strlen(target_buf)+1); + unlock_user(target_buf, arg2, (ret > 0 ? ret : 0)); + break; + } +#endif +#ifdef TARGET_NR_unamesunos + case TARGET_NR_unamesunos: + { + struct target_utsname *target_buf; + struct utsname buf; + + if (!lock_user_struct(VERIFY_WRITE, target_buf, arg1, 0)) + goto efault; + ret = get_errno(uname(&buf)); + if (!is_error(ret)) { + /* Override the native machine name with whatever is being + emulated. */ + strcpy (buf.machine, cpu_to_uname_machine(cpu_env)); + /* Allow the user to override the reported release. */ + if (qemu_uname_release && *qemu_uname_release) + strcpy (buf.release, qemu_uname_release); + + strncpy(target_buf->sysname, "SunOS", sizeof(target_buf->sysname)); + strncpy(target_buf->nodename, buf.nodename, sizeof(target_buf->nodename)); + strncpy(target_buf->release, "5.7", sizeof(target_buf->release)); + strncpy(target_buf->version, "Generic", sizeof(target_buf->version)); + strncpy(target_buf->machine, "sun4m", sizeof(target_buf->machine)); + ret = 1; /* says the illuminos code? */ + } + unlock_user_struct(target_buf, arg1, 1); + break; + } +#endif +/* IRIX specific syscalls */ +#ifdef TARGET_NR_sproc + case TARGET_NR_nsproc: /* pid = nsproc(entry, flags, prthread, prsched) */ + { + /* TODO: prsched? */ + struct target_prthread *target_prthread; + abi_ulong prthread = arg3; + if (!lock_user_struct(VERIFY_READ, target_prthread, prthread, 0)) + goto efault; + __get_user(arg3, &target_prthread->prt_arg); + __get_user(arg4, &target_prthread->prt_stkptr); + __get_user(arg5, &target_prthread->prt_stklen); + unlock_user_struct(target_prthread, prthread, 1); + goto do_sprocsp; + } + case TARGET_NR_sproc: /* pid = sproc(entry, flags, arg) */ + arg5 = 16384; /* default stack size? */ + arg4 = target_mmap(0, arg5, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if ((abi_int)arg4 == -1) { + ret = -TARGET_ENOMEM; + break; + } + goto do_sprocsp; + + case TARGET_NR_sprocsp: /* pid = sprocsp(entry, flags, arg, stack, len) */ + do_sprocsp: + { + int opt; + + /* qemu only knows about (v)fork and pthread_create :-( */ + if ((arg2 & (TARGET_PR_BLOCK|TARGET_PR_SALL)) == + (TARGET_PR_BLOCK|TARGET_PR_SADDR)) + /* treat this like vfork */ + opt = CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD; + else + /* treat everything else like pthread_create */ + opt = CLONE_THREAD_FLAGS; + arg4 = arg4 + arg5 - 16; /* set stack top */ + ret = get_errno(do_fork(cpu_env, opt, arg4, 0, 0, 0, arg1, arg3)); + /* man page says PR_BLOCK blocks the parent process like procblk does */ + if (ret > 0 && !(opt & CLONE_VFORK) && (arg2 & TARGET_PR_BLOCK)) { + TaskState *ts = cpu->opaque; + arg1 = TARGET_NR_procblk_block; + arg2 = ts->ts_tid; + goto do_procblk; + } + /* child, or error */ + break; + } +#endif +#ifdef TARGET_NR_procblk + case TARGET_NR_procblk: + do_procblk: + { + TaskState *ts = find_task_state(arg2); + int old_count; + ret = 0; + if (!ts) { + ret = -TARGET_ESRCH; + break; + } + /* NOTE: implementation inspired by netbsd-5 code */ + pthread_mutex_lock(&ts->procblk_mutex); + old_count = ts->procblk_count; + switch (arg1) { + case TARGET_NR_procblk_block: /* blockproc(pid) */ + if (ts != cpu->opaque && old_count == 0) + ret = -TARGET_EPERM; + else + ts->procblk_count --; + break; + case TARGET_NR_procblk_unblock: /* unblockproc(pid) */ + ts->procblk_count ++; + break; + case TARGET_NR_procblk_count: /* setblockproccnt(pid, val) */ + if (ts != cpu->opaque && (old_count < 0) != (arg3 < 0)) + ret = -TARGET_EPERM; + else + ts->procblk_count = arg3; + break; + /* TODO: block_all, unblock_all, count_all */ + default: + gemu_log("qemu: Unsupported syscall: procblk(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + if (ret == 0 && ts) { + if (ts->procblk_count < 0 && old_count >= 0) { + ts->is_blocked = 1; + do { + pthread_cond_wait(&ts->procblk_cond, &ts->procblk_mutex); + } while (ts->is_blocked); + } else if (ts->procblk_count >= 0 && old_count < 0) { + ts->is_blocked = 0; + pthread_cond_broadcast(&ts->procblk_cond); + } + } + pthread_mutex_unlock(&ts->procblk_mutex); + } + break; +#endif +#ifdef TARGET_NR_usync_cntl + case TARGET_NR_usync_cntl: + { + struct target_usync *target_buf; + struct usync_ref *sync, *lock; + struct timespec ts; + if (!lock_user_struct(VERIFY_WRITE, target_buf, arg2, 0)) + goto efault; + if (!(sync = usync_get_sync(tswap64(target_buf->u_sync)))) { + ret = -TARGET_ENOMEM; + break; + } + /* Unfortunately I discovered the netbsd-5 code is plainly wrong :-( + * The mtune usync file talks about a "synchronizing address", which is + * what all this is about. Nothing in user space is changed by usync. + */ + switch (arg1) { + case TARGET_NR_usync_handoff: /* implements pthread_cond_wait? */ + /* TODO: handoff uncovered by experiment, and it seems to work, + * but it looks rather strange. Is this correct? */ + if (!(lock = usync_get_sync(tswap64(target_buf->u_lock)))) { + ret = -TARGET_ENOMEM; + break; + } + pthread_mutex_lock(&lock->lock); + lock->count ++; + lock->handoffs ++; /* Mark this as being used as handoff lock */ + ret = pthread_cond_signal(&lock->cond); + pthread_mutex_unlock(&lock->lock); + /*FALLTHROUGH*/ + case TARGET_NR_usync_block: /* block on address */ + case TARGET_NR_usync_intr_block: /* interruptible block? */ + __get_user(ts.tv_sec, &target_buf->u_sec); + __get_user(ts.tv_nsec, &target_buf->u_nsec); + pthread_mutex_lock(&sync->lock); + sync->waiters ++; + for (ret = 0; sync->count <= 0 && ret == 0; ) { + if (target_buf->u_flags & tswap16(TARGET_US_TIMEOUT)) + ret = pthread_cond_timedwait(&sync->cond, &sync->lock, &ts); + else + ret = pthread_cond_wait(&sync->cond, &sync->lock); + } + if (!ret) { + sync->count --; + /* Notify the caller if this was used as handoff lock */ + ret = sync->handoffs; + if (sync->handoffs) + sync->handoffs --; + } + sync->waiters --; + pthread_mutex_unlock(&sync->lock); + break; + case TARGET_NR_usync_unblock_all: /* unblock everyone waiting on addr */ + pthread_mutex_lock(&sync->lock); + sync->count = sync->waiters; + ret = pthread_cond_broadcast(&sync->cond); + pthread_mutex_unlock(&sync->lock); + break; + case TARGET_NR_usync_unblock: /* unblock one process waiting on addr */ + pthread_mutex_lock(&sync->lock); + sync->count ++; + ret = pthread_cond_signal(&sync->cond); + pthread_mutex_unlock(&sync->lock); + break; + case TARGET_NR_usync_get_state: /* get current wait state */ + pthread_mutex_lock(&sync->lock); + ret = sync->count - sync->waiters; + pthread_mutex_unlock(&sync->lock); + break; + default: + gemu_log("qemu: Unsupported syscall: usynccntl(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + unlock_user_struct(target_buf, arg2, 1); + } + break; +#endif +#ifdef TARGET_NR_sgiprctl + case TARGET_NR_sgiprctl: + { + CPUState *p; + TaskState *ts = (TaskState *)cpu->opaque; + switch (arg1) { + case TARGET_NR_prctl_maxpprocs: /* #available processors */ + ret = 1; + break; + case TARGET_NR_prctl_getnshare: /* #processes in share group? */ + for (ret = 0, p = first_cpu; p; ret++, p = CPU_NEXT(p)) ; + break; + case TARGET_NR_prctl_lastshexit: /* checks if share group is empty?*/ + ret = (CPU_NEXT(first_cpu) == NULL); + break; + case TARGET_NR_prctl_termchild: /* send SIGHUP to child if parent dies */ + ts->termchild_sig = TARGET_SIGHUP; + ret = 0; + break; + case TARGET_NR_prctl_unblkonexec: /* on exec unblock parent thread */ + /* TODO: for vfork, this should work right away, but otherwise? */ + ret = 0; + break; + case TARGET_NR_prctl_setexitsig: /* on exit send signal to threads */ + /* TODO: global parameters (that is, valid for all threads)? */ + for (p = first_cpu; p; p = CPU_NEXT(p)) { + ts = (TaskState *)p->opaque; + ts->exit_sig = arg2; + } + ret = 0; + break; + case TARGET_NR_prctl_isblocked: /* is process blocked? */ + /* TODO: only covers procblk/threadctl, not usync/psema/semsys? */ + ts = find_task_state(arg2); + if (ts) + ret = ts->is_blocked; + else + ret = -TARGET_ESRCH; + break; + case TARGET_NR_prctl_initthreads: /* initialize process for pthreads? */ + ts->is_pthread = 1; + ret = 0; + break; + case TARGET_NR_prctl_threadctl: /* pthread thread control */ + switch (arg2) { + case TARGET_NR_prctl_thread_exit: /* exit() */ + ret = do_exit(cpu_env, 0); + break; + case TARGET_NR_prctl_thread_block: /* block(), this thread */ + pthread_mutex_lock(&ts->procblk_mutex); + ts->procblk_count --; + ts->is_blocked = 1; + for (ret = 0; ts->procblk_count < 0 && ret == 0; ) { + ret = pthread_cond_wait(&ts->procblk_cond, &ts->procblk_mutex); + }; + ts->is_blocked = 0; + pthread_mutex_unlock(&ts->procblk_mutex); + if (ret) + ret = -host_to_target_errno(errno); + break; + case TARGET_NR_prctl_thread_unblock: /* unblock(tid) */ + ts = find_task_state(arg3); + if (ts) { + pthread_mutex_lock(&ts->procblk_mutex); + ts->procblk_count ++; + pthread_cond_broadcast(&ts->procblk_cond); + pthread_mutex_unlock(&ts->procblk_mutex); + ret = 0; + } else + ret = -TARGET_ESRCH; + break; + case TARGET_NR_prctl_thread_kill: /* kill(tid, sig) */ + { + CPUState *p = find_cpu_state(arg3); + target_siginfo_t info = { 0 }; + info.si_signo = arg4; + if (p) { + queue_signal((CPUArchState *)p->env_ptr, info.si_signo, + QEMU_SI_KILL, &info); + /* TODO: must process here because thread may be blocked? */ + process_pending_signals((CPUArchState *)p->env_ptr); + } + ret = 0; + break; + } + case TARGET_NR_prctl_thread_sched: /* what's this ?!? */ + default: + ret = -TARGET_ENOSYS; + break; + } + break; + default: + gemu_log("qemu: Unsupported syscall: sgiprctl(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif +#ifdef TARGET_NR_psema_cntl + case TARGET_NR_psema_cntl: + { + char *p; + sem_t *s; + int v; + switch (arg1) { + case TARGET_NR_psema_open: /* idx = sem_open(name, flags, mode, val) */ + /* TODO: On IRIX, this returns a small integer, probably an fd? */ + if (!(p = lock_user_string(arg2))) + goto efault; + s = sem_open(p, target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4, arg5); + if (s == SEM_FAILED) + ret = -host_to_target_errno(errno); + else + ret = psema_get_index(p, s, 1); + unlock_user(p, arg2, 0); + break; + case TARGET_NR_psema_close: /* sem_close(idx) */ + ret = get_errno(sem_close(psema_get_sem(arg2))); + if (ret == 0) + psema_remove_index(arg2); + break; + case TARGET_NR_psema_unlink: /* sem_unlink(name) */ + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sem_unlink(p)); + if (!is_error(ret)) + psema_unlink_index(p); + unlock_user(p, arg2, 0); + break; + case TARGET_NR_psema_wait: /* sem_wait(idx) */ + case TARGET_NR_psema_wait2: /* TODO: difference between wait, wait2? */ + ret = get_errno(sem_wait(psema_get_sem(arg2))); + break; + case TARGET_NR_psema_trywait: /* sem_trywait(idx) */ + ret = get_errno(sem_trywait(psema_get_sem(arg2))); + break; + case TARGET_NR_psema_post: /* sem_post(idx) */ + ret = get_errno(sem_post(psema_get_sem(arg2))); + break; + case TARGET_NR_psema_getvalue: /* sem_getvalue(idx, &val) */ + ret = get_errno(sem_getvalue(psema_get_sem(arg2), &v)); + put_user(v, arg3, abi_int); + break; + default: + gemu_log("qemu: Unsupported syscall: psema_cntl(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif +#ifdef TARGET_NR_syssgi + case TARGET_NR_syssgi: + { + switch (arg1) { + case TARGET_NR_syssgi_elfmap: /* map ELF shared object */ + { +#ifdef TARGET_ABI_MIPSN64 + struct elf64_phdr *target_phdr, *phdr; +#else + struct elf32_phdr *target_phdr, *phdr; +#endif + int i; + target_phdr = lock_user(VERIFY_READ, arg3, sizeof(*phdr)*arg4, 1); + if (!target_phdr) { + goto efault; + } + phdr = alloca(sizeof(*phdr)*arg4); + for (i = 0; i < arg4; i++) { + __get_user(phdr[i].p_type, &target_phdr[i].p_type); + __get_user(phdr[i].p_offset, &target_phdr[i].p_offset); + __get_user(phdr[i].p_vaddr, &target_phdr[i].p_vaddr); + __get_user(phdr[i].p_paddr, &target_phdr[i].p_paddr); + __get_user(phdr[i].p_filesz, &target_phdr[i].p_filesz); + __get_user(phdr[i].p_memsz, &target_phdr[i].p_memsz); + __get_user(phdr[i].p_flags, &target_phdr[i].p_flags); + __get_user(phdr[i].p_align, &target_phdr[i].p_align); + } + ret = sgi_map_elf_image(arg2, phdr, arg4); + unlock_user(target_phdr, arg3, 0); + break; + } + case TARGET_NR_syssgi_sigaltstack: + ret = do_sigaltstack(cpu_env, arg2, arg3, + get_sp_from_cpustate((CPUArchState *)cpu_env)); + break; + case TARGET_NR_syssgi_settimeofday: + { + struct timeval tv; + if (copy_from_user_timeval(&tv, arg2)) + goto efault; + ret = get_errno(settimeofday(&tv, NULL)); + } + break; + case TARGET_NR_syssgi_getpgid: + ret = get_errno(getpgid(arg2)); + break; + case TARGET_NR_syssgi_getsid: + ret = get_errno(getsid(arg2)); + break; + case TARGET_NR_syssgi_sysconf: + switch (arg2) { + case TARGET_NR_sysconf_childmax: + ret = get_errno(sysconf(_SC_CHILD_MAX)); + break; + case TARGET_NR_sysconf_openmax: + ret = get_errno(sysconf(_SC_OPEN_MAX)); + break; + case TARGET_NR_sysconf_clktick: + ret = get_errno(sysconf(_SC_CLK_TCK)); + break; + case TARGET_NR_sysconf_pagesize: + ret = TARGET_PAGE_SIZE; + break; + case TARGET_NR_sysconf_nprocs: + ret = 1; + break; + case TARGET_NR_sysconf_acl: + case TARGET_NR_sysconf_cap: + case TARGET_NR_sysconf_mac: + ret = 0; + break; + default: + gemu_log("qemu: Unsupported syscall: sysconf(%d)\n", (int)arg2); + ret = -TARGET_ENOSYS; + break; + } + break; + case TARGET_NR_syssgi_pathconf: + if (arg3 == 1) { + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(pathconf(path(p), target_to_host_pathconf(arg2))); + unlock_user(p, arg1, 0); + } else + ret = get_errno(fpathconf(arg1, target_to_host_pathconf(arg2))); + break; + case TARGET_NR_syssgi_rusage: + { + struct rusage rusage; + ret = get_errno(getrusage(arg2, &rusage)); + if (!is_error(ret)) { + ret = host_to_target_rusage(arg3, &rusage); + } + } + break; + case TARGET_NR_syssgi_fdhi: /* highest valid fd */ + { + DIR *dir; + struct dirent *de; + int fdhi = 0; + if ((dir = opendir("/proc/self/fd"))) { + while ((de = readdir(dir))) { + if (de->d_name[0] != '.') { + char *err = NULL; + long l = strtol(de->d_name, &err, 10); + if (err && !*err && l > fdhi) + fdhi = l; + } + } + } + ret = (fdhi > 0 ? fdhi+1 : -TARGET_EBADF); + } + break; + case TARGET_NR_syssgi_getust: /* get unadjusted system time */ + { + struct timespec ts; + struct timeval tv; + abi_ullong ust, *target_ust; + + /* arg1: ptr to llong, some time in ns? */ + target_ust = lock_user(VERIFY_WRITE, arg1, sizeof(ust), 0); + if (!target_ust) + goto efault; + ret = get_errno(clock_gettime(CLOCK_MONOTONIC_RAW, &ts)); + if (!is_error(ret)) { + ust = ts.tv_sec * 1000000000LL + ts.tv_nsec; + __put_user(ust, target_ust); + } + unlock_user(target_ust, arg1, sizeof(ust)); + + /* arg2: optional ptr to timeval (equiv. to gettimeofday)? */ + if (arg2 && !is_error(ret)) { + ret = get_errno(gettimeofday(&tv, NULL)); + if (!is_error(ret) && arg2) { + if (copy_to_user_timeval(arg2, &tv)) + goto efault; + } + } + } + break; + case TARGET_NR_syssgi_sysid: + { + char * buf = lock_user(VERIFY_WRITE, arg2, 64, 0); + if (!buf) { + goto efault; + } + snprintf(buf, 64, "%12llx", 0x08006900000DULL); + ret = 0; + unlock_user(buf, arg2, 64); + break; + } + case TARGET_NR_syssgi_rldenv: + case TARGET_NR_syssgi_tosstsave: + case TARGET_NR_syssgi_fpbcopy: + ret = 0; + break; + case TARGET_NR_syssgi_setgroups: + case TARGET_NR_syssgi_getgroups: + default: + gemu_log("qemu: Unsupported syscall: sgisys(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif +#ifdef TARGET_NR_sginap + case TARGET_NR_sginap: /* yield if arg1=0, else nap arg1 clk ticks */ + if (arg1) + ret = get_errno(usleep(arg1*10000)); /* assume tick freq = 100 Hz */ + else + ret = sched_yield(); + break; +#endif +#ifdef TARGET_NR_getmountid + case TARGET_NR_getmountid: + { + uint32_t *mid = lock_user(VERIFY_WRITE, arg2, sizeof(uint32_t)*4, 0); + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(statfs(p, &stfs)); + memcpy(mid, &stfs.f_fsid, sizeof(uint32_t)*4); + __put_user(stfs.f_type, &mid[3]); + unlock_user(p, arg1, 0); + unlock_user(mid, arg2, sizeof(uint32_t)*4); + break; + } +#endif + /* stub implementations for misc IRIX stuff */ +#ifdef TARGET_NR_sysmp + case TARGET_NR_sysmp: + { + switch (arg1) { + case TARGET_NR_sysmp_nprocs: /* #physical processors */ + case TARGET_NR_sysmp_naprocs: /* #processors without process limit */ + ret = 1; + break; + case TARGET_NR_sysmp_pgsize: + ret = TARGET_PAGE_SIZE; + break; + default: + gemu_log("qemu: Unsupported syscall: sgisysmp(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif +#ifdef TARGET_NR_swapctl + case TARGET_NR_swapctl: + { + switch (arg1) { + case TARGET_NR_swapctl_getfree: + put_user(512*512, arg2, abi_ulong); + ret = 0; + break; + default: + gemu_log("qemu: Unsupported syscall: swapctl(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif +#ifdef TARGET_NR_sysinfosgi + case TARGET_NR_sysinfosgi: + { + char *target_buf; + + if (!(target_buf = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; + + ret = 0; + target_buf[arg3-1] = 0; + switch (arg1) { + case TARGET_NR_sysinfo_gethostname: + ret = get_errno(gethostname(target_buf, arg3-1)); + break; + case TARGET_NR_sysinfo_sethostname: + ret = get_errno(sethostname(target_buf, arg3-1)); + break; + case TARGET_NR_sysinfo_getsrpcdomain: + strncpy(target_buf, "", arg3-1); + break; + + case TARGET_NR_sysinfo_sysname: + strncpy(target_buf, "IRIX", arg3-1); + break; + case TARGET_NR_sysinfo_release: + strncpy(target_buf, "6.5", arg3-1); + break; + case TARGET_NR_sysinfo_version: + strncpy(target_buf, "01010101", arg3-1); + break; + case TARGET_NR_sysinfo_machine: + strncpy(target_buf, "IP22", arg3-1); + break; + case TARGET_NR_sysinfo_hwserial: + snprintf(target_buf, arg3-1, "%12llx", 0x08006900000DULL); + break; + case TARGET_NR_sysinfo_hwproducer: + strncpy(target_buf, "Qemu", arg3-1); + break; + + case TARGET_NR_sysinfo_processors: + strncpy(target_buf, "R4000 3.0", arg3-1); + break; + default: + gemu_log("qemu: Unsupported syscall: sgisysinfo(%d)\n", (int)arg1); + ret = -TARGET_EINVAL; + } + ret = (ret ?: strlen(target_buf)+1); + unlock_user(target_buf, arg2, (ret > 0 ? ret : 0)); + break; + } +#endif +#if defined TARGET_NR_utssyssgi + case TARGET_NR_utssyssgi: + { + switch (arg3) { + case TARGET_NR_utssys_uname: + { + struct target_utsname *target_buf; + struct utsname buf; + + if (!lock_user_struct(VERIFY_WRITE, target_buf, arg1, 0)) + goto efault; + ret = get_errno(uname(&buf)); + if (!is_error(ret)) { + /* Override the native machine name with whatever is being + emulated. */ + strcpy (buf.machine, cpu_to_uname_machine(cpu_env)); + /* Allow the user to override the reported release. */ + if (qemu_uname_release && *qemu_uname_release) + strcpy (buf.release, qemu_uname_release); + + strncpy(target_buf->sysname, "IRIX", sizeof(target_buf->sysname)); + strncpy(target_buf->nodename, buf.nodename, sizeof(target_buf->nodename)); + strncpy(target_buf->release, "6.5", sizeof(target_buf->release)); + strncpy(target_buf->version, "01010101", sizeof(target_buf->version)); + strncpy(target_buf->machine, "IP22", sizeof(target_buf->machine)); + } + unlock_user_struct(target_buf, arg1, 1); + break; + } + default: + gemu_log("qemu: Unsupported syscall: utssys(%d)\n", (int)arg1); + ret = -TARGET_ENOSYS; + break; + } + break; + } +#endif default: + goto unimplemented; + unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list) +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_set_robust_list) unimplemented_nowarn: #endif ret = -TARGET_ENOSYS; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e00e1b3862..eae23e8ad7 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -203,12 +203,21 @@ struct target_ip_mreq_source { }; struct target_timeval { +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN64) + int tv_pad1; + abi_int tv_sec; +#else abi_long tv_sec; +#endif abi_long tv_usec; }; struct target_timespec { +#if defined(TARGET_ABI_IRIX) && defined(TARGET_ABI_MIPSN64) + abi_int tv_sec; +#else abi_long tv_sec; +#endif abi_long tv_nsec; }; @@ -255,7 +264,11 @@ struct target_timex { abi_int:32; abi_int:32; abi_int:32; }; +#ifdef TARGET_ABI_IRIX +typedef abi_int target_clock_t; +#else typedef abi_long target_clock_t; +#endif #define TARGET_HZ 100 @@ -267,8 +280,13 @@ struct target_tms { }; struct target_utimbuf { +#ifdef TARGET_ABI_IRIX + abi_int actime; + abi_int modtime; +#else abi_long actime; abi_long modtime; +#endif }; struct target_sel_arg_struct { @@ -286,9 +304,15 @@ struct target_msghdr { abi_long msg_name; /* Socket name */ int msg_namelen; /* Length of name */ abi_long msg_iov; /* Data blocks */ +#ifdef TARGET_ABI_IRIX + abi_int msg_iovlen; /* Number of blocks */ + abi_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + abi_int msg_controllen; /* Length of cmsg list */ +#else abi_long msg_iovlen; /* Number of blocks */ abi_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ abi_long msg_controllen; /* Length of cmsg list */ +#endif unsigned int msg_flags; }; @@ -376,7 +400,9 @@ struct target_dirent64 { uint64_t d_ino; int64_t d_off; unsigned short d_reclen; +#if !defined TARGET_ABI_IRIX && !defined TARGET_ABI_SOLARIS unsigned char d_type; +#endif char d_name[256]; }; @@ -386,24 +412,38 @@ struct target_dirent64 { #define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ #define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ -#ifdef TARGET_MIPS +#if defined TARGET_MIPS || defined TARGET_ABI_SOLARIS #define TARGET_NSIG 128 #else #define TARGET_NSIG 64 #endif + +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS +#define TARGET_NSIG_BPW (8*sizeof(uint32_t)) +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +typedef struct { + uint32_t sig[TARGET_NSIG_WORDS]; +} target_sigset_t; +#else #define TARGET_NSIG_BPW TARGET_ABI_BITS #define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) typedef struct { abi_ulong sig[TARGET_NSIG_WORDS]; } target_sigset_t; +#endif #ifdef BSWAP_NEEDED static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) { int i; for(i = 0;i < TARGET_NSIG_WORDS; i++) +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS + d->sig[i] = tswap32(s->sig[i]); +#else d->sig[i] = tswapal(s->sig[i]); +#endif } #else static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) @@ -427,7 +467,7 @@ void host_to_target_old_sigset(abi_ulong *old_sigset, void target_to_host_old_sigset(sigset_t *sigset, const abi_ulong *old_sigset); struct target_sigaction; -int do_sigaction(int sig, const struct target_sigaction *act, +int do_sigaction(CPUArchState *env, int sig, const struct target_sigaction *act, struct target_sigaction *oact); #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ @@ -438,7 +478,15 @@ int do_sigaction(int sig, const struct target_sigaction *act, || defined(TARGET_TILEGX) || defined(TARGET_HPPA) || defined(TARGET_NIOS2) \ || defined(TARGET_RISCV) -#if defined(TARGET_SPARC) +#if defined(TARGET_ABI_IRIX) || defined(TARGET_ABI_SOLARIS) +#define TARGET_SA_NOCLDSTOP 0x00020000 +#define TARGET_SA_NOCLDWAIT 0x00010000 +#define TARGET_SA_SIGINFO 0x00000008 +#define TARGET_SA_ONSTACK 0x00000001 +#define TARGET_SA_RESTART 0x00000004 +#define TARGET_SA_NODEFER 0x00000010 +#define TARGET_SA_RESETHAND 0x00000002 +#elif defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u #define TARGET_SA_NOCLDWAIT 0x100u #define TARGET_SA_SIGINFO 0x200u @@ -536,47 +584,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIG_UNBLOCK 2 #define TARGET_SIG_SETMASK 3 -#elif defined(TARGET_SPARC) - -#define TARGET_SIGHUP 1 -#define TARGET_SIGINT 2 -#define TARGET_SIGQUIT 3 -#define TARGET_SIGILL 4 -#define TARGET_SIGTRAP 5 -#define TARGET_SIGABRT 6 -#define TARGET_SIGIOT 6 -#define TARGET_SIGSTKFLT 7 /* actually EMT */ -#define TARGET_SIGFPE 8 -#define TARGET_SIGKILL 9 -#define TARGET_SIGBUS 10 -#define TARGET_SIGSEGV 11 -#define TARGET_SIGSYS 12 -#define TARGET_SIGPIPE 13 -#define TARGET_SIGALRM 14 -#define TARGET_SIGTERM 15 -#define TARGET_SIGURG 16 -#define TARGET_SIGSTOP 17 -#define TARGET_SIGTSTP 18 -#define TARGET_SIGCONT 19 -#define TARGET_SIGCHLD 20 -#define TARGET_SIGTTIN 21 -#define TARGET_SIGTTOU 22 -#define TARGET_SIGIO 23 -#define TARGET_SIGXCPU 24 -#define TARGET_SIGXFSZ 25 -#define TARGET_SIGVTALRM 26 -#define TARGET_SIGPROF 27 -#define TARGET_SIGWINCH 28 -#define TARGET_SIGPWR 29 -#define TARGET_SIGUSR1 30 -#define TARGET_SIGUSR2 31 -#define TARGET_SIGRTMIN 32 - -#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */ -#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */ -#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */ - -#elif defined(TARGET_MIPS) +#elif defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) #define TARGET_SIGHUP 1 /* Hangup (POSIX). */ #define TARGET_SIGINT 2 /* Interrupt (ANSI). */ @@ -613,7 +621,11 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */ #define TARGET_SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */ #define TARGET_SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */ +#ifdef TARGET_ABI_SOLARIS +#define TARGET_SIGRTMIN 42 +#else #define TARGET_SIGRTMIN 32 +#endif #define TARGET_SIG_BLOCK 1 /* for blocking signals */ #define TARGET_SIG_UNBLOCK 2 /* for unblocking signals */ @@ -659,6 +671,46 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIG_UNBLOCK 1 #define TARGET_SIG_SETMASK 2 +#elif defined(TARGET_SPARC) + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGBUS 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGURG 16 +#define TARGET_SIGSTOP 17 +#define TARGET_SIGTSTP 18 +#define TARGET_SIGCONT 19 +#define TARGET_SIGCHLD 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGIO 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGPWR 29 +#define TARGET_SIGUSR1 30 +#define TARGET_SIGUSR2 31 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */ + #else /* OpenRISC Using the general signals */ @@ -723,7 +775,7 @@ struct target_sigaction { target_sigset_t sa_mask; abi_ulong sa_restorer; }; -#elif defined(TARGET_MIPS) +#elif defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) struct target_sigaction { uint32_t sa_flags; #if defined(TARGET_ABI_MIPSN32) @@ -812,7 +864,7 @@ typedef struct { #define QEMU_SI_RT 5 typedef struct target_siginfo { -#ifdef TARGET_MIPS +#if defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) int si_signo; int si_code; int si_errno; @@ -847,10 +899,17 @@ typedef struct target_siginfo { /* SIGCHLD */ struct { pid_t _pid; /* which child */ +#if defined(TARGET_ABI_IRIX) || defined(TARGET_ABI_SOLARIS) + target_clock_t _utime; + int _status; /* exit code */ + target_clock_t _stime; + int _swap; +#else uid_t _uid; /* sender's uid */ int _status; /* exit code */ target_clock_t _utime; target_clock_t _stime; +#endif } _sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ @@ -860,8 +919,13 @@ typedef struct target_siginfo { /* SIGPOLL */ struct { +#if defined(TARGET_ABI_IRIX) || defined(TARGET_ABI_SOLARIS) + int _fd; + abi_long _band; /* POLL_IN, POLL_OUT, POLL_MSG */ +#else int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; +#endif } _sigpoll; } _sifields; } target_siginfo_t; @@ -944,11 +1008,13 @@ struct target_rlimit { #define TARGET_RLIM_INFINITY 0x7fffffffffffffffull #elif defined(TARGET_MIPS) || (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32) #define TARGET_RLIM_INFINITY 0x7fffffffUL +#define TARGET_RLIM64_INFINITY 0x7fffffffffffffffull #else #define TARGET_RLIM_INFINITY ((abi_ulong)-1) +#define TARGET_RLIM64_INFINITY ((uint64_t)-1) #endif -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) #define TARGET_RLIMIT_CPU 0 #define TARGET_RLIMIT_FSIZE 1 #define TARGET_RLIMIT_DATA 2 @@ -1008,6 +1074,10 @@ struct target_pollfd { #define TARGET_KDSETLED 0x4B32 /* set led state [lights, not flags] */ #define TARGET_KDSIGACCEPT 0x4B4E +#ifdef TARGET_ABI_IRIX +#define TARGET_SIOCNREAD 0x4004730a +#endif + #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SH4) #define TARGET_SIOCATMARK TARGET_IOR('s', 7, int) #define TARGET_SIOCGPGRP TARGET_IOR('s', 9, pid_t) @@ -1311,10 +1381,21 @@ struct target_pollfd { #define TARGET_NCC 8 struct target_termio { +#ifdef TARGET_ABI_IRIX + uint32_t c_iflag; /* input mode flags */ + uint32_t c_oflag; /* output mode flags */ + uint32_t c_cflag; /* control mode flags */ + uint32_t c_lflag; /* local mode flags */ +#ifdef IRIX_NEW_TERMIO + uint32_t c_ospeed; + uint32_t c_ispeed; +#endif +#else unsigned short c_iflag; /* input mode flags */ unsigned short c_oflag; /* output mode flags */ unsigned short c_cflag; /* control mode flags */ unsigned short c_lflag; /* local mode flags */ +#endif unsigned char c_line; /* line discipline */ unsigned char c_cc[TARGET_NCC]; /* control characters */ }; @@ -1356,6 +1437,9 @@ struct target_winsize { #define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */ #define TARGET_MAP_STACK 0x40000 /* ignored */ #define TARGET_MAP_HUGETLB 0x80000 /* create a huge page mapping */ +#ifdef TARGET_ABI_IRIX +#define TARGET_MAP_AUTOGROW 0x40 +#endif #elif defined(TARGET_PPC) #define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ @@ -1392,6 +1476,19 @@ struct target_winsize { #define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */ #define TARGET_MAP_STACK 0x40000 /* ignored */ #define TARGET_MAP_HUGETLB 0x80000 /* create a huge page mapping */ +#elif defined TARGET_ABI_SOLARIS +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define TARGET_MAP_ANONYMOUS 0x0100 /* don't use a file */ +#define TARGET_MAP_GROWSDOWN 0 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x0400 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x0040 /* don't check for reservations */ +#define TARGET_MAP_POPULATE 0 /* populate (prefault) pagetables */ +#define TARGET_MAP_NONBLOCK 0 /* do not block on IO */ +#define TARGET_MAP_UNINITIALIZED 0 /* for anonymous mmap, memory could be uninitialized */ +#define TARGET_MAP_STACK 0 /* ignored */ +#define TARGET_MAP_HUGETLB 0 /* create a huge page mapping */ #else #define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ @@ -1504,6 +1601,56 @@ struct target_eabi_stat64 { } QEMU_PACKED; #endif +#elif defined(TARGET_ABI_SOLARIS) + +struct target_stat { + abi_ulong st_dev; + abi_long st_pad1[3]; + abi_ulong st_ino; + abi_uint st_mode; + abi_uint st_nlink; + abi_int st_uid; + abi_int st_gid; + abi_ulong st_rdev; + abi_long st_pad2[2]; + abi_long st_size; + abi_long st_pad3; + abi_long target_st_atime; + abi_ulong __unused1; + abi_long target_st_mtime; + abi_ulong __unused2; + abi_long target_st_ctime; + abi_ulong __unused3; + abi_int st_blksize; + int64_t st_blocks; + char st_fstype[16]; + abi_long __unused4[8]; +}; + +#define TARGET_HAS_STRUCT_STAT64 +struct target_stat64 { + abi_ulong st_dev; + abi_long st_pad1[3]; + uint64_t st_ino; + abi_uint st_mode; + abi_uint st_nlink; + abi_int st_uid; + abi_int st_gid; + abi_ulong st_rdev; + abi_long st_pad2[2]; + int64_t st_size; + abi_long target_st_atime; + abi_ulong __unused1; + abi_long target_st_mtime; + abi_ulong __unused2; + abi_long target_st_ctime; + abi_ulong __unused3; + abi_int st_blksize; + int64_t st_blocks; + char st_fstype[16]; + abi_long __unused4[8]; +}; + #elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) struct target_stat { unsigned int st_dev; @@ -1583,7 +1730,7 @@ struct target_stat64 { unsigned char __pad0[6]; unsigned short st_dev; - uint64_t st_ino; + uint64_t st_ino; unsigned int st_mode; unsigned int st_nlink; @@ -1597,6 +1744,7 @@ struct target_stat64 { unsigned char __pad3[8]; int64_t st_size; + unsigned int st_blksize; unsigned char __pad4[8]; @@ -1787,13 +1935,87 @@ struct target_stat64 { unsigned long long st_ino; } QEMU_PACKED; +#elif defined (TARGET_ABI_IRIX) + +struct target_stat { + uint32_t st_dev; + abi_long st_pad0[3]; /* Reserved for st_dev expansion */ + abi_ulong st_ino; + + uint32_t st_mode; + uint32_t st_nlink; + + int32_t st_uid; + int32_t st_gid; + + uint32_t st_rdev; + abi_long st_pad1[2]; /* Reserved for st_rdev expansion */ + abi_long st_size; + abi_long st_pad2; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + int32_t target_st_atime; + abi_long target_st_atime_nsec; + + int32_t target_st_mtime; + abi_long target_st_mtime_nsec; + + int32_t target_st_ctime; + abi_long target_st_ctime_nsec; + + abi_long st_blksize; + abi_long st_blocks; + char st_fstype[16]; + abi_long st_projid; + abi_long st_pad[7]; +}; + +#define TARGET_HAS_STRUCT_STAT64 +struct target_stat64 { + uint32_t st_dev; + abi_long st_pad0[3]; /* Reserved for st_dev expansion */ + uint64_t st_ino; + + uint32_t st_mode; + uint32_t st_nlink; + + int32_t st_uid; + int32_t st_gid; + + uint32_t st_rdev; + abi_long st_pad1[2]; /* Reserved for st_rdev expansion */ + int64_t st_size; + abi_long st_pad2; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + int32_t target_st_atime; + abi_long target_st_atime_nsec; + + int32_t target_st_mtime; + abi_long target_st_mtime_nsec; + + int32_t target_st_ctime; + abi_long target_st_ctime_nsec; + + abi_long st_blksize; + int64_t st_blocks; + char st_fstype[16]; + abi_long st_projid; + abi_long st_pad[7]; +}; + #elif defined(TARGET_ABI_MIPSN64) /* The memory layout is the same as of struct stat64 of the 32-bit kernel. */ struct target_stat { unsigned int st_dev; unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ - abi_ulong st_ino; unsigned int st_mode; @@ -1804,7 +2026,6 @@ struct target_stat { unsigned int st_rdev; unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ - abi_ulong st_size; /* @@ -1822,32 +2043,80 @@ struct target_stat { unsigned int st_blksize; unsigned int st_pad2; - abi_ulong st_blocks; }; #elif defined(TARGET_ABI_MIPSN32) struct target_stat { - abi_ulong st_dev; - abi_ulong st_pad0[3]; /* Reserved for st_dev expansion */ - uint64_t st_ino; - unsigned int st_mode; - unsigned int st_nlink; - int st_uid; - int st_gid; - abi_ulong st_rdev; - abi_ulong st_pad1[3]; /* Reserved for st_rdev expansion */ - int64_t st_size; - abi_long target_st_atime; - abi_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */ - abi_long target_st_mtime; - abi_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */ - abi_long target_st_ctime; - abi_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */ - abi_ulong st_blksize; - abi_ulong st_pad2; - int64_t st_blocks; + unsigned st_dev; + int st_pad0[3]; /* Reserved for network id */ + unsigned int st_ino; + unsigned int st_mode; + unsigned int st_nlink; + int st_uid; + int st_gid; + unsigned st_rdev; + unsigned int st_pad1[2]; + unsigned int st_size; + unsigned int st_pad2; + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + unsigned int target_st_atime; + unsigned int target_st_atime_nsec; + unsigned int target_st_mtime; + unsigned int target_st_mtime_nsec; + unsigned int target_st_ctime; + unsigned int target_st_ctime_nsec; + unsigned int st_blksize; + unsigned int st_blocks; + unsigned int st_pad3[14]; +}; + +/* + * This matches struct stat64 in glibc2.1, hence the absolutely insane + * amounts of padding around dev_t's. The memory layout is the same as of + * struct stat of the 64-bit kernel. + */ + +#define TARGET_HAS_STRUCT_STAT64 +struct target_stat64 { + unsigned int st_dev; + unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ + + uint64_t st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + int st_uid; + int st_gid; + + unsigned int st_rdev; + + unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ + + int st_size; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + int target_st_atime; + unsigned int target_st_atime_nsec; /* Reserved for st_atime expansion */ + + int target_st_mtime; + unsigned int target_st_mtime_nsec; /* Reserved for st_mtime expansion */ + + int target_st_ctime; + unsigned int target_st_ctime_nsec; /* Reserved for st_ctime expansion */ + + unsigned int st_blksize; + + int st_blocks; + unsigned int st_pad2; }; #elif defined(TARGET_ABI_MIPSO32) @@ -2214,7 +2483,11 @@ typedef struct { #ifdef TARGET_MIPS #ifdef TARGET_ABI_MIPSN32 struct target_statfs { +#ifdef TARGET_ABI_IRIX + short f_type; +#else int32_t f_type; +#endif int32_t f_bsize; int32_t f_frsize; /* Fragment size - unsupported */ int32_t f_blocks; @@ -2230,7 +2503,11 @@ struct target_statfs { }; #else struct target_statfs { +#ifdef TARGET_ABI_IRIX + short f_type; +#else abi_long f_type; +#endif abi_long f_bsize; abi_long f_frsize; /* Fragment size - unsupported */ abi_long f_blocks; @@ -2247,10 +2524,18 @@ struct target_statfs { #endif struct target_statfs64 { +#ifdef TARGET_ABI_IRIX + short f_type; + short __pad1; + uint32_t f_bsize; + uint32_t f_frsize; /* Fragment size - unsupported */ + uint32_t __pad2; +#else uint32_t f_type; uint32_t f_bsize; uint32_t f_frsize; /* Fragment size - unsupported */ uint32_t __pad; +#endif uint64_t f_blocks; uint64_t f_bfree; uint64_t f_files; @@ -2361,12 +2646,45 @@ struct target_statfs64 { #define TARGET_F_SETLKW 9 #define TARGET_F_SETOWN 5 /* for sockets. */ #define TARGET_F_GETOWN 6 /* for sockets. */ +#define TARGET_F_SETOWN_EX 15 +#define TARGET_F_GETOWN_EX 16 +#define TARGET_F_SETSIG 10 /* for sockets. */ +#define TARGET_F_GETSIG 11 /* for sockets. */ #define TARGET_F_RDLCK 1 #define TARGET_F_WRLCK 2 #define TARGET_F_UNLCK 8 #define TARGET_F_EXLCK 16 #define TARGET_F_SHLCK 32 +#elif defined(TARGET_ABI_IRIX) +#define TARGET_F_GETLK 14 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 +#define TARGET_F_SETOWN 23 /* for sockets. */ +#define TARGET_F_GETOWN 24 /* for sockets. */ +#define TARGET_F_ALLOCSP 10 +#define TARGET_F_FREESP 11 +#define TARGET_F_ALLOCSP64 36 +#define TARGET_F_FREESP64 37 + +#define TARGET_F_RDLCK 1 +#define TARGET_F_WRLCK 2 +#define TARGET_F_UNLCK 3 +#elif defined(TARGET_ABI_SOLARIS) +#define TARGET_F_GETLK 14 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 +#define TARGET_F_SETOWN 23 /* for sockets. */ +#define TARGET_F_GETOWN 24 /* for sockets. */ +#define TARGET_F_ALLOCSP 10 +#define TARGET_F_FREESP 11 +#define TARGET_F_ALLOCSP64 28 +#define TARGET_F_FREESP64 27 +#define TARGET_F_DUP2FD 9 + +#define TARGET_F_RDLCK 1 +#define TARGET_F_WRLCK 2 +#define TARGET_F_UNLCK 3 #elif defined(TARGET_MIPS) #define TARGET_F_GETLK 14 #define TARGET_F_SETLK 6 @@ -2388,9 +2706,12 @@ struct target_statfs64 { #define TARGET_F_SETLKW 7 #define TARGET_F_SETOWN 8 /* for sockets. */ #define TARGET_F_GETOWN 9 /* for sockets. */ -#endif #define TARGET_F_SETOWN_EX 15 #define TARGET_F_GETOWN_EX 16 +#define TARGET_F_SETSIG 10 /* for sockets. */ +#define TARGET_F_GETSIG 11 /* for sockets. */ +#endif + #ifndef TARGET_F_RDLCK #define TARGET_F_RDLCK 0 @@ -2412,7 +2733,7 @@ struct target_statfs64 { #define TARGET_F_GETSIG 11 /* for sockets. */ #endif -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_ABI_SOLARIS) #define TARGET_F_GETLK64 33 /* using 'struct flock64' */ #define TARGET_F_SETLK64 34 #define TARGET_F_SETLKW64 35 @@ -2486,6 +2807,23 @@ struct target_statfs64 { #define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ #define TARGET_O_LARGEFILE 0200000 #define TARGET_O_DIRECT 0400000 /* direct disk access hint */ +#elif defined (TARGET_ABI_SOLARIS) +#define TARGET_O_APPEND 0x0008 +#define TARGET_O_CREAT 0x0100 /* not fcntl */ +#define TARGET_O_NDELAY 0x0004 +#define TARGET_O_NONBLOCK 0x0080 +#define TARGET_O_LARGEFILE 0x2000 +#define TARGET_O_DSYNC 0x0040 +#define TARGET_O_TRUNC 0x0200 /* not fcntl */ +#define TARGET_O_EXCL 0x0400 /* not fcntl */ +#define TARGET_O_NOCTTY 0x0800 /* not fcntl */ +#define TARGET_O_CLOEXEC 0x800000 +#define TARGET___O_SYNC 0x0010 +#define TARGET_O_NOFOLLOW 0x20000 +#define TARGET_FASYNC 0 +#define TARGET_O_DIRECT 0 +#define TARGET_O_NOATIME 0 +#define TARGET_O_PATH 0 #elif defined (TARGET_SPARC) #define TARGET_O_APPEND 0x0008 #define TARGET_FASYNC 0x0040 /* fcntl, for BSD compatibility */ @@ -2579,11 +2917,13 @@ struct target_flock { short l_whence; abi_long l_start; abi_long l_len; -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_ABI_IRIX) abi_long l_sysid; +#elif defined(TARGET_ABI_SOLARIS) + abi_int l_sysid; #endif int l_pid; -#if defined(TARGET_MIPS) +#if defined TARGET_MIPS || defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS abi_long pad[4]; #endif }; @@ -2598,6 +2938,11 @@ struct target_flock64 { #endif abi_llong l_start; abi_llong l_len; +#if defined(TARGET_MIPS) || defined(TARGET_ABI_IRIX) + abi_long l_sysid; +#elif defined(TARGET_ABI_SOLARIS) + abi_int l_sysid; +#endif int l_pid; } QEMU_PACKED; @@ -2898,9 +3243,18 @@ typedef int32_t target_timer_t; / sizeof(int32_t)) struct target_sigevent { +#ifdef TARGET_ABI_IRIX + int sigev_notify; + struct { + int sigev_signo; + abi_ulong sigev_nifunc; + }; + target_sigval_t sigev_value; +#else target_sigval_t sigev_value; abi_int sigev_signo; abi_int sigev_notify; +#endif union { abi_int _pad[TARGET_SIGEV_PAD_SIZE]; abi_int _tid; @@ -2952,4 +3306,168 @@ struct target_user_cap_data { /* Return size of the log buffer */ #define TARGET_SYSLOG_ACTION_SIZE_BUFFER 10 +#if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS +struct target_statvfs { + abi_ulong f_bsize; /* fundamental file system block size */ + abi_ulong f_frsize; /* fragment size */ + abi_ulong f_blocks; /* total # of blocks of f_frsize on fs */ + abi_ulong f_bfree; /* total # of free blocks of f_frsize */ + abi_ulong f_bavail; /* # of free blocks avail to non-superuser */ + abi_ulong f_files; /* total # of file nodes (inodes) */ + abi_ulong f_ffree; /* total # of free file nodes */ + abi_ulong f_favail; /* # of free nodes avail to non-superuser */ + abi_ulong f_fsid; /* file system id (dev for now) */ + uint32_t f_pad0[4]; + abi_ulong f_flag; /* bit-mask of flags */ + abi_ulong f_namemax; /* maximum file name length */ + uint32_t f_pad1[24]; /* reserved for future expansion */ +}; + +struct target_statvfs64 { + abi_ulong f_bsize; /* fundamental file system block size */ + abi_ulong f_frsize; /* fragment size */ + uint64_t f_blocks; /* total # of blocks of f_frsize on fs */ + uint64_t f_bfree; /* total # of free blocks of f_frsize */ + uint64_t f_bavail; /* # of free blocks avail to non-superuser */ + uint64_t f_files; /* total # of file nodes (inodes) */ + uint64_t f_ffree; /* total # of free file nodes */ + uint64_t f_favail; /* # of free nodes avail to non-superuser */ + abi_ulong f_fsid; /* file system id (dev for now) */ + uint32_t f_pad0[4]; + abi_ulong f_flag; /* bit-mask of flags */ + abi_ulong f_namemax; /* maximum file name length */ + uint32_t f_pad1[24]; /* reserved for future expansion */ +}; + +struct target_utsname { + char sysname[257]; + char nodename[257]; + char release[257]; + char version[257]; + char machine[257]; +#ifdef TARGET_ABI_IRIX + char reserved[257][8]; +#endif +}; + +#define TARGET_P_PID 0 +#define TARGET_P_PGID 2 +#define TARGET_P_ALL 7 + +/* wait flags */ +#define TARGET_WEXITED 0001 +#define TARGET_WSTOPPED 0004 +#define TARGET_WCONTINUED 0010 +#define TARGET_WNOHANG 0100 +#define TARGET_WNOWAIT 0200 + +#define TARGET_STAT64_VER 3 + +/* common sem/shm/msg definitions */ +#define TARGET_IPC_RMID 10 +#define TARGET_IPC_SET 11 +#define TARGET_IPC_STAT 12 + +#define TARGET_IPC_CREAT 0001000 +#define TARGET_IPC_EXCL 0002000 +#define TARGET_IPC_NOWAIT 0004000 + +/* sem function definitions */ +#define TARGET_SEM_GETNCNT 3 +#define TARGET_SEM_GETPID 4 +#define TARGET_SEM_GETVAL 5 +#define TARGET_SEM_GETALL 6 +#define TARGET_SEM_GETZCNT 7 +#define TARGET_SEM_SETVAL 8 +#define TARGET_SEM_SETALL 9 + +/* shm function definitions */ +#define TARGET_SHM_LOCK 3 +#define TARGET_SHM_UNLOCK 4 + +#define TARGET_SHM_RDONLY 010000 +#define TARGET_SHM_RND 020000 + +/* msg function definitions */ +#define TARGET_MSG_NOERROR 010000 +#endif + +#ifdef TARGET_ABI_IRIX +/* usync interface - undocumented by SGI, so there's some guesswork :-( */ +struct target_usync { + abi_int u_magic; /* 1002 in all cases? */ + uint64_t u_sync; /* pointer to sync object */ + uint16_t u_type; /* type of sync object? Either 1 or 2 */ + uint16_t u_flags; /* e.g. timeout flag for timed wait */ + abi_int u_unknown1[4]; /* some signal stuff? */ + uint64_t u_lock; /* pointer to mutex for cond_wait */ + uint64_t u_sec; /* timeout for cond_wait, tv_sec */ + uint64_t u_nsec; /* timeout for cond_wait, tv_nsec */ + abi_int u_unknown2[6]; +}; + +#define TARGET_US_TIMEOUT 0x00000004 + +/* nsproc interface - structure from sys/prctl.h */ +struct target_prthread { +#ifdef TARGET_ABI_MIPSN32 + abi_uint prt_entry; + abi_uint prt_arg; + abi_uint prt_flags; + abi_uint prt_stkptr; +#else + abi_ulong prt_entry; + abi_ulong prt_arg; + abi_uint prt_flags; + abi_ulong prt_stkptr; +#endif + abi_int prt_stklen; +}; + +/* sproc flags */ +#define TARGET_PR_SPROC 0x00000001 +#define TARGET_PR_SFDS 0x00000002 +#define TARGET_PR_SDIR 0x00000004 +#define TARGET_PR_SADDR 0x00000040 +#define TARGET_PR_SALL 0x0000007f +#define TARGET_PR_BLOCK 0x01000000 +#endif + +#ifdef TARGET_ABI_SOLARIS +#define TARGET_E_OK 8 + +#define TARGET_PC_LINK_MAX 1 +#define TARGET_PC_MAX_CANON 2 +#define TARGET_PC_MAX_INPUT 3 +#define TARGET_PC_NAME_MAX 4 +#define TARGET_PC_PATH_MAX 5 +#define TARGET_PC_PIPE_BUF 6 +#define TARGET_PC_NO_TRUNC 7 +#define TARGET_PC_VDISABLE 8 +#define TARGET_PC_CHOWN_RESTRICTED 9 +#define TARGET_PC_ASYNC_IO 10 +#define TARGET_PC_PRIO_IO 11 +#define TARGET_PC_SYNC_IO 12 +#define TARGET_PC_ALLOC_SIZE_MIN 13 +#define TARGET_PC_REC_INCR_XFER_SIZE 14 +#define TARGET_PC_REC_MAX_XFER_SIZE 15 +#define TARGET_PC_REC_MIN_XFER_SIZE 16 +#define TARGET_PC_REC_XFER_ALIGN 17 +#define TARGET_PC_SYMLINK_MAX 18 +#define TARGET_PC_2_SYMLINKS 19 +#else +#define TARGET_PC_LINK_MAX 1 +#define TARGET_PC_MAX_CANON 2 +#define TARGET_PC_MAX_INPUT 3 +#define TARGET_PC_NAME_MAX 4 +#define TARGET_PC_PATH_MAX 5 +#define TARGET_PC_PIPE_BUF 6 +#define TARGET_PC_NO_TRUNC 8 +#define TARGET_PC_VDISABLE 9 +#define TARGET_PC_CHOWN_RESTRICTED 7 +#define TARGET_PC_ASYNC_IO 64 +#define TARGET_PC_PRIO_IO 11 +#define TARGET_PC_SYNC_IO 10 +#endif + #endif diff --git a/target/mips/Makefile.objs b/target/mips/Makefile.objs index 651f36f517..5e8303d784 100644 --- a/target/mips/Makefile.objs +++ b/target/mips/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o -obj-y += gdbstub.o msa_helper.o mips-semi.o +obj-y += gdbstub.o msa_helper.o mips-semi.o irix_helper.o obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target/mips/helper.h b/target/mips/helper.h index 5f492348dd..2d3f1a6bfa 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -956,3 +956,26 @@ MSALDST_PROTO(d) #undef MSALDST_PROTO DEF_HELPER_3(cache, void, env, tl, i32) + +#ifdef TARGET_ABI_IRIX +DEF_HELPER_2(irix_prda_ld_8, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_16, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_32, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_64, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_8s, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_16s, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_32s, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_16b, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_32b, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_64b, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_16sb, i64, tl, env) +DEF_HELPER_2(irix_prda_ld_32sb, i64, tl, env) + +DEF_HELPER_3(irix_prda_st_8, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_16, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_32, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_64, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_16b, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_32b, void, i64, tl, env) +DEF_HELPER_3(irix_prda_st_64b, void, i64, tl, env) +#endif diff --git a/target/mips/irix_helper.c b/target/mips/irix_helper.c new file mode 100644 index 0000000000..c14f0924fc --- /dev/null +++ b/target/mips/irix_helper.c @@ -0,0 +1,164 @@ +/* + * IRIX PRDA access helper functions for QEMU + * + * Copyright (c) 2015 Kai-Uwe Bloem + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" + + +#ifdef TARGET_ABI_IRIX +/* argh, ugly! need TaskState here to access PRDA storage */ +#include + +#define DEBUG(x) //x + +static inline void *prda_ptr(CPUMIPSState *env, target_ulong addr) +{ + TaskState *ts = ENV_GET_CPU(env)->opaque; + return &ts->prda[addr-0x200000]; +} + +uint64_t helper_irix_prda_ld_8(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldub_p(prda_ptr(env, addr)); + DEBUG(printf("ld8(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} + +uint64_t helper_irix_prda_ld_16(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = lduw_p(prda_ptr(env, addr)); + DEBUG(printf("ld16(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_32(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = (uint32_t)ldl_p(prda_ptr(env, addr)); + DEBUG(printf("ld32(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_64(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldq_p(prda_ptr(env, addr)); + DEBUG(printf("ld64(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} + +uint64_t helper_irix_prda_ld_8s(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldsb_p(prda_ptr(env, addr)); + DEBUG(printf("ld8s(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} + +uint64_t helper_irix_prda_ld_16s(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldsw_p(prda_ptr(env, addr)); + DEBUG(printf("ld16s(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_32s(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = (int32_t)ldl_p(prda_ptr(env, addr)); + DEBUG(printf("ld32s(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} + +uint64_t helper_irix_prda_ld_16b(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = lduw_be_p(prda_ptr(env, addr)); + DEBUG(printf("ld16b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_32b(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = (uint32_t)ldl_be_p(prda_ptr(env, addr)); + DEBUG(printf("ld32b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_64b(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldq_be_p(prda_ptr(env, addr)); + DEBUG(printf("ld64b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_16sb(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = ldsw_be_p(prda_ptr(env, addr)); + DEBUG(printf("ld16sb(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} +uint64_t helper_irix_prda_ld_32sb(target_ulong addr, CPUMIPSState *env) +{ + uint64_t ret; + ret = (int32_t)ldl_be_p(prda_ptr(env, addr)); + DEBUG(printf("ld32sb(%p) addr=%lx val=%lx\n",env,(long)addr,(long)ret)); + return ret; +} + + +void helper_irix_prda_st_8(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st8(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stb_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_16(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st16(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stw_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_32(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st32(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stl_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_64(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st64(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stq_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_16b(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st16b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stw_be_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_32b(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st32b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stl_be_p(prda_ptr(env, addr), val); +} +void helper_irix_prda_st_64b(uint64_t val, target_ulong addr, CPUMIPSState *env) +{ + DEBUG(printf("st64b(%p) addr=%lx val=%lx\n",env,(long)addr,(long)val)); + stq_be_p(prda_ptr(env, addr), val); +} + +#endif diff --git a/target/mips/translate.c b/target/mips/translate.c index d05ee67e63..675e30c6fd 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -2142,6 +2142,187 @@ static target_ulong pc_relative_pc (DisasContext *ctx) return pc; } +#ifdef TARGET_ABI_IRIX +static void (*irix_prda_helpers_ld[MO_SSIZE|MO_BSWAP])(TCGv_i64 ret, TCGv addr, TCGv_ptr env) = { + [MO_UB] = gen_helper_irix_prda_ld_8, + [MO_UW] = gen_helper_irix_prda_ld_16, + [MO_UL] = gen_helper_irix_prda_ld_32, + [MO_Q] = gen_helper_irix_prda_ld_64, + [MO_SB] = gen_helper_irix_prda_ld_8s, + [MO_SW] = gen_helper_irix_prda_ld_16s, + [MO_SL] = gen_helper_irix_prda_ld_32s, + [MO_UW|MO_BSWAP] = gen_helper_irix_prda_ld_16b, + [MO_UL|MO_BSWAP] = gen_helper_irix_prda_ld_32b, + [MO_Q|MO_BSWAP] = gen_helper_irix_prda_ld_64b, + [MO_SW|MO_BSWAP] = gen_helper_irix_prda_ld_16sb, + [MO_SL|MO_BSWAP] = gen_helper_irix_prda_ld_32sb, +}; + +static void (*irix_prda_helpers_st[MO_SSIZE|MO_BSWAP])(TCGv_i64 val, TCGv addr, TCGv_ptr env) = { + [MO_UB] = gen_helper_irix_prda_st_8, + [MO_UW] = gen_helper_irix_prda_st_16, + [MO_UL] = gen_helper_irix_prda_st_32, + [MO_Q] = gen_helper_irix_prda_st_64, + [MO_UW|MO_BSWAP] = gen_helper_irix_prda_st_16b, + [MO_UL|MO_BSWAP] = gen_helper_irix_prda_st_32b, + [MO_Q|MO_BSWAP] = gen_helper_irix_prda_st_64b, +}; + +extern int irix_emulate_prda; + +static void tcg_gen_irix_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) +{ + if (irix_emulate_prda) { + TCGv t0, t1; + TCGv_i32 t2 = tcg_temp_local_new_i32(); + TCGv_i64 t3; + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + t1 = tcg_temp_local_new(); + tcg_gen_mov_tl(t1, addr); + + t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, t1, TARGET_PAGE_BITS); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x200000 >> TARGET_PAGE_BITS, l1); + tcg_temp_free(t0); + + assert(irix_prda_helpers_ld[memop] != NULL); + t3 = tcg_temp_new_i64(); + (irix_prda_helpers_ld[memop])(t3, t1, cpu_env); + tcg_gen_extrl_i64_i32(t2, t3); + tcg_temp_free_i64(t3); + tcg_gen_br(l2); + + gen_set_label(l1); + tcg_gen_qemu_ld_i32(t2, t1, idx, memop); + + gen_set_label(l2); + tcg_gen_mov_tl(addr, t1); + tcg_gen_mov_i32(val, t2); + tcg_temp_free(t1); + tcg_temp_free_i32(t2); + } else + tcg_gen_qemu_ld_i32(val, addr, idx, memop); +} +static void tcg_gen_irix_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) +{ + if (irix_emulate_prda) { + TCGv t0, t1; + TCGv_i64 t2 = tcg_temp_local_new_i64(); + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + t1 = tcg_temp_local_new(); + tcg_gen_mov_tl(t1, addr); + + t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, t1, TARGET_PAGE_BITS); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x200000 >> TARGET_PAGE_BITS, l1); + tcg_temp_free(t0); + + assert(irix_prda_helpers_ld[memop] != NULL); + (irix_prda_helpers_ld[memop])(t2, t1, cpu_env); + tcg_gen_br(l2); + + gen_set_label(l1); + tcg_gen_qemu_ld_i64(t2, t1, idx, memop); + + gen_set_label(l2); + tcg_gen_mov_tl(addr, t1); + tcg_gen_mov_i64(val, t2); + tcg_temp_free(t1); + tcg_temp_free_i64(t2); + } else + tcg_gen_qemu_ld_i64(val, addr, idx, memop); +} +#define tcg_gen_qemu_ld_i32(v,a,i,m) tcg_gen_irix_ld_i32(v,a,i,m) +#define tcg_gen_qemu_ld_i64(v,a,i,m) tcg_gen_irix_ld_i64(v,a,i,m) + +#undef tcg_gen_qemu_ld_tl +#if TARGET_LONG_BITS == 32 +#define tcg_gen_qemu_ld_tl(v,a,i,m) tcg_gen_irix_ld_i32(v,a,i,m) +#else +#define tcg_gen_qemu_ld_tl(v,a,i,m) tcg_gen_irix_ld_i64(v,a,i,m) +#endif + +static void tcg_gen_irix_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) +{ + if (irix_emulate_prda) { + TCGv t0, t1; + TCGv_i32 t2; + TCGv_i64 t3; + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + t1 = tcg_temp_local_new(); + tcg_gen_mov_tl(t1, addr); + t2 = tcg_temp_local_new_i32(); + tcg_gen_mov_i32(t2, val); + + t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, t1, TARGET_PAGE_BITS); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x200000 >> TARGET_PAGE_BITS, l1); + tcg_temp_free(t0); + + assert(irix_prda_helpers_st[memop] != NULL); + t3 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t3, t2); + (irix_prda_helpers_st[memop])(t3, t1, cpu_env); + tcg_temp_free_i64(t3); + tcg_gen_br(l2); + + gen_set_label(l1); + tcg_gen_qemu_st_i32(t2, t1, idx, memop); + + gen_set_label(l2); + tcg_temp_free(t1); + tcg_temp_free_i32(t2); + } else + tcg_gen_qemu_st_i32(val, addr, idx, memop); +} +static void tcg_gen_irix_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) +{ + if (irix_emulate_prda) { + TCGv t0, t1; + TCGv_i64 t2; + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + t1 = tcg_temp_local_new(); + tcg_gen_mov_tl(t1, addr); + t2 = tcg_temp_local_new_i64(); + tcg_gen_mov_i64(t2, val); + + t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, t1, TARGET_PAGE_BITS); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x200000 >> TARGET_PAGE_BITS, l1); + tcg_temp_free(t0); + + assert(irix_prda_helpers_st[memop] != NULL); + (irix_prda_helpers_st[memop])(t2, t1, cpu_env); + tcg_gen_br(l2); + + gen_set_label(l1); + tcg_gen_qemu_st_i64(t2, t1, idx, memop); + + gen_set_label(l2); + tcg_temp_free(t1); + tcg_temp_free_i64(t2); + } else + tcg_gen_qemu_st_i64(val, addr, idx, memop); +} +#define tcg_gen_qemu_st_i32(v,a,i,m) tcg_gen_irix_st_i32(v,a,i,m) +#define tcg_gen_qemu_st_i64(v,a,i,m) tcg_gen_irix_st_i64(v,a,i,m) + +#undef tcg_gen_qemu_st_tl +#if TARGET_LONG_BITS == 32 +#define tcg_gen_qemu_st_tl(v,a,i,m) tcg_gen_irix_st_i32(v,a,i,m) +#else +#define tcg_gen_qemu_st_tl(v,a,i,m) tcg_gen_irix_st_i64(v,a,i,m) +#endif +#endif + /* Load */ static void gen_ld(DisasContext *ctx, uint32_t opc, int rt, int base, int16_t offset) @@ -2177,7 +2358,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, gen_store_gpr(t0, rt); break; case OPC_LDL: - t1 = tcg_temp_new(); + t1 = tcg_temp_local_new(); /*X*/ /* Do a byte access to possibly trigger a page fault with the unaligned address. */ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); @@ -2199,7 +2380,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, gen_store_gpr(t0, rt); break; case OPC_LDR: - t1 = tcg_temp_new(); + t1 = tcg_temp_local_new(); /*X*/ /* Do a byte access to possibly trigger a page fault with the unaligned address. */ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); @@ -2278,7 +2459,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, mem_idx = MIPS_HFLAG_UM; /* fall through */ case OPC_LWL: - t1 = tcg_temp_new(); + t1 = tcg_temp_local_new(); /*X*/ /* Do a byte access to possibly trigger a page fault with the unaligned address. */ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); @@ -2304,7 +2485,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, mem_idx = MIPS_HFLAG_UM; /* fall through */ case OPC_LWR: - t1 = tcg_temp_new(); + t1 = tcg_temp_local_new(); /*X*/ /* Do a byte access to possibly trigger a page fault with the unaligned address. */ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); diff --git a/target/mips/translate_init.c b/target/mips/translate_init.c index c7ba6ee5f9..d1e23cacd2 100644 --- a/target/mips/translate_init.c +++ b/target/mips/translate_init.c @@ -636,6 +636,8 @@ const mips_def_t mips_defs[] = .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x89 << FCR0_PRID) | (0x0 << FCR0_REV), + .CP1_fcr31 = 0, + .CP1_fcr31_rw_bitmask = 0xFF83FFFF, .SEGBITS = 42, .PABITS = 36, .insn_flags = CPU_MIPS64R2, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index ff6ed91f9a..bfee751f71 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -41,9 +41,9 @@ static void sparc_cpu_reset(CPUState *s) #ifndef TARGET_SPARC64 env->wim = 1; #endif - env->regwptr = env->regbase + (env->cwp * 16); CC_OP = CC_OP_FLAGS; #if defined(CONFIG_USER_ONLY) + env->cwp = env->nwindows - 1; #ifdef TARGET_SPARC64 env->cleanwin = env->nwindows - 2; env->cansave = env->nwindows - 2; @@ -74,6 +74,7 @@ static void sparc_cpu_reset(CPUState *s) env->npc = env->pc + 4; #endif env->cache_control = 0; + env->regwptr = env->regbase + (env->cwp * 16); } static bool sparc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 9724134a5b..4b67d3c5f6 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -820,4 +820,9 @@ static inline bool tb_am_enabled(int tb_flags) #endif } +/* main.c */ +void flush_windows(CPUSPARCState *env); + +#include "exec/exec-all.h" + #endif diff --git a/util/path.c b/util/path.c index 7f9fc272fb..c720f268cc 100644 --- a/util/path.c +++ b/util/path.c @@ -15,13 +15,17 @@ struct pathelem char *name; /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ char *pathname; + /* Entry type */ + unsigned char type; + /* Parent */ struct pathelem *parent; /* Children */ - unsigned int num_entries; - struct pathelem *entries[0]; + int num_entries; + struct pathelem **entries; }; -static struct pathelem *base; +static struct pathelem **base; +int base_count; /* First N chars of S1 match S2, and S2 is N chars long. */ static int strneq(const char *s1, unsigned int n, const char *s2) @@ -37,14 +41,15 @@ static int strneq(const char *s1, unsigned int n, const char *s2) static struct pathelem *add_entry(struct pathelem *root, const char *name, unsigned type); -static struct pathelem *new_entry(const char *root, - struct pathelem *parent, - const char *name) +static struct pathelem *new_entry(const char *root, struct pathelem *parent, + const char *name, unsigned char type) { struct pathelem *new = g_malloc(sizeof(*new)); new->name = g_strdup(name); new->pathname = g_strdup_printf("%s/%s", root, name); - new->num_entries = 0; + new->type = type; + new->entries = NULL; + new->num_entries = -1; return new; } @@ -64,6 +69,7 @@ static struct pathelem *add_dir_maybe(struct pathelem *path) { DIR *dir; + path->num_entries = 0; if ((dir = opendir(path->pathname)) != NULL) { struct dirent *dirent; @@ -84,22 +90,18 @@ static struct pathelem *add_entry(struct pathelem *root, const char *name, root->num_entries++; - root = g_realloc(root, sizeof(*root) - + sizeof(root->entries[0])*root->num_entries); + root->entries = g_realloc(root->entries, + sizeof(root->entries[0])*root->num_entries); e = &root->entries[root->num_entries-1]; - *e = new_entry(root->pathname, root, name); - if (is_dir_maybe(type)) { - *e = add_dir_maybe(*e); - } - + *e = new_entry(root->pathname, root, name, type); return root; } /* This needs to be done after tree is stabilized (ie. no more reallocs!). */ static void set_parents(struct pathelem *child, struct pathelem *parent) { - unsigned int i; + int i; child->parent = parent; for (i = 0; i < child->num_entries; i++) @@ -108,9 +110,9 @@ static void set_parents(struct pathelem *child, struct pathelem *parent) /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ static const char * -follow_path(const struct pathelem *cursor, const char *name) +follow_path(struct pathelem *cursor, const char *name) { - unsigned int i, namelen; + int i, namelen; name += strspn(name, "/"); namelen = strcspn(name, "/"); @@ -124,6 +126,20 @@ follow_path(const struct pathelem *cursor, const char *name) if (strneq(name, namelen, ".")) return follow_path(cursor, name + namelen); + if (cursor->num_entries < 0) { + static char path[255]; + if (is_dir_maybe(cursor->type)) + add_dir_maybe(cursor); + else if (cursor->type == DT_LNK && + readlink(cursor->pathname, path, sizeof(path)) >= 0) { + if (*path != '/') + add_dir_maybe(cursor); + } else + cursor->num_entries = 0; + if (cursor->num_entries > 0) + set_parents(cursor, cursor->parent); + } + for (i = 0; i < cursor->num_entries; i++) if (strneq(name, namelen, cursor->entries[i]->name)) return follow_path(cursor->entries[i], name + namelen); @@ -132,46 +148,64 @@ follow_path(const struct pathelem *cursor, const char *name) return NULL; } -void init_paths(const char *prefix) +void init_paths(const char *prefix_list) { char pref_buf[PATH_MAX]; + int count = base_count; + char *list, *prefix, *p; - if (prefix[0] == '\0' || - !strcmp(prefix, "/")) - return; + list = g_strdup(prefix_list); - if (prefix[0] != '/') { - char *cwd = getcwd(NULL, 0); - size_t pref_buf_len = sizeof(pref_buf); + for (p = list; *p; p++) count += (*p == ':'); + base = g_realloc(base, sizeof(*base) * (count + 1)); - if (!cwd) - abort(); - pstrcpy(pref_buf, sizeof(pref_buf), cwd); - pstrcat(pref_buf, pref_buf_len, "/"); - pstrcat(pref_buf, pref_buf_len, prefix); - free(cwd); - } else - pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1); + for (prefix = strtok(list, ":"); prefix; prefix = strtok(NULL, ":")) { + if (prefix[0] == '\0' || !strcmp(prefix, "/")) + continue; - base = new_entry("", NULL, pref_buf); - base = add_dir_maybe(base); - if (base->num_entries == 0) { - g_free(base->pathname); - g_free(base->name); - g_free(base); - base = NULL; - } else { - set_parents(base, base); + if (prefix[0] != '/') { + char *cwd = getcwd(NULL, 0); + size_t pref_buf_len = sizeof(pref_buf); + + if (!cwd) + abort(); + pstrcpy(pref_buf, sizeof(pref_buf), cwd); + pstrcat(pref_buf, pref_buf_len, "/"); + pstrcat(pref_buf, pref_buf_len, prefix); + free(cwd); + } else + pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1); + + base[base_count] = new_entry("", NULL, pref_buf, DT_DIR); + base[base_count] = add_dir_maybe(base[base_count]); + + if (base[base_count]->num_entries <= 0) { + g_free(base[base_count]->pathname); + g_free(base[base_count]->name); + g_free(base[base_count]); + } else { + set_parents(base[base_count], base[base_count]); + base_count ++; + } } + g_free(list); } /* Look for path in emulation dir, otherwise return name. */ const char *path(const char *name) { + const char *p; + int i; + /* Only do absolute paths: quick and dirty, but should mostly be OK. Could do relative by tracking cwd. */ if (!base || !name || name[0] != '/') return name; - return follow_path(base, name) ?: name; + for (i = 0; i < base_count; i++) { + if ((p = follow_path(base[i], name))) + return p; + } + + return name; }