From cb33da57aaa368d575825d80d734374e3ef8c472 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 9 Oct 2007 16:34:29 +0000 Subject: [PATCH] Support for executing 32 bit SPARC32PLUS files for Sparc64 user emulator git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3378 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 4 ++ configure | 7 +++ linux-user/elfload.c | 97 +++++++++++++++++++++++++++++++---------- linux-user/elfload32.c | 30 +++++++++++++ linux-user/linuxload.c | 4 ++ linux-user/main.c | 1 + linux-user/qemu.h | 5 +++ linux-user/sparc64/syscall_nr.h | 48 ++++++++++---------- 9 files changed, 149 insertions(+), 48 deletions(-) create mode 100755 linux-user/elfload32.c diff --git a/Changelog b/Changelog index 26fc301..4c7a121 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,7 @@ - Read-only support for Parallels disk images (Alex Beregszaszi) - SVM (x86 virtualization) support (Alexander Graf) - CRIS emulation (Edgar E. Iglesias) + - SPARC32PLUS execution support (Blue Swirl) version 0.9.0: diff --git a/Makefile.target b/Makefile.target index fe0cf37..8ebe3c3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -254,6 +254,10 @@ LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT OBJS+= flatload.o endif +ifdef TARGET_HAS_ELFLOAD32 +OBJS+= elfload32.o +elfload32.o: elfload.c +endif ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o diff --git a/configure b/configure index a8dbf85..8e705e1 100755 --- a/configure +++ b/configure @@ -999,6 +999,7 @@ echo "include ../config-host.mak" >> $config_mak echo "#include \"../config-host.h\"" >> $config_h bflt="no" +elfload32="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h @@ -1023,6 +1024,7 @@ elif test "$target_cpu" = "sparc64" ; then echo "#define TARGET_ARCH \"sparc64\"" >> $config_h echo "#define TARGET_SPARC 1" >> $config_h echo "#define TARGET_SPARC64 1" >> $config_h + elfload32="yes" elif test "$target_cpu" = "ppc" ; then echo "TARGET_ARCH=ppc" >> $config_mak echo "#define TARGET_ARCH \"ppc\"" >> $config_h @@ -1112,6 +1114,11 @@ if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then echo "TARGET_HAS_BFLT=yes" >> $config_mak echo "#define TARGET_HAS_BFLT 1" >> $config_h fi +# 32 bit ELF loader in addition to native 64 bit loader? +if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then + echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak + echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h +fi # sdl defines if test "$target_user_only" = "no"; then diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 1db6bab..fbe7ddd 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -12,6 +12,66 @@ #include "qemu.h" #include "disas.h" +/* from personality.h */ + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors + * (signal handling) + */ + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | + WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, +}; + +/* + * Return the base personality without flags. + */ +#define personality(pers) (pers & PER_MASK) + /* this flag is uneffective under linux too, should be deleted */ #ifndef MAP_DENYWRITE #define MAP_DENYWRITE 0 @@ -154,7 +214,7 @@ enum #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) +#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -168,7 +228,10 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; + if (personality(infop->personality) == PER_LINUX32) + regs->u_regs[14] = infop->start_stack - 16 * 4; + else + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; } #else @@ -412,6 +475,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_HWCAP 0 #endif +#ifdef OVERRIDE_ELF_CLASS +#undef ELF_CLASS +#define ELF_CLASS OVERRIDE_ELF_CLASS +#undef bswaptls +#define bswaptls(ptr) bswap32s(ptr) +#endif + #include "elf.h" struct exec @@ -439,25 +509,6 @@ struct exec /* max code+data+bss+brk space allocated to ET_DYN executables */ #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) -/* from personality.h */ - -/* Flags for bug emulation. These occupy the top three bytes. */ -#define STICKY_TIMEOUTS 0x4000000 -#define WHOLE_SECONDS 0x2000000 - -/* Personality types. These go in the low byte. Avoid using the top bit, - * it will conflict with error returns. - */ -#define PER_MASK (0x00ff) -#define PER_LINUX (0x0000) -#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) -#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) -#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) -#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) -#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) -#define PER_BSD (0x0006) -#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) - /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) @@ -587,8 +638,8 @@ static target_ulong copy_elf_strings(int argc,char ** argv, void **page, return p; } -target_ulong setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +static target_ulong setup_arg_pages(target_ulong p, struct linux_binprm *bprm, + struct image_info *info) { target_ulong stack_base, size, error; int i; diff --git a/linux-user/elfload32.c b/linux-user/elfload32.c new file mode 100755 index 0000000..d1a15ff --- /dev/null +++ b/linux-user/elfload32.c @@ -0,0 +1,30 @@ +#define OVERRIDE_ELF_CLASS ELFCLASS32 +#define load_elf_binary load_elf_binary32 +#define do_init_thread do_init_thread32 + +#include "elfload.c" + +#undef load_elf_binary +#undef do_init_thread + +int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); + +int load_elf_binary_multi(struct linux_binprm *bprm, + struct target_pt_regs *regs, + struct image_info *info) +{ + struct elfhdr *elf_ex; + int retval; + + elf_ex = (struct elfhdr *) bprm->buf; /* exec-header */ + if (elf_ex->e_ident[EI_CLASS] == ELFCLASS64) { + retval = load_elf_binary(bprm, regs, info); + } else { + retval = load_elf_binary32(bprm, regs, info); + if (personality(info->personality) == PER_LINUX) + info->personality = PER_LINUX32; + } + + return retval; +} diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 0efbb76..51f2953 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -169,7 +169,11 @@ int loader_exec(const char * filename, char ** argv, char ** envp, && bprm.buf[1] == 'E' && bprm.buf[2] == 'L' && bprm.buf[3] == 'F') { +#ifndef TARGET_HAS_ELFLOAD32 retval = load_elf_binary(&bprm,regs,infop); +#else + retval = load_elf_binary_multi(&bprm, regs, infop); +#endif #if defined(TARGET_HAS_BFLT) } else if (bprm.buf[0] == 'b' && bprm.buf[1] == 'F' diff --git a/linux-user/main.c b/linux-user/main.c index b4bc93d..7de7ff5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -564,6 +564,7 @@ void cpu_loop (CPUSPARCState *env) case 0x88: case 0x90: #else + case 0x110: case 0x16d: #endif ret = do_syscall (env, env->gregs[1], diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 2c48e92..8a7cb24 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -124,6 +124,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); +#ifdef TARGET_HAS_ELFLOAD32 +int load_elf_binary_multi(struct linux_binprm *bprm, + struct target_pt_regs *regs, + struct image_info *info); +#endif void memcpy_to_target(target_ulong dest, const void *src, unsigned long len); diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index 5310294..70bee808 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -29,11 +29,11 @@ #define TARGET_NR_sigaltstack 28 /* Common */ #define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ #define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ -/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */ -/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */ +#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */ +#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */ #define TARGET_NR_access 33 /* Common */ #define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ -/* #define TARGET_NR_chown32 35 Linux sparc32 specific */ +#define TARGET_NR_chown32 35 /* Linux sparc32 specific */ #define TARGET_NR_sync 36 /* Common */ #define TARGET_NR_kill 37 /* Common */ #define TARGET_NR_stat 38 /* Common */ @@ -42,7 +42,7 @@ #define TARGET_NR_dup 41 /* Common */ #define TARGET_NR_pipe 42 /* Common */ #define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ -/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */ +#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */ #define TARGET_NR_umount2 45 /* Linux Specific */ #define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ #define TARGET_NR_getgid 47 /* Common */ @@ -51,48 +51,48 @@ #define TARGET_NR_getegid 50 /* SunOS calls getgid() */ #define TARGET_NR_acct 51 /* Common */ #define TARGET_NR_memory_ordering 52 /* Linux Specific */ -/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */ +#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */ #define TARGET_NR_ioctl 54 /* Common */ #define TARGET_NR_reboot 55 /* Common */ -/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */ +#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */ #define TARGET_NR_symlink 57 /* Common */ #define TARGET_NR_readlink 58 /* Common */ #define TARGET_NR_execve 59 /* Common */ #define TARGET_NR_umask 60 /* Common */ #define TARGET_NR_chroot 61 /* Common */ #define TARGET_NR_fstat 62 /* Common */ -/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */ +#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */ #define TARGET_NR_getpagesize 64 /* Common */ #define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ #define TARGET_NR_vfork 66 /* Common */ #define TARGET_NR_pread64 67 /* Linux Specific */ #define TARGET_NR_pwrite64 68 /* Linux Specific */ -/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */ -/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */ +#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ +#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ #define TARGET_NR_mmap 71 /* Common */ -/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */ #define TARGET_NR_munmap 73 /* Common */ #define TARGET_NR_mprotect 74 /* Common */ #define TARGET_NR_madvise 75 /* Common */ #define TARGET_NR_vhangup 76 /* Common */ -/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */ +#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */ #define TARGET_NR_mincore 78 /* Common */ #define TARGET_NR_getgroups 79 /* Common */ #define TARGET_NR_setgroups 80 /* Common */ #define TARGET_NR_getpgrp 81 /* Common */ -/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */ #define TARGET_NR_setitimer 83 /* Common */ -/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */ +#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */ #define TARGET_NR_swapon 85 /* Common */ #define TARGET_NR_getitimer 86 /* Common */ -/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */ #define TARGET_NR_sethostname 88 /* Common */ -/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */ #define TARGET_NR_dup2 90 /* Common */ -/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */ #define TARGET_NR_fcntl 92 /* Common */ #define TARGET_NR_select 93 /* Common */ -/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */ #define TARGET_NR_fsync 95 /* Common */ #define TARGET_NR_setpriority 96 /* Common */ #define TARGET_NR_socket 97 /* Common */ @@ -110,10 +110,10 @@ #define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */ #define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */ #define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */ -/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ +/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ #define TARGET_NR_recvmsg 113 /* Common */ #define TARGET_NR_sendmsg 114 /* Common */ -/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */ #define TARGET_NR_gettimeofday 116 /* Common */ #define TARGET_NR_getrusage 117 /* Common */ #define TARGET_NR_getsockopt 118 /* Common */ @@ -130,14 +130,14 @@ #define TARGET_NR_truncate 129 /* Common */ #define TARGET_NR_ftruncate 130 /* Common */ #define TARGET_NR_flock 131 /* Common */ -/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */ +#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */ #define TARGET_NR_sendto 133 /* Common */ #define TARGET_NR_shutdown 134 /* Common */ #define TARGET_NR_socketpair 135 /* Common */ #define TARGET_NR_mkdir 136 /* Common */ #define TARGET_NR_rmdir 137 /* Common */ #define TARGET_NR_utimes 138 /* SunOS Specific */ -/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */ +#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */ #define TARGET_NR_sendfile64 140 /* adjtime under SunOS */ #define TARGET_NR_getpeername 141 /* Common */ #define TARGET_NR_futex 142 /* gethostid under SunOS */ @@ -153,7 +153,7 @@ /* #define TARGET_NR_putmsg 152 SunOS Specific */ #define TARGET_NR_poll 153 /* Common */ #define TARGET_NR_getdents64 154 /* Linux specific */ -/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */ +#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */ /* #define TARGET_NR_getdirentries 156 SunOS Specific */ #define TARGET_NR_statfs 157 /* Common */ #define TARGET_NR_fstatfs 158 /* Common */ @@ -229,9 +229,7 @@ #define TARGET_NR_setfsuid 228 /* Linux Specific */ #define TARGET_NR_setfsgid 229 /* Linux Specific */ #define TARGET_NR__newselect 230 /* Linux Specific */ -#ifdef __KERNEL__ -#define TARGET_NR_time 231 /* Linux sparc32 */ -#endif +#define TARGET_NR_time 231 /* Linux sparc32 */ /* #define TARGET_NR_oldstat 232 Linux Specific */ #define TARGET_NR_stime 233 /* Linux Specific */ #define TARGET_NR_statfs64 234 /* Linux Specific */ -- 2.7.4