Patchwork [RFC] x32-linux-user: initial commit

login
register
mail settings
Submitter Blue Swirl
Date April 7, 2012, 6:44 p.m.
Message ID <CAAu8pHuSJZiEGyLy+yd1Q8wQXzT3xQ-Ef3SesNgEZUQ_xZHzRA@mail.gmail.com>
Download mbox | patch
Permalink /patch/151313/
State New
Headers show

Comments

Blue Swirl - April 7, 2012, 6:44 p.m.
Add experimental support for x32 (x86_64 CPU, 32 bit ABI) user
emulator.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
A hand constructed (possibly incorrect) helloworld program prints the
greeting but crashes.

/src/qemu/obj-amd64/x32-linux-user/qemu-x32 -strace -d
in_asm,op,out_asm helloworld_x86_x32
ERROR: ioctl(BLKGETSIZE64): target=0x80041272 host=0x80081272
ERROR: ioctl(BLKBSZGET): target=0x80041270 host=0x80081270
ERROR: ioctl(SNDCTL_DSP_MAPINBUF): target=0x80085013 host=0x80105013
ERROR: ioctl(SNDCTL_DSP_MAPOUTBUF): target=0x80085014 host=0x80105014
ERROR: ioctl(VFAT_IOCTL_READDIR_BOTH): target=0x82187201 host=0x82307201
ERROR: ioctl(VFAT_IOCTL_READDIR_SHORT): target=0x82187202 host=0x82307202
19617 stat(0x00000002,0x080480b7) = -1 errno=14 (Bad address)
19617 write(0,0x80480b7,13)Hello World!
 = 13
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault
$ file helloworld_x86_x32
helloworld_x86_x32: ELF 32-bit LSB executable, x86-64, version 1
(SYSV), statically linked, not stripped
---
 configure                          |   11 ++++++++++-
 default-configs/x32-linux-user.mak |    1 +
 linux-user/elfload.c               |    8 ++++++++
 linux-user/main.c                  |    8 ++++----
 linux-user/signal.c                |    2 +-
 linux-user/syscall.c               |    2 +-
 qemu-tech.texi                     |    2 ++
 7 files changed, 27 insertions(+), 7 deletions(-)
 create mode 100644 default-configs/x32-linux-user.mak

Patch

From da26c80e168c3e1159542415f9df73ddae28de7f Mon Sep 17 00:00:00 2001
Message-Id: <da26c80e168c3e1159542415f9df73ddae28de7f.1333824052.git.blauwirbel@gmail.com>
From: Blue Swirl <blauwirbel@gmail.com>
Date: Sat, 7 Apr 2012 18:34:04 +0000
Subject: [PATCH] x32-linux-user: initial commit

Add experimental support for x32 (x86_64 CPU, 32 bit ABI) user
emulator.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
 configure                          |   11 ++++++++++-
 default-configs/x32-linux-user.mak |    1 +
 linux-user/elfload.c               |    8 ++++++++
 linux-user/main.c                  |    8 ++++----
 linux-user/signal.c                |    2 +-
 linux-user/syscall.c               |    2 +-
 qemu-tech.texi                     |    2 ++
 7 files changed, 27 insertions(+), 7 deletions(-)
 create mode 100644 default-configs/x32-linux-user.mak

diff --git a/configure b/configure
index 671b232..3cb29cd 100755
--- a/configure
+++ b/configure
@@ -942,6 +942,7 @@  if [ "$linux_user" = "yes" ] ; then
     default_target_list="${default_target_list}\
 i386-linux-user \
 x86_64-linux-user \
+x32-linux-user \
 alpha-linux-user \
 arm-linux-user \
 armeb-linux-user \
@@ -3497,6 +3498,14 @@  case "$target_arch2" in
     target_phys_bits=64
     target_long_alignment=8
   ;;
+    x32)
+    TARGET_ARCH=x86_64
+    TARGET_BASE_ARCH=i386
+    TARGET_ABI_DIR=x86_64
+    echo "TARGET_ABI32=y" >> $config_target_mak
+    target_phys_bits=64
+    target_long_alignment=8 # ??? Not specified in x32-abi
+  ;;
   alpha)
     target_phys_bits=64
     target_long_alignment=8
@@ -3770,7 +3779,7 @@  for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_HPPA_DIS=y"  >> $config_target_mak
     echo "CONFIG_HPPA_DIS=y"  >> $libdis_config_mak
   ;;
-  i386|x86_64)
+  i386|x86_64|x32)
     echo "CONFIG_I386_DIS=y"  >> $config_target_mak
     echo "CONFIG_I386_DIS=y"  >> $libdis_config_mak
   ;;
diff --git a/default-configs/x32-linux-user.mak b/default-configs/x32-linux-user.mak
new file mode 100644
index 0000000..44c5e23
--- /dev/null
+++ b/default-configs/x32-linux-user.mak
@@ -0,0 +1 @@ 
+# Default configuration for x32-linux-user
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f3b1552..d4c0c34 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -134,10 +134,18 @@  static uint32_t get_elf_hwcap(void)
 }
 
 #ifdef TARGET_X86_64
+#ifdef TARGET_ABI32
+#define ELF_START_MMAP 0x80000000
+/* ??? */
+#define elf_check_arch(x) (((x) == ELF_ARCH))
+
+#define ELF_CLASS      ELFCLASS32
+#else
 #define ELF_START_MMAP 0x2aaaaab000ULL
 #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
 
 #define ELF_CLASS      ELFCLASS64
+#endif
 #define ELF_ARCH       EM_X86_64
 
 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
diff --git a/linux-user/main.c b/linux-user/main.c
index 191b750..fc45371 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -282,7 +282,7 @@  static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
 }
 
 static uint64_t *idt_table;
-#ifdef TARGET_X86_64
+#if defined(TARGET_X86_64) && !defined(TARGET_ABI32)
 static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
                        uint64_t addr, unsigned int sel)
 {
@@ -3577,7 +3577,7 @@  int main(int argc, char **argv, char **envp)
     env->eflags |= IF_MASK;
 
     /* linux register setup */
-#ifndef TARGET_ABI32
+#ifdef TARGET_X86_64
     env->regs[R_EAX] = regs->rax;
     env->regs[R_EBX] = regs->rbx;
     env->regs[R_ECX] = regs->rcx;
@@ -3639,7 +3639,7 @@  int main(int argc, char **argv, char **envp)
                                     MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
         gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
+#ifdef TARGET_X86_64
         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
@@ -3656,7 +3656,7 @@  int main(int argc, char **argv, char **envp)
     }
     cpu_x86_load_seg(env, R_CS, __USER_CS);
     cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
+#ifdef TARGET_X86_64
     cpu_x86_load_seg(env, R_DS, __USER_DS);
     cpu_x86_load_seg(env, R_ES, __USER_DS);
     cpu_x86_load_seg(env, R_FS, __USER_DS);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index b1e139d..a75affb 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -649,7 +649,7 @@  static inline int current_exec_domain_sig(int sig)
 	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
 }
 
-#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
 
 /* from the Linux kernel */
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8a92162..c079448 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7935,7 +7935,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_X86_64) /* ??? */
     case TARGET_NR_fcntl64:
     {
 	int cmd;
diff --git a/qemu-tech.texi b/qemu-tech.texi
index 5676fb7..67663e3 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -168,6 +168,8 @@  Current QEMU limitations:
 
 @item Limited x86-64 support.
 
+@item Experimental x32 user (x86-64 CPU, 32 bit ABI) emulator support.
+
 @item IPC syscalls are missing.
 
 @item The x86 segment limits and access rights are not tested at every
-- 
1.7.2.5