aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-02-09 16:49:55 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-02-09 16:49:55 +0000
commitce4defa062c5e6d940f73a1013f8770f23b0f4bf (patch)
tree685dfe397fa69b4ef03be4a197644a4b6daa86f7
parentb88a38324b9cc469d6fffaecacbeb106a248a4cf (diff)
Arm Linux EABI syscall support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1756 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--linux-user/main.c6
-rw-r--r--linux-user/syscall.c149
-rw-r--r--linux-user/syscall_defs.h44
-rw-r--r--target-arm/cpu.h5
4 files changed, 171 insertions, 33 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index 56accfbb52..afcf4f4b1b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -360,6 +360,7 @@ void cpu_loop(CPUARMState *env)
case EXCP_SWI:
case EXCP_BKPT:
{
+ env->eabi = 1;
/* system call */
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
@@ -386,13 +387,14 @@ void cpu_loop(CPUARMState *env)
} else if (n == ARM_NR_semihosting
|| n == ARM_NR_thumb_semihosting) {
env->regs[0] = do_arm_semihosting (env);
- } else if (n >= ARM_SYSCALL_BASE
+ } else if (n == 0 || n >= ARM_SYSCALL_BASE
|| (env->thumb && n == ARM_THUMB_SYSCALL)) {
/* linux syscall */
- if (env->thumb) {
+ if (env->thumb || n == 0) {
n = env->regs[7];
} else {
n -= ARM_SYSCALL_BASE;
+ env->eabi = 0;
}
env->regs[0] = do_syscall(env,
n,
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 164eb394a1..ab7846d7ac 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1651,6 +1651,45 @@ void syscall_init(void)
}
}
+static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIG_ENDIAN
+ return ((uint64_t)word0 << 32) | word1;
+#else
+ return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+
+#ifdef TARGET_NR_truncate64
+static inline long target_truncate64(void *cpu_env, const char *arg1,
+ long arg2, long arg3, long arg4)
+{
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi)
+ {
+ arg2 = arg3;
+ arg3 = arg4;
+ }
+#endif
+ return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
+}
+#endif
+
+#ifdef TARGET_NR_ftruncate64
+static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2,
+ long arg3, long arg4)
+{
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi)
+ {
+ arg2 = arg3;
+ arg3 = arg4;
+ }
+#endif
+ return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
+}
+#endif
+
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
@@ -2844,12 +2883,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#endif
#ifdef TARGET_NR_truncate64
case TARGET_NR_truncate64:
- ret = get_errno(truncate64((const char *)arg1, arg2));
+ ret = target_truncate64(cpu_env, (const char *)arg1, arg2, arg3, arg4);
break;
#endif
#ifdef TARGET_NR_ftruncate64
case TARGET_NR_ftruncate64:
- ret = get_errno(ftruncate64(arg1, arg2));
+ ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
break;
#endif
#ifdef TARGET_NR_stat64
@@ -2868,25 +2907,50 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(fstat(arg1, &st));
do_stat64:
if (!is_error(ret)) {
- struct target_stat64 *target_st = (void *)arg2;
- memset(target_st, 0, sizeof(struct target_stat64));
- put_user(st.st_dev, &target_st->st_dev);
- put_user(st.st_ino, &target_st->st_ino);
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi) {
+ struct target_eabi_stat64 *target_st = (void *)arg2;
+ memset(target_st, 0, sizeof(struct target_eabi_stat64));
+ put_user(st.st_dev, &target_st->st_dev);
+ put_user(st.st_ino, &target_st->st_ino);
+#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
+ put_user(st.st_ino, &target_st->__st_ino);
+#endif
+ put_user(st.st_mode, &target_st->st_mode);
+ put_user(st.st_nlink, &target_st->st_nlink);
+ put_user(st.st_uid, &target_st->st_uid);
+ put_user(st.st_gid, &target_st->st_gid);
+ put_user(st.st_rdev, &target_st->st_rdev);
+ /* XXX: better use of kernel struct */
+ 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);
+ } else
+#endif
+ {
+ struct target_stat64 *target_st = (void *)arg2;
+ memset(target_st, 0, sizeof(struct target_stat64));
+ put_user(st.st_dev, &target_st->st_dev);
+ put_user(st.st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
- put_user(st.st_ino, &target_st->__st_ino);
-#endif
- put_user(st.st_mode, &target_st->st_mode);
- put_user(st.st_nlink, &target_st->st_nlink);
- put_user(st.st_uid, &target_st->st_uid);
- put_user(st.st_gid, &target_st->st_gid);
- put_user(st.st_rdev, &target_st->st_rdev);
- /* XXX: better use of kernel struct */
- 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);
+ put_user(st.st_ino, &target_st->__st_ino);
+#endif
+ put_user(st.st_mode, &target_st->st_mode);
+ put_user(st.st_nlink, &target_st->st_nlink);
+ put_user(st.st_uid, &target_st->st_uid);
+ put_user(st.st_gid, &target_st->st_gid);
+ put_user(st.st_rdev, &target_st->st_rdev);
+ /* XXX: better use of kernel struct */
+ 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);
+ }
}
}
break;
@@ -3150,26 +3214,51 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
{
struct flock64 fl;
struct target_flock64 *target_fl = (void *)arg3;
+#ifdef TARGET_ARM
+ struct target_eabi_flock64 *target_efl = (void *)arg3;
+#endif
switch(arg2) {
case F_GETLK64:
ret = get_errno(fcntl(arg1, arg2, &fl));
if (ret == 0) {
- target_fl->l_type = tswap16(fl.l_type);
- target_fl->l_whence = tswap16(fl.l_whence);
- target_fl->l_start = tswap64(fl.l_start);
- target_fl->l_len = tswap64(fl.l_len);
- target_fl->l_pid = tswapl(fl.l_pid);
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi) {
+ target_efl->l_type = tswap16(fl.l_type);
+ target_efl->l_whence = tswap16(fl.l_whence);
+ target_efl->l_start = tswap64(fl.l_start);
+ target_efl->l_len = tswap64(fl.l_len);
+ target_efl->l_pid = tswapl(fl.l_pid);
+ } else
+#endif
+ {
+ target_fl->l_type = tswap16(fl.l_type);
+ target_fl->l_whence = tswap16(fl.l_whence);
+ target_fl->l_start = tswap64(fl.l_start);
+ target_fl->l_len = tswap64(fl.l_len);
+ target_fl->l_pid = tswapl(fl.l_pid);
+ }
}
break;
case F_SETLK64:
case F_SETLKW64:
- fl.l_type = tswap16(target_fl->l_type);
- fl.l_whence = tswap16(target_fl->l_whence);
- fl.l_start = tswap64(target_fl->l_start);
- fl.l_len = tswap64(target_fl->l_len);
- fl.l_pid = tswapl(target_fl->l_pid);
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi) {
+ fl.l_type = tswap16(target_efl->l_type);
+ fl.l_whence = tswap16(target_efl->l_whence);
+ fl.l_start = tswap64(target_efl->l_start);
+ fl.l_len = tswap64(target_efl->l_len);
+ fl.l_pid = tswapl(target_efl->l_pid);
+ } else
+#endif
+ {
+ fl.l_type = tswap16(target_fl->l_type);
+ fl.l_whence = tswap16(target_fl->l_whence);
+ fl.l_start = tswap64(target_fl->l_start);
+ fl.l_len = tswap64(target_fl->l_len);
+ fl.l_pid = tswapl(target_fl->l_pid);
+ }
ret = get_errno(fcntl(arg1, arg2, &fl));
break;
default:
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 68f7e7f017..c722e3a427 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -924,6 +924,38 @@ struct target_stat64 {
unsigned long long st_ino;
} __attribute__((packed));
+#ifdef TARGET_ARM
+struct target_eabi_stat64 {
+ unsigned long long st_dev;
+ unsigned int __pad1;
+ unsigned long __st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+
+ unsigned long st_uid;
+ unsigned long st_gid;
+
+ unsigned long long st_rdev;
+ unsigned int __pad2[2];
+
+ long long st_size;
+ unsigned long st_blksize;
+ unsigned int __pad3;
+ unsigned long long st_blocks;
+
+ unsigned long target_st_atime;
+ unsigned long target_st_atime_nsec;
+
+ unsigned long target_st_mtime;
+ unsigned long target_st_mtime_nsec;
+
+ unsigned long target_st_ctime;
+ unsigned long target_st_ctime_nsec;
+
+ unsigned long long st_ino;
+} __attribute__ ((packed));
+#endif
+
#elif defined(TARGET_SPARC)
struct target_stat {
@@ -1298,8 +1330,18 @@ struct target_flock64 {
unsigned long long l_start;
unsigned long long l_len;
int l_pid;
-};
+}__attribute__((packed));
+#ifdef TARGET_ARM
+struct target_eabi_flock64 {
+ short l_type;
+ short l_whence;
+ int __pad;
+ unsigned long long l_start;
+ unsigned long long l_len;
+ int l_pid;
+}__attribute__((packed));
+#endif
/* soundcard defines */
/* XXX: convert them all to arch indepedent entries */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 7cc7da60e9..052634cd50 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -110,6 +110,11 @@ typedef struct CPUARMState {
float_status fp_status;
} vfp;
+#if defined(CONFIG_USER_ONLY)
+ /* For usermode syscall translation. */
+ int eabi;
+#endif
+
CPU_COMMON
} CPUARMState;