From ba0e276db4b51bd2255a5d5ff8902c70d32ade40 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Dec 2009 15:56:29 -0800 Subject: [PATCH] target-alpha: Fixes for alpha-linux syscalls. 1. Add correct definitions of error numbers. 2. Implement SYS_osf_sigprocmask 3. Implement SYS_osf_get/setsysinfo for IEEE_FP_CONTROL. This last requires exposing the FPCR value to do_syscall. Since this value is actually split up into the float_status, expose routines from helper.c to access it. Finally, also add a float_exception_mask field to float_status. We don't actually use it to control delivery of exceptions to the emulator yet, but simply hold the value that we placed there when loading/storing the FPCR. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- fpu/softfloat.h | 1 + linux-user/alpha/syscall.h | 212 +++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 137 ++++++++++++++++++++++-- target-alpha/cpu.h | 49 +++++++++ target-alpha/helper.c | 77 ++++++++++++++ target-alpha/op_helper.c | 41 +------ 6 files changed, 468 insertions(+), 49 deletions(-) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 636591b04c..9d82694119 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -187,6 +187,7 @@ typedef struct float_status { signed char float_detect_tininess; signed char float_rounding_mode; signed char float_exception_flags; + signed char float_exception_mask; #ifdef FLOATX80 signed char floatx80_rounding_precision; #endif diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index 394afec56c..15a0100335 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -39,3 +39,215 @@ struct target_pt_regs { }; #define UNAME_MACHINE "alpha" + +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 11 +#undef TARGET_EAGAIN +#define TARGET_EAGAIN 35 +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 36 +#undef TARGET_EALREADY +#define TARGET_EALREADY 37 +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 38 +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 39 +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 40 +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 41 +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 42 +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 43 +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 44 +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 45 +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 46 +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 47 +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 48 +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 49 +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 50 +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 51 +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 52 +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 53 +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 54 +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 55 +#undef TARGET_EISCONN +#define TARGET_EISCONN 56 +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 57 +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 58 +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 59 +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 60 +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 61 +#undef TARGET_ELOOP +#define TARGET_ELOOP 62 +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 63 +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 64 +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 65 +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 66 +// Unused 67 +#undef TARGET_EUSERS +#define TARGET_EUSERS 68 +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 69 +#undef TARGET_ESTALE +#define TARGET_ESTALE 70 +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 71 +// Unused 72-76 +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 77 +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 78 +// Unused 79 +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 80 +#undef TARGET_EIDRM +#define TARGET_EIDRM 81 +#undef TARGET_ENOSR +#define TARGET_ENOSR 82 +#undef TARGET_ETIME +#define TARGET_ETIME 83 +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 84 +#undef TARGET_EPROTO +#define TARGET_EPROTO 85 +#undef TARGET_ENODATA +#define TARGET_ENODATA 86 +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 87 +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 88 +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 89 +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 90 +#undef TARGET_EL3RST +#define TARGET_EL3RST 91 +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 92 +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 93 +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 94 +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 95 +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 96 +#undef TARGET_EBADE +#define TARGET_EBADE 97 +#undef TARGET_EBADR +#define TARGET_EBADR 98 +#undef TARGET_EXFULL +#define TARGET_EXFULL 99 +#undef TARGET_ENOANO +#define TARGET_ENOANO 100 +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 101 +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 102 +// Unused 103 +#undef TARGET_EBFONT +#define TARGET_EBFONT 104 +#undef TARGET_ENONET +#define TARGET_ENONET 105 +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 106 +#undef TARGET_EADV +#define TARGET_EADV 107 +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 108 +#undef TARGET_ECOMM +#define TARGET_ECOMM 109 +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 110 +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 111 +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 112 +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 113 +#undef TARGET_EBADFD +#define TARGET_EBADFD 114 +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 115 +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 116 + +// Same as default 117-121 + +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 122 +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 123 +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 124 +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 125 +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 126 +#undef TARGET_ERESTART +#define TARGET_ERESTART 127 +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 128 +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 129 +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 130 +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 131 +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 132 +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 133 +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 134 +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 135 +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 136 +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 137 +#undef TARGET_ERFKILL +#define TARGET_ERFKILL 138 + +// For sys_osf_getsysinfo +#define TARGET_GSI_UACPROC 8 +#define TARGET_GSI_IEEE_FP_CONTROL 45 +#define TARGET_GSI_IEEE_STATE_AT_SIGNAL 46 +#define TARGET_GSI_PROC_TYPE 60 +#define TARGET_GSI_GET_HWRPB 101 + +// For sys_ofs_setsysinfo +#define TARGET_SSI_NVPAIRS 1 +#define TARGET_SSI_IEEE_FP_CONTROL 14 +#define TARGET_SSI_IEEE_STATE_AT_SIGNAL 15 +#define TARGET_SSI_IEEE_IGNORE_STATE_AT_SIGNAL 16 +#define TARGET_SSI_IEEE_RAISE_EXCEPTION 1001 + +#define TARGET_SSIN_UACPROC 6 + +#define TARGET_UAC_NOPRINT 1 +#define TARGET_UAC_NOFIX 2 +#define TARGET_UAC_SIGBUS 4 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e38552ca1c..1acf1f5b64 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6390,25 +6390,142 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxuid: - { - uid_t euid; - euid=geteuid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid; - } + { + uid_t euid; + euid=geteuid(); + ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid; + } ret = get_errno(getuid()); break; #endif #if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxgid: - { - uid_t egid; - egid=getegid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid; - } + { + uid_t egid; + egid=getegid(); + ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid; + } ret = get_errno(getgid()); break; #endif +#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA) + /* Alpha specific */ + case TARGET_NR_osf_getsysinfo: + ret = -TARGET_EOPNOTSUPP; + switch (arg1) { + case TARGET_GSI_IEEE_FP_CONTROL: + { + uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env); + + /* Copied from linux ieee_fpcr_to_swcr. */ + swcr = (fpcr >> 35) & SWCR_STATUS_MASK; + swcr |= (fpcr >> 36) & SWCR_MAP_DMZ; + swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV + | SWCR_TRAP_ENABLE_DZE + | SWCR_TRAP_ENABLE_OVF); + swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF + | SWCR_TRAP_ENABLE_INE); + swcr |= (fpcr >> 47) & SWCR_MAP_UMZ; + swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO; + + if (put_user_u64 (swcr, arg2)) + goto efault; + ret = 0; + } + break; + + /* case GSI_IEEE_STATE_AT_SIGNAL: + -- Not implemented in linux kernel. + case GSI_UACPROC: + -- Retrieves current unaligned access state; not much used. + case GSI_PROC_TYPE: + -- Retrieves implver information; surely not used. + case GSI_GET_HWRPB: + -- Grabs a copy of the HWRPB; surely not used. + */ + } + break; +#endif +#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA) + /* Alpha specific */ + case TARGET_NR_osf_setsysinfo: + ret = -TARGET_EOPNOTSUPP; + switch (arg1) { + case TARGET_SSI_IEEE_FP_CONTROL: + case TARGET_SSI_IEEE_RAISE_EXCEPTION: + { + uint64_t swcr, fpcr, orig_fpcr; + + if (get_user_u64 (swcr, arg2)) + goto efault; + orig_fpcr = cpu_alpha_load_fpcr (cpu_env); + fpcr = orig_fpcr & FPCR_DYN_MASK; + + /* Copied from linux ieee_swcr_to_fpcr. */ + fpcr |= (swcr & SWCR_STATUS_MASK) << 35; + fpcr |= (swcr & SWCR_MAP_DMZ) << 36; + fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV + | SWCR_TRAP_ENABLE_DZE + | SWCR_TRAP_ENABLE_OVF)) << 48; + fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF + | SWCR_TRAP_ENABLE_INE)) << 57; + fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0); + fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41; + + cpu_alpha_store_fpcr (cpu_env, fpcr); + ret = 0; + + if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) { + /* Old exceptions are not signaled. */ + fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK); + + /* If any exceptions set by this call, and are unmasked, + send a signal. */ + /* ??? FIXME */ + } + } + break; + + /* case SSI_NVPAIRS: + -- Used with SSIN_UACPROC to enable unaligned accesses. + case SSI_IEEE_STATE_AT_SIGNAL: + case SSI_IEEE_IGNORE_STATE_AT_SIGNAL: + -- Not implemented in linux kernel + */ + } + break; +#endif +#ifdef TARGET_NR_osf_sigprocmask + /* Alpha specific. */ + case TARGET_NR_osf_sigprocmask: + { + abi_ulong mask; + int how = arg1; + sigset_t set, oldset; + + switch(arg1) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -TARGET_EINVAL; + goto fail; + } + mask = arg2; + target_to_host_old_sigset(&set, &mask); + sigprocmask(arg1, &set, &oldset); + host_to_target_old_sigset(&mask, &oldset); + ret = mask; + } + break; +#endif #ifdef TARGET_NR_getgid32 case TARGET_NR_getgid32: diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index ca9dfe2458..c0dff4bb87 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -139,6 +139,53 @@ enum { FP_ROUND_DYNAMIC = 0x3, }; +/* FPCR bits */ +#define FPCR_SUM (1ULL << 63) +#define FPCR_INED (1ULL << 62) +#define FPCR_UNFD (1ULL << 61) +#define FPCR_UNDZ (1ULL << 60) +#define FPCR_DYN_SHIFT 58 +#define FPCR_DYN_MASK (3ULL << FPCR_DYN_SHIFT) +#define FPCR_IOV (1ULL << 57) +#define FPCR_INE (1ULL << 56) +#define FPCR_UNF (1ULL << 55) +#define FPCR_OVF (1ULL << 54) +#define FPCR_DZE (1ULL << 53) +#define FPCR_INV (1ULL << 52) +#define FPCR_OVFD (1ULL << 51) +#define FPCR_DZED (1ULL << 50) +#define FPCR_INVD (1ULL << 49) +#define FPCR_DNZ (1ULL << 48) +#define FPCR_DNOD (1ULL << 47) +#define FPCR_STATUS_MASK (FPCR_IOV | FPCR_INE | FPCR_UNF \ + | FPCR_OVF | FPCR_DZE | FPCR_INV) + +/* The silly software trap enables implemented by the kernel emulation. + These are more or less architecturally required, since the real hardware + has read-as-zero bits in the FPCR when the features aren't implemented. + For the purposes of QEMU, we pretend the FPCR can hold everything. */ +#define SWCR_TRAP_ENABLE_INV (1ULL << 1) +#define SWCR_TRAP_ENABLE_DZE (1ULL << 2) +#define SWCR_TRAP_ENABLE_OVF (1ULL << 3) +#define SWCR_TRAP_ENABLE_UNF (1ULL << 4) +#define SWCR_TRAP_ENABLE_INE (1ULL << 5) +#define SWCR_TRAP_ENABLE_DNO (1ULL << 6) +#define SWCR_TRAP_ENABLE_MASK ((1ULL << 7) - (1ULL << 1)) + +#define SWCR_MAP_DMZ (1ULL << 12) +#define SWCR_MAP_UMZ (1ULL << 13) +#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) + +#define SWCR_STATUS_INV (1ULL << 17) +#define SWCR_STATUS_DZE (1ULL << 18) +#define SWCR_STATUS_OVF (1ULL << 19) +#define SWCR_STATUS_UNF (1ULL << 20) +#define SWCR_STATUS_INE (1ULL << 21) +#define SWCR_STATUS_DNO (1ULL << 22) +#define SWCR_STATUS_MASK ((1ULL << 23) - (1ULL << 17)) + +#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK) + /* Internal processor registers */ /* XXX: TOFIX: most of those registers are implementation dependant */ enum { @@ -436,6 +483,8 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault void do_interrupt (CPUState *env); +uint64_t cpu_alpha_load_fpcr (CPUState *env); +void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void pal_init (CPUState *env); diff --git a/target-alpha/helper.c b/target-alpha/helper.c index fcd5841e01..a658f9782a 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -23,6 +23,83 @@ #include "cpu.h" #include "exec-all.h" +#include "softfloat.h" + +uint64_t cpu_alpha_load_fpcr (CPUState *env) +{ + uint64_t ret = 0; + int flags, mask; + + flags = env->fp_status.float_exception_flags; + ret |= (uint64_t) flags << 52; + if (flags) + ret |= FPCR_SUM; + env->ipr[IPR_EXC_SUM] &= ~0x3E; + env->ipr[IPR_EXC_SUM] |= flags << 1; + + mask = env->fp_status.float_exception_mask; + if (mask & float_flag_invalid) + ret |= FPCR_INVD; + if (mask & float_flag_divbyzero) + ret |= FPCR_DZED; + if (mask & float_flag_overflow) + ret |= FPCR_OVFD; + if (mask & float_flag_underflow) + ret |= FPCR_UNFD; + if (mask & float_flag_inexact) + ret |= FPCR_INED; + + switch (env->fp_status.float_rounding_mode) { + case float_round_nearest_even: + ret |= 2ULL << FPCR_DYN_SHIFT; + break; + case float_round_down: + ret |= 1ULL << FPCR_DYN_SHIFT; + break; + case float_round_up: + ret |= 3ULL << FPCR_DYN_SHIFT; + break; + case float_round_to_zero: + break; + } + return ret; +} + +void cpu_alpha_store_fpcr (CPUState *env, uint64_t val) +{ + int round_mode, mask; + + set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status); + + mask = 0; + if (val & FPCR_INVD) + mask |= float_flag_invalid; + if (val & FPCR_DZED) + mask |= float_flag_divbyzero; + if (val & FPCR_OVFD) + mask |= float_flag_overflow; + if (val & FPCR_UNFD) + mask |= float_flag_underflow; + if (val & FPCR_INED) + mask |= float_flag_inexact; + env->fp_status.float_exception_mask = mask; + + switch ((val >> FPCR_DYN_SHIFT) & 3) { + case 0: + round_mode = float_round_to_zero; + break; + case 1: + round_mode = float_round_down; + break; + case 2: + round_mode = float_round_nearest_even; + break; + case 3: + round_mode = float_round_up; + break; + } + set_float_rounding_mode(round_mode, &env->fp_status); +} #if defined(CONFIG_USER_ONLY) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 508272c85d..999a8ab46c 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -39,49 +39,12 @@ uint64_t helper_load_pcc (void) uint64_t helper_load_fpcr (void) { - uint64_t ret = 0; -#ifdef CONFIG_SOFTFLOAT - ret |= env->fp_status.float_exception_flags << 52; - if (env->fp_status.float_exception_flags) - ret |= 1ULL << 63; - env->ipr[IPR_EXC_SUM] &= ~0x3E: - env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1; -#endif - switch (env->fp_status.float_rounding_mode) { - case float_round_nearest_even: - ret |= 2ULL << 58; - break; - case float_round_down: - ret |= 1ULL << 58; - break; - case float_round_up: - ret |= 3ULL << 58; - break; - case float_round_to_zero: - break; - } - return ret; + return cpu_alpha_load_fpcr (env); } void helper_store_fpcr (uint64_t val) { -#ifdef CONFIG_SOFTFLOAT - set_float_exception_flags((val >> 52) & 0x3F, &FP_STATUS); -#endif - switch ((val >> 58) & 3) { - case 0: - set_float_rounding_mode(float_round_to_zero, &FP_STATUS); - break; - case 1: - set_float_rounding_mode(float_round_down, &FP_STATUS); - break; - case 2: - set_float_rounding_mode(float_round_nearest_even, &FP_STATUS); - break; - case 3: - set_float_rounding_mode(float_round_up, &FP_STATUS); - break; - } + cpu_alpha_store_fpcr (env, val); } static spinlock_t intr_cpu_lock = SPIN_LOCK_UNLOCKED;