diff --git a/qemu-0.7.0-amd64.patch b/0001-qemu-0.7.0-amd64.patch similarity index 64% rename from qemu-0.7.0-amd64.patch rename to 0001-qemu-0.7.0-amd64.patch index 3f47a373..57b223a0 100644 --- a/qemu-0.7.0-amd64.patch +++ b/0001-qemu-0.7.0-amd64.patch @@ -1,6 +1,18 @@ ---- x86_64.ld -+++ x86_64.ld -@@ -59,8 +59,6 @@ +From 736ba7792e27aa443af4a3737a7372ff774dc394 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:17:39 +0200 +Subject: [PATCH 01/33] qemu-0.7.0-amd64 + +No clue why this is necessary or useful, nothing found in any changelogs. +--- + x86_64.ld | 6 ++---- + 1 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/x86_64.ld b/x86_64.ld +index 878dafb..142e641 100644 +--- a/x86_64.ld ++++ b/x86_64.ld +@@ -59,8 +59,6 @@ SECTIONS .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } @@ -9,7 +21,7 @@ /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); -@@ -86,8 +84,8 @@ +@@ -86,8 +84,8 @@ SECTIONS .data1 : { *(.data1) } .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } @@ -20,3 +32,6 @@ .dynamic : { *(.dynamic) } .ctors : { +-- +1.6.2.1 + diff --git a/qemu-0.9.0.cvs-binfmt.patch b/0002-qemu-0.9.0.cvs-binfmt.patch similarity index 91% rename from qemu-0.9.0.cvs-binfmt.patch rename to 0002-qemu-0.9.0.cvs-binfmt.patch index 092b5cec..657d7e23 100644 --- a/qemu-0.9.0.cvs-binfmt.patch +++ b/0002-qemu-0.9.0.cvs-binfmt.patch @@ -1,8 +1,23 @@ -Index: qemu-0.9.0/qemu-binfmt-conf.sh -================================================================================ ---- qemu/qemu-binfmt-conf.sh -+++ qemu/qemu-binfmt-conf.sh -@@ -12,7 +12,7 @@ +From 993c181ec92f0e5edfcb609048a4fa288c193309 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:18:44 +0200 +Subject: [PATCH 02/33] qemu-0.9.0.cvs-binfmt + +Fixes binfmt_misc setup script: +- x86_64 is i386-compatible +- m68k signature fixed +- path to QEMU + +Signed-off-by: Ulrich Hecht +--- + qemu-binfmt-conf.sh | 33 ++++++++++++++++++--------------- + 1 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh +index 941f0cf..67d6728 100644 +--- a/qemu-binfmt-conf.sh ++++ b/qemu-binfmt-conf.sh +@@ -12,7 +12,7 @@ fi # probe cpu type cpu=`uname -m` case "$cpu" in @@ -11,7 +26,7 @@ Index: qemu-0.9.0/qemu-binfmt-conf.sh cpu="i386" ;; m68k) -@@ -24,36 +24,39 @@ +@@ -24,36 +24,39 @@ case "$cpu" in "Power Macintosh"|ppc|ppc64) cpu="ppc" ;; @@ -65,3 +80,6 @@ Index: qemu-0.9.0/qemu-binfmt-conf.sh + echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register fi +-- +1.6.2.1 + diff --git a/qemu-cvs-alsa_bitfield.patch b/0003-qemu-cvs-alsa_bitfield.patch similarity index 59% rename from qemu-cvs-alsa_bitfield.patch rename to 0003-qemu-cvs-alsa_bitfield.patch index ef2a6aff..da6d2f72 100644 --- a/qemu-cvs-alsa_bitfield.patch +++ b/0003-qemu-cvs-alsa_bitfield.patch @@ -1,8 +1,21 @@ -Index: qemu/thunk.h -================================================================================ ---- qemu/thunk.c -+++ qemu/thunk.c -@@ -40,6 +40,7 @@ +From 6a9b13749aa2889fee2d6dc2fc4ae80a3df24a49 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:20:50 +0200 +Subject: [PATCH 03/33] qemu-cvs-alsa_bitfield + +Implements TYPE_INTBITFIELD partially. (required for ALSA support) + +Signed-off-by: Ulrich Hecht +--- + thunk.c | 21 +++++++++++++++++++++ + thunk.h | 3 +++ + 2 files changed, 24 insertions(+), 0 deletions(-) + +diff --git a/thunk.c b/thunk.c +index 0657188..5638b2c 100644 +--- a/thunk.c ++++ b/thunk.c +@@ -41,6 +41,7 @@ static inline const argtype *thunk_type_next(const argtype *type_ptr) case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: @@ -10,7 +23,7 @@ Index: qemu/thunk.h case TYPE_LONGLONG: case TYPE_ULONGLONG: case TYPE_LONG: -@@ -132,6 +133,26 @@ +@@ -139,6 +140,26 @@ const argtype *thunk_convert(void *dst, const void *src, case TYPE_INT: *(uint32_t *)dst = tswap32(*(uint32_t *)src); break; @@ -37,9 +50,11 @@ Index: qemu/thunk.h case TYPE_LONGLONG: case TYPE_ULONGLONG: *(uint64_t *)dst = tswap64(*(uint64_t *)src); ---- qemu/thunk.h -+++ qemu/thunk.h -@@ -38,6 +38,7 @@ +diff --git a/thunk.h b/thunk.h +index 109c541..55890f3 100644 +--- a/thunk.h ++++ b/thunk.h +@@ -37,6 +37,7 @@ typedef enum argtype { TYPE_PTR, TYPE_ARRAY, TYPE_STRUCT, @@ -47,7 +62,7 @@ Index: qemu/thunk.h } argtype; #define MK_PTR(type) TYPE_PTR, type -@@ -87,6 +88,7 @@ +@@ -90,6 +91,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host) case TYPE_SHORT: return 2; case TYPE_INT: @@ -55,7 +70,7 @@ Index: qemu/thunk.h return 4; case TYPE_LONGLONG: case TYPE_ULONGLONG: -@@ -124,6 +126,7 @@ +@@ -127,6 +129,7 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) case TYPE_SHORT: return 2; case TYPE_INT: @@ -63,3 +78,6 @@ Index: qemu/thunk.h return 4; case TYPE_LONGLONG: case TYPE_ULONGLONG: +-- +1.6.2.1 + diff --git a/qemu-cvs-alsa_ioctl.patch b/0004-qemu-cvs-alsa_ioctl.patch similarity index 98% rename from qemu-cvs-alsa_ioctl.patch rename to 0004-qemu-cvs-alsa_ioctl.patch index bdd7d339..b517832a 100644 --- a/qemu-cvs-alsa_ioctl.patch +++ b/0004-qemu-cvs-alsa_ioctl.patch @@ -1,19 +1,44 @@ -Index: qemu/linux-user/ioctls.h -================================================================================ ---- qemu-0.10.1/linux-user/ioctls.h -+++ qemu-0.10.1/linux-user/ioctls.h -@@ -314,3 +314,9 @@ - IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop))) - IOCTL(MTIOCGET, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtget))) - IOCTL(MTIOCPOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtpos))) -+ +From d14e67385b88cf274b9c9a5969880bd7f1d292a0 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:23:27 +0200 +Subject: [PATCH 04/33] qemu-cvs-alsa_ioctl + +Implements ALSA ioctls on PPC hosts. + +Signed-off-by: Ulrich Hecht +--- + linux-user/ioctls.h | 5 + + linux-user/ioctls_alsa.h | 467 ++++++++++ + linux-user/ioctls_alsa_structs.h | 1740 ++++++++++++++++++++++++++++++++++++++ + linux-user/syscall_defs.h | 1 + + linux-user/syscall_types.h | 5 + + linux-user/syscall_types_alsa.h | 1337 +++++++++++++++++++++++++++++ + 6 files changed, 3555 insertions(+), 0 deletions(-) + create mode 100644 linux-user/ioctls_alsa.h + create mode 100644 linux-user/ioctls_alsa_structs.h + create mode 100644 linux-user/syscall_types_alsa.h + +diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h +index 685cc71..aee5a88 100644 +--- a/linux-user/ioctls.h ++++ b/linux-user/ioctls.h +@@ -301,6 +301,11 @@ + IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) + IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) + +/* FIXME: including these on x86 / x86_64 breaks qemu-i386 */ +#ifdef __powerpc__ +#include "ioctls_alsa.h" +#endif + ---- qemu-0.10.1/linux-user/ioctls_alsa.h -+++ qemu-0.10.1/linux-user/ioctls_alsa.h + IOCTL(LOOP_SET_FD, 0, TYPE_INT) + IOCTL(LOOP_CLR_FD, 0, TYPE_INT) + IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) +diff --git a/linux-user/ioctls_alsa.h b/linux-user/ioctls_alsa.h +new file mode 100644 +index 0000000..c2aa542 +--- /dev/null ++++ b/linux-user/ioctls_alsa.h @@ -0,0 +1,467 @@ +#define SNDRV_SEQ_IOCTL_PVERSION _IOR ('S', 0x00, int) +#define SNDRV_SEQ_IOCTL_CLIENT_ID _IOR ('S', 0x01, int) @@ -482,8 +507,11 @@ Index: qemu/linux-user/ioctls.h +IOCTL( SNDRV_SB_CSP_IOCTL_RESTART , 0, TYPE_NULL ) +IOCTL( SND_SSCAPE_LOAD_BOOTB , IOC_RW, MK_PTR(MK_STRUCT(STRUCT_sscape_bootblock)) ) +IOCTL( SND_SSCAPE_LOAD_MCODE , IOC_W, MK_PTR(MK_STRUCT(STRUCT_sscape_microcode)) ) ---- qemu-0.10.1/linux-user/ioctls_alsa_structs.h -+++ qemu-0.10.1/linux-user/ioctls_alsa_structs.h +diff --git a/linux-user/ioctls_alsa_structs.h b/linux-user/ioctls_alsa_structs.h +new file mode 100644 +index 0000000..3de8614 +--- /dev/null ++++ b/linux-user/ioctls_alsa_structs.h @@ -0,0 +1,1740 @@ +/* + * Advanced Linux Sound Architecture @@ -2225,30 +2253,36 @@ Index: qemu/linux-user/ioctls.h +{ + unsigned char *code; +}; ---- qemu-0.10.1/linux-user/syscall_defs.h -+++ qemu-0.10.1/linux-user/syscall_defs.h -@@ -2001,6 +2001,7 @@ - #include "socket.h" +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index ac5dbc5..78c6488 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -2138,3 +2138,4 @@ struct target_mq_attr { + #define FUTEX_CLOCK_REALTIME 256 + #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) - #include "errno_defs.h" +#include "ioctls_alsa_structs.h" +diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h +index d3f3df9..1fa48d0 100644 +--- a/linux-user/syscall_types.h ++++ b/linux-user/syscall_types.h +@@ -80,6 +80,11 @@ STRUCT(count_info, + STRUCT(mixer_info, + MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) - struct target_ipc64_perm - { ---- qemu-0.10.1/linux-user/syscall_types.h -+++ qemu-0.10.1/linux-user/syscall_types.h -@@ -114,3 +114,9 @@ - STRUCT(mtget, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG, - TYPE_INT, TYPE_INT) - STRUCT(mtpos, TYPE_LONG) -+ +/* FIXME: including these on x86 / x86_64 breaks qemu-i386 */ +#ifdef __powerpc__ +#include "syscall_types_alsa.h" +#endif + ---- qemu-0.10.1/linux-user/syscall_types_alsa.h -+++ qemu-0.10.1/linux-user/syscall_types_alsa.h + /* loop device ioctls */ + STRUCT(loop_info, + TYPE_INT, /* lo_number */ +diff --git a/linux-user/syscall_types_alsa.h b/linux-user/syscall_types_alsa.h +new file mode 100644 +index 0000000..6dbc964 +--- /dev/null ++++ b/linux-user/syscall_types_alsa.h @@ -0,0 +1,1337 @@ +/* + * Advanced Linux Sound Architecture @@ -3587,3 +3621,6 @@ Index: qemu/linux-user/ioctls.h + TYPE_PTRVOID +) + +-- +1.6.2.1 + diff --git a/qemu-cvs-alsa_mmap.patch b/0005-qemu-cvs-alsa_mmap.patch similarity index 52% rename from qemu-cvs-alsa_mmap.patch rename to 0005-qemu-cvs-alsa_mmap.patch index bc44c870..74587e75 100644 --- a/qemu-cvs-alsa_mmap.patch +++ b/0005-qemu-cvs-alsa_mmap.patch @@ -1,9 +1,21 @@ -Index: qemu/linux-user/mmap.c -================================================================================ ---- qemu/linux-user/mmap.c -+++ qemu/linux-user/mmap.c -@@ -153,6 +153,9 @@ - return 0; +From 3c312c26b8dd16c170720160677c0cd72ad71655 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:24:15 +0200 +Subject: [PATCH 05/33] qemu-cvs-alsa_mmap + +Hack to prevent ALSA from using mmap() interface to simplify emulation. + +Signed-off-by: Ulrich Hecht +--- + linux-user/mmap.c | 14 ++++++++++++++ + 1 files changed, 14 insertions(+), 0 deletions(-) + +diff --git a/linux-user/mmap.c b/linux-user/mmap.c +index e05caa0..c33e5fe 100644 +--- a/linux-user/mmap.c ++++ b/linux-user/mmap.c +@@ -321,6 +321,9 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) + return addr; } +#define SNDRV_PCM_MMAP_OFFSET_STATUS 0x80000000 @@ -12,7 +24,7 @@ Index: qemu/linux-user/mmap.c /* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) -@@ -194,6 +197,17 @@ +@@ -356,6 +359,17 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } #endif @@ -29,4 +41,7 @@ Index: qemu/linux-user/mmap.c + if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; - return -1; + goto fail; +-- +1.6.2.1 + diff --git a/0006-qemu-cvs-gettimeofday.patch b/0006-qemu-cvs-gettimeofday.patch new file mode 100644 index 00000000..d0bcbeeb --- /dev/null +++ b/0006-qemu-cvs-gettimeofday.patch @@ -0,0 +1,26 @@ +From 3baf3b46ba7a653bdfdca59edb64f87d7b9a0671 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:25:41 +0200 +Subject: [PATCH 06/33] qemu-cvs-gettimeofday + +No clue what this is for. +--- + linux-user/syscall.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 7b57323..70d3b2d 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -5063,6 +5063,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + case TARGET_NR_gettimeofday: + { + struct timeval tv; ++ if(copy_from_user_timeval(&tv, arg1)) ++ goto efault; + ret = get_errno(gettimeofday(&tv, NULL)); + if (!is_error(ret)) { + if (copy_to_user_timeval(arg1, &tv)) +-- +1.6.2.1 + diff --git a/0007-qemu-cvs-ioctl_debug.patch b/0007-qemu-cvs-ioctl_debug.patch new file mode 100644 index 00000000..31a5f8be --- /dev/null +++ b/0007-qemu-cvs-ioctl_debug.patch @@ -0,0 +1,33 @@ +From dfc0f3252a5333ec9c70122c2ca9bb25578e0f2e Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:26:33 +0200 +Subject: [PATCH 07/33] qemu-cvs-ioctl_debug + +Extends unsupported ioctl debug output. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 70d3b2d..ce5283c 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -2890,7 +2890,12 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) + ie = ioctl_entries; + for(;;) { + if (ie->target_cmd == 0) { +- gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); ++ int i; ++ gemu_log("Unsupported ioctl: cmd=0x%04lx (%x)\n", (unsigned long)cmd, (unsigned int)(cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); ++ for(i=0;ioctl_entries[i].target_cmd;i++) { ++ if((ioctl_entries[i].target_cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) == (cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT))) ++ gemu_log("%p\t->\t%s (%x)\n", (void *)(unsigned long)ioctl_entries[i].host_cmd, ioctl_entries[i].name, (ioctl_entries[i].target_cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); ++ } + return -TARGET_ENOSYS; + } + if (ie->target_cmd == cmd) +-- +1.6.2.1 + diff --git a/0008-qemu-cvs-ioctl_nodirection.patch b/0008-qemu-cvs-ioctl_nodirection.patch new file mode 100644 index 00000000..790daaf0 --- /dev/null +++ b/0008-qemu-cvs-ioctl_nodirection.patch @@ -0,0 +1,42 @@ +From 0ae47f212081dde6ff4cbc44864003132b8a59ef Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:27:36 +0200 +Subject: [PATCH 08/33] qemu-cvs-ioctl_nodirection + +the direction given in the ioctl should be correct so we can assume the +communication is uni-directional. The alsa developers did not like this +concept though and declared ioctls IOC_R and IOC_W even though they were +IOC_RW. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index ce5283c..b7230c7 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -2920,6 +2920,11 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) + arg_type++; + target_size = thunk_type_size(arg_type, 0); + switch(ie->access) { ++ /* FIXME: actually the direction given in the ioctl should be ++ * correct so we can assume the communication is uni-directional. ++ * The alsa developers did not like this concept though and ++ * declared ioctls IOC_R and IOC_W even though they were IOC_RW.*/ ++/* + case IOC_R: + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { +@@ -2938,6 +2943,7 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + break; ++*/ + default: + case IOC_RW: + argptr = lock_user(VERIFY_READ, arg, target_size, 1); +-- +1.6.2.1 + diff --git a/qemu-cvs-newpath.patch b/0009-qemu-cvs-newpath.patch similarity index 91% rename from qemu-cvs-newpath.patch rename to 0009-qemu-cvs-newpath.patch index ddf0db51..bfbe9112 100644 --- a/qemu-cvs-newpath.patch +++ b/0009-qemu-cvs-newpath.patch @@ -1,7 +1,19 @@ -Index: qemu.bkp/linux-user/path.c -================================================================================ ---- qemu-0.10.1/linux-user/path.c -+++ qemu-0.10.1/linux-user/path.c +From 447a7055bbff636821fb9a559e9b8d30b1ab9391 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:28:45 +0200 +Subject: [PATCH 09/33] qemu-cvs-newpath + +fast path mangling patch by Kirill A. Shutemov + +Signed-off-by: Ulrich Hecht +--- + linux-user/path.c | 190 ++++++++++++++++------------------------------------- + 1 files changed, 56 insertions(+), 134 deletions(-) + +diff --git a/linux-user/path.c b/linux-user/path.c +index 06b1f5f..aedff50 100644 +--- a/linux-user/path.c ++++ b/linux-user/path.c @@ -1,159 +1,81 @@ /* Code to mangle pathnames into those matching a given prefix. eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so"); @@ -149,7 +161,8 @@ Index: qemu.bkp/linux-user/path.c - free(cwd); - } else - strcpy(pref_buf,prefix + 1); -- ++ list_head = malloc(sizeof(struct path_list_head)); + - base = new_entry("", NULL, pref_buf); - base = add_dir_maybe(base); - if (base->num_entries == 0) { @@ -158,8 +171,6 @@ Index: qemu.bkp/linux-user/path.c - } else { - set_parents(base, base); - } -+ list_head = malloc(sizeof(struct path_list_head)); -+ + /* first element of list is prefix */ + list_head->path = strdup(prefix); + list_head->next = NULL; @@ -178,13 +189,14 @@ Index: qemu.bkp/linux-user/path.c Could do relative by tracking cwd. */ - if (!base || !name || name[0] != '/') - return name; +- +- return follow_path(base, name) ?: name; + if (!list_head || result[0] != '/') + goto exit; + + strncpy(newname, list_head->path, path_length); + strncat(newname, name, path_length); - -- return follow_path(base, name) ?: name; ++ + /* look for place where path should be present */ + while ( list->next && (strcmp(list->next->path, newname) < 0) ) + list = list->next; @@ -218,3 +230,6 @@ Index: qemu.bkp/linux-user/path.c + free(newname); + return result; } +-- +1.6.2.1 + diff --git a/qemu-cvs-sched_getaffinity.patch b/0010-qemu-cvs-sched_getaffinity.patch similarity index 58% rename from qemu-cvs-sched_getaffinity.patch rename to 0010-qemu-cvs-sched_getaffinity.patch index 61cc5833..4d5760cf 100644 --- a/qemu-cvs-sched_getaffinity.patch +++ b/0010-qemu-cvs-sched_getaffinity.patch @@ -1,16 +1,28 @@ -Index: qemu.bkp/linux-user/syscall.c -================================================================================ ---- qemu-0.10.1/linux-user/syscall.c -+++ qemu-0.10.1/linux-user/syscall.c -@@ -157,6 +157,7 @@ +From 2c9c1dd32c9abf3ae72101782eada5a11c4334a5 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:30:16 +0200 +Subject: [PATCH 10/33] qemu-cvs-sched_getaffinity + +Implements sched_getaffinity syscall. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index b7230c7..faf41b1 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -152,6 +152,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ + } - #define __NR_sys_exit __NR_exit +#define __NR_sys_sched_getaffinity __NR_sched_getaffinity #define __NR_sys_uname __NR_uname #define __NR_sys_faccessat __NR_faccessat #define __NR_sys_fchmodat __NR_fchmodat -@@ -265,6 +266,9 @@ +@@ -213,6 +214,9 @@ _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) #if defined(TARGET_NR_tkill) && defined(__NR_tkill) _syscall2(int,sys_tkill,int,tid,int,sig) #endif @@ -20,10 +32,11 @@ Index: qemu.bkp/linux-user/syscall.c #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif -@@ -6090,6 +6094,17 @@ +@@ -6979,6 +6983,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif - + #endif /* CONFIG_SPLICE */ ++ +#ifdef TARGET_NR_sched_getaffinity + case TARGET_NR_sched_getaffinity: + { @@ -38,3 +51,6 @@ Index: qemu.bkp/linux-user/syscall.c default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); +-- +1.6.2.1 + diff --git a/0011-qemu-cvs-mmap-amd64.patch b/0011-qemu-cvs-mmap-amd64.patch new file mode 100644 index 00000000..9cb9fa6e --- /dev/null +++ b/0011-qemu-cvs-mmap-amd64.patch @@ -0,0 +1,41 @@ +From b8637036b678276513dd920045016b0e8c37df4d Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:34:05 +0200 +Subject: [PATCH 11/33] qemu-cvs-mmap-amd64 + +Map stuff to address space < 4GB on AMD64. This patch got continually smaller +as most cases were this was an issue were dealt with in other ways. May +already be fully obsolete. + +Signed-off-by: Ulrich Hecht +--- + linux-user/mmap.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/linux-user/mmap.c b/linux-user/mmap.c +index c33e5fe..9ca8f6f 100644 +--- a/linux-user/mmap.c ++++ b/linux-user/mmap.c +@@ -31,6 +31,10 @@ + #include "qemu.h" + #include "qemu-common.h" + ++#if !defined(MAP_32BIT) ++#define MAP_32BIT 0 ++#endif ++ + //#define DEBUG_MMAP + + #if defined(USE_NPTL) +@@ -230,7 +234,7 @@ static int mmap_frag(abi_ulong real_start, + if (prot1 == 0) { + /* no page was there, so we allocate one */ + void *p = mmap(host_start, qemu_host_page_size, prot, +- flags | MAP_ANONYMOUS, -1, 0); ++ flags | MAP_ANONYMOUS | MAP_32BIT, -1, 0); + if (p == MAP_FAILED) + return -1; + prot1 = prot; +-- +1.6.2.1 + diff --git a/0012-qemu-cvs-pthread.patch b/0012-qemu-cvs-pthread.patch new file mode 100644 index 00000000..093ad846 --- /dev/null +++ b/0012-qemu-cvs-pthread.patch @@ -0,0 +1,28 @@ +From 09e232e1084dd42cf233fcac97816851b9261693 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:34:36 +0200 +Subject: [PATCH 12/33] qemu-cvs-pthread + +Link with libpthread. Not sure if still necessary. + +Signed-off-by: Ulrich Hecht +--- + Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/Makefile b/Makefile +index dc95869..ecc30ce 100644 +--- a/Makefile ++++ b/Makefile +@@ -19,7 +19,7 @@ VPATH=$(SRC_PATH):$(SRC_PATH)/hw + CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@ + CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + CPPFLAGS += -U_FORTIFY_SOURCE +-LIBS= ++LIBS=-lpthread + ifdef CONFIG_STATIC + LDFLAGS += -static + endif +-- +1.6.2.1 + diff --git a/0013-qemu-img-vmdk-scsi.patch b/0013-qemu-img-vmdk-scsi.patch new file mode 100644 index 00000000..ba474d01 --- /dev/null +++ b/0013-qemu-img-vmdk-scsi.patch @@ -0,0 +1,142 @@ +From 8acba6ba3add1b4e463f6fce711357e3c7c70555 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:37:42 +0200 +Subject: [PATCH 13/33] qemu-img-vmdk-scsi + +Support creation of SCSI VMDK images in qemu-img. + +Signed-off-by: Ulrich Hecht +--- + block/vmdk.c | 5 +++-- + block_int.h | 1 + + qemu-img-cmds.hx | 8 ++++---- + qemu-img.c | 15 +++++++++++++-- + 4 files changed, 21 insertions(+), 8 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 4e48622..b7a15c7 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -710,7 +710,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) + "ddb.geometry.cylinders = \"%" PRId64 "\"\n" + "ddb.geometry.heads = \"16\"\n" + "ddb.geometry.sectors = \"63\"\n" +- "ddb.adapterType = \"ide\"\n"; ++ "ddb.adapterType = \"%s\"\n"; + char desc[1024]; + const char *real_filename, *temp_str; + int64_t total_size = 0; +@@ -800,7 +800,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) + snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL), + total_size, real_filename, + (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), +- total_size / (int64_t)(63 * 16)); ++ total_size / (int64_t)(63 * 16), ++ flags & BLOCK_FLAG_SCSI ? "lsilogic" : "ide"); + + /* write the descriptor */ + lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); +diff --git a/block_int.h b/block_int.h +index 8898d91..d482050 100644 +--- a/block_int.h ++++ b/block_int.h +@@ -30,6 +30,7 @@ + #define BLOCK_FLAG_ENCRYPT 1 + #define BLOCK_FLAG_COMPRESS 2 + #define BLOCK_FLAG_COMPAT6 4 ++#define BLOCK_FLAG_SCSI 8 + + #define BLOCK_OPT_SIZE "size" + #define BLOCK_OPT_ENCRYPT "encryption" +diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx +index ddb86f0..be94d22 100644 +--- a/qemu-img-cmds.hx ++++ b/qemu-img-cmds.hx +@@ -16,9 +16,9 @@ STEXI + ETEXI + + DEF("create", img_create, +- "create [-F fmt] [-b base_image] [-f fmt] [-o options] filename [size]") ++ "create [-s] [-F fmt] [-b base_image] [-f fmt] [-o options] filename [size]") + STEXI +-@item create [-F @var{base_fmt}] [-b @var{base_image}] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ++@item create [-s] [-F @var{base_fmt}] [-b @var{base_image}] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] + ETEXI + + DEF("commit", img_commit, +@@ -28,9 +28,9 @@ STEXI + ETEXI + + DEF("convert", img_convert, +- "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-B output_base_image] filename [filename2 [...]] output_filename") ++ "convert [-c] [-s] [-f fmt] [-O output_fmt] [-o options] [-B output_base_image] filename [filename2 [...]] output_filename") + STEXI +-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} ++@item convert [-c] [-s] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} + ETEXI + + DEF("info", img_info, +diff --git a/qemu-img.c b/qemu-img.c +index 070fe2e..2adeb56 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -259,7 +259,7 @@ static int img_create(int argc, char **argv) + + flags = 0; + for(;;) { +- c = getopt(argc, argv, "F:b:f:he6o:"); ++ c = getopt(argc, argv, "F:b:f:hes6o:"); + if (c == -1) + break; + switch(c) { +@@ -278,6 +278,9 @@ static int img_create(int argc, char **argv) + case 'e': + flags |= BLOCK_FLAG_ENCRYPT; + break; ++ case 's': ++ flags |= BLOCK_FLAG_SCSI; ++ break; + case '6': + flags |= BLOCK_FLAG_COMPAT6; + break; +@@ -357,6 +360,8 @@ static int img_create(int argc, char **argv) + + printf("Formatting '%s', fmt=%s ", filename, fmt); + print_option_parameters(param); ++ if (flags & BLOCK_FLAG_SCSI) ++ printf(", SCSI"); + puts(""); + + ret = bdrv_create(drv, filename, param); +@@ -551,7 +556,7 @@ static int img_convert(int argc, char **argv) + out_baseimg = NULL; + flags = 0; + for(;;) { +- c = getopt(argc, argv, "f:O:B:hce6o:"); ++ c = getopt(argc, argv, "f:O:B:hces6o:"); + if (c == -1) + break; + switch(c) { +@@ -573,6 +578,9 @@ static int img_convert(int argc, char **argv) + case 'e': + flags |= BLOCK_FLAG_ENCRYPT; + break; ++ case 's': ++ flags |= BLOCK_FLAG_SCSI; ++ break; + case '6': + flags |= BLOCK_FLAG_COMPAT6; + break; +@@ -639,6 +647,9 @@ static int img_convert(int argc, char **argv) + } + } + ++ if (flags & BLOCK_FLAG_SCSI && strcmp(drv->format_name, "vmdk")) ++ error("SCSI devices not supported for this file format"); ++ + /* Create the new image */ + ret = bdrv_create(drv, out_filename, param); + free_option_parameters(param); +-- +1.6.2.1 + diff --git a/0014-qemu-nonvoid_return.patch b/0014-qemu-nonvoid_return.patch new file mode 100644 index 00000000..1344f1bf --- /dev/null +++ b/0014-qemu-nonvoid_return.patch @@ -0,0 +1,40 @@ +From e880deb6d14c779cd9ecca4a25168c162183200e Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:38:20 +0200 +Subject: [PATCH 14/33] qemu-nonvoid_return + +Squelches GCC warnings about undefined return values. + +Signed-off-by: Ulrich Hecht +--- + hw/mpcore.c | 1 + + target-m68k/translate.c | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/hw/mpcore.c b/hw/mpcore.c +index 907bd99..a682695 100644 +--- a/hw/mpcore.c ++++ b/hw/mpcore.c +@@ -108,6 +108,7 @@ static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset) + default: + return 0; + } ++ return 0; + } + + static void mpcore_timer_write(mpcore_timer_state *s, int offset, +diff --git a/target-m68k/translate.c b/target-m68k/translate.c +index b37578b..feaa155 100644 +--- a/target-m68k/translate.c ++++ b/target-m68k/translate.c +@@ -440,6 +440,7 @@ static inline int opsize_bytes(int opsize) + qemu_assert(0, "bad operand size"); + return 0; + } ++ return 0; + } + + /* Assign value to a register. If the width is less than the register width +-- +1.6.2.1 + diff --git a/qemu-svn-pcap.patch b/0015-pcap-network-emulation.patch similarity index 56% rename from qemu-svn-pcap.patch rename to 0015-pcap-network-emulation.patch index a314a545..bfd0c308 100644 --- a/qemu-svn-pcap.patch +++ b/0015-pcap-network-emulation.patch @@ -1,8 +1,23 @@ -Index: Makefile.target -================================================================================ ---- Makefile.target -+++ Makefile.target -@@ -690,6 +690,9 @@ +From 0792daad3fd53b5fb841fc6ed0e8ec6a06e8479a Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 14 Apr 2009 16:52:51 +0200 +Subject: [PATCH 15/33] pcap network emulation + +Implements network emulation using libpcap; useful for direct Ethernet access. + +Signed-off-by: Ulrich Hecht +--- + Makefile.target | 3 ++ + configure | 7 ++++ + net.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + qemu-options.hx | 4 ++ + 4 files changed, 122 insertions(+), 0 deletions(-) + +diff --git a/Makefile.target b/Makefile.target +index f9cd42a..9c9304c 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -618,6 +618,9 @@ endif ifdef CONFIG_SLIRP CPPFLAGS+=-I$(SRC_PATH)/slirp endif @@ -10,19 +25,21 @@ Index: Makefile.target +LIBS+=-lpcap +endif - LIBS+=$(AIOLIBS) # specific flags are needed for non soft mmu emulator ---- configure -+++ configure -@@ -160,6 +160,7 @@ - gdbstub="yes" + ifdef CONFIG_STATIC +diff --git a/configure b/configure +index 2a6ae40..d104413 100755 +--- a/configure ++++ b/configure +@@ -169,6 +169,7 @@ mingw32="no" + EXESUF="" slirp="yes" vde="yes" +pcap="yes" fmod_lib="" fmod_inc="" oss_lib="" -@@ -392,6 +393,8 @@ +@@ -432,6 +433,8 @@ for opt do ;; --disable-vde) vde="no" ;; @@ -30,21 +47,23 @@ Index: Makefile.target + ;; --disable-kqemu) kqemu="no" ;; - --disable-brlapi) brlapi="no" -@@ -1353,6 +1356,10 @@ - echo "#define CONFIG_VDE 1" >> $config_h - echo "VDE_LIBS=-lvdeplug" >> $config_mak + --disable-xen) xen="no" +@@ -1598,6 +1601,10 @@ if test "$vde" = "yes" ; then + echo "#define CONFIG_VDE 1" >> $config_host_h + echo "VDE_LIBS=-lvdeplug" >> $config_host_mak fi +if test "$pcap" = "yes" ; then -+ echo "CONFIG_PCAP=yes" >> $config_mak -+ echo "#define CONFIG_PCAP 1" >> $config_h ++ echo "CONFIG_PCAP=yes" >> $config_host_mak ++ echo "#define CONFIG_PCAP 1" >> $config_host_h +fi for card in $audio_card_list; do def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'` - echo "$def=yes" >> $config_mak ---- net.c -+++ net.c -@@ -689,6 +689,104 @@ + echo "$def=y" >> $config_host_mak +diff --git a/net.c b/net.c +index cf6b033..b321135 100644 +--- a/net.c ++++ b/net.c +@@ -1270,6 +1270,105 @@ void do_info_usernet(Monitor *mon) #endif /* CONFIG_SLIRP */ @@ -55,11 +74,12 @@ Index: Makefile.target + pcap_t *handle; +} PCAPState; + -+static void pcap_receive(void *opaque, const uint8_t *buf, int size) ++static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ -+ PCAPState *s = (PCAPState *)opaque; ++ PCAPState *s = (PCAPState *)(vc->opaque); + + pcap_sendpacket(s->handle, (u_char*)buf, size); ++ return size; +} + +static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata) @@ -125,7 +145,7 @@ Index: Makefile.target + } +#endif /* BIOCIMMEDIATE */ + -+ s->vc = qemu_new_vlan_client(vlan, model, name, pcap_receive, NULL, s); ++ s->vc = qemu_new_vlan_client(vlan, model, name, NULL, pcap_receive, NULL, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector"); + if ((fd = pcap_get_selectable_fd(s->handle)) < 0) { + fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n"); @@ -149,12 +169,10 @@ Index: Makefile.target #if !defined(_WIN32) typedef struct TAPState { -@@ -1656,7 +1754,17 @@ - } - vlan->nb_host_devs++; - ret = net_slirp_init(vlan, device, name); -- } else if (!strcmp(device, "channel")) { -+ } else +@@ -2636,6 +2735,15 @@ int net_client_init(Monitor *mon, const char *device, const char *p) + ret = 0; + } else + #endif +#ifdef CONFIG_PCAP + if (!strcmp(device, "pcap")) { + char ifname[64]; @@ -164,20 +182,24 @@ Index: Makefile.target + ret = net_pcap_init(vlan, device, name, ifname); + } else +#endif -+ if (!strcmp(device, "channel")) { - long port; - char name[20], *devname; - struct VMChannel *vmc; ---- vl.c -+++ vl.c -@@ -3990,6 +3994,10 @@ - " use '[down]script=no' to disable script execution;\n" - " use 'fd=h' to connect to an already opened TAP interface\n" + #ifdef _WIN32 + if (!strcmp(device, "tap")) { + static const char * const tap_params[] = { +diff --git a/qemu-options.hx b/qemu-options.hx +index a58287c..4d46d6c 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -801,6 +801,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, + " default of 'sndbuf=1048576' can be disabled using 'sndbuf=0'\n" + #endif #endif +#ifdef CONFIG_PCAP -+ "-net pcap[,vlan=n][,ifname=name]\n" -+ " connect the host network interface using PCAP to VLAN 'n'\n" ++ "-net pcap[,vlan=n][,ifname=name]\n" ++ " connect the host network interface using PCAP to VLAN 'n'\n" +#endif - "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n" - " connect the vlan 'n' to another VLAN using a socket connection\n" - "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n" + "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n" + " connect the vlan 'n' to another VLAN using a socket connection\n" + "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n" +-- +1.6.2.1 + diff --git a/0016-i386-linux-user-NPTL-support.patch b/0016-i386-linux-user-NPTL-support.patch new file mode 100644 index 00000000..c8d4d65a --- /dev/null +++ b/0016-i386-linux-user-NPTL-support.patch @@ -0,0 +1,64 @@ +From d6f4cb8539685ddb6f3ecd8f043c33a3213b0d56 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 16 Apr 2009 15:14:12 +0200 +Subject: [PATCH 16/33] i386-linux-user NPTL support + +Makes NPTL binaries run by implementing TLS. + +Signed-off-by: Ulrich Hecht +--- + configure | 1 + + linux-user/syscall.c | 16 ++++++++++++++-- + 2 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/configure b/configure +index d104413..97ca826 100755 +--- a/configure ++++ b/configure +@@ -1901,6 +1901,7 @@ TARGET_ABI_DIR="" + case "$target_arch2" in + i386) + target_phys_bits=32 ++ target_nptl="yes" + ;; + x86_64) + TARGET_BASE_ARCH=i386 +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index faf41b1..87ceac7 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3575,8 +3575,14 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, + ts->child_tidptr = child_tidptr; + } + +- if (nptl_flags & CLONE_SETTLS) ++ if (nptl_flags & CLONE_SETTLS) { ++#if defined(TARGET_I386) && defined(TARGET_ABI32) ++ do_set_thread_area(new_env, newtls); ++ cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector); ++#else + cpu_set_tls (new_env, newtls); ++#endif ++ } + + /* Grab a mutex so that thread setup appears atomic. */ + pthread_mutex_lock(&clone_lock); +@@ -3648,8 +3654,14 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, + if (flags & CLONE_PARENT_SETTID) + put_user_u32(gettid(), parent_tidptr); + ts = (TaskState *)env->opaque; +- if (flags & CLONE_SETTLS) ++ if (flags & CLONE_SETTLS) { ++#if defined(TARGET_I386) && defined(TARGET_ABI32) ++ do_set_thread_area(env, newtls); ++ cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector); ++#else + cpu_set_tls (env, newtls); ++#endif ++ } + if (flags & CLONE_CHILD_CLEARTID) + ts->child_tidptr = child_tidptr; + #endif +-- +1.6.2.1 + diff --git a/0017-qemu-0.11-git-ioctl_mount.patch b/0017-qemu-0.11-git-ioctl_mount.patch new file mode 100644 index 00000000..0723b291 --- /dev/null +++ b/0017-qemu-0.11-git-ioctl_mount.patch @@ -0,0 +1,25 @@ +From dc645f74998b4beeee36b37e81c3a358e75be0b1 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Wed, 17 Jun 2009 14:54:48 +0200 +Subject: [PATCH 17/33] qemu-0.11-git-ioctl_mount + +--- + linux-user/ioctls.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h +index aee5a88..a0fb052 100644 +--- a/linux-user/ioctls.h ++++ b/linux-user/ioctls.h +@@ -310,7 +310,7 @@ + IOCTL(LOOP_CLR_FD, 0, TYPE_INT) + IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) + IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) +-#if 0 /* These have some problems - not fully tested */ ++#if 1 /* These have some problems - not fully tested */ + IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) + IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) + #endif +-- +1.6.2.1 + diff --git a/0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch b/0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch new file mode 100644 index 00000000..27bd43fb --- /dev/null +++ b/0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch @@ -0,0 +1,116 @@ +From 075e9351395b1000568b215589eb3f1f7fdcb7a1 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Wed, 17 Jun 2009 15:08:38 +0200 +Subject: [PATCH 18/33] qemu-0.11-git-user-linux-ppc-uid16_fix + +--- + linux-user/ppc/syscall_nr.h | 30 +++++++++++++++--------------- + linux-user/syscall_defs.h | 2 +- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h +index f54276b..cc84a4c 100644 +--- a/linux-user/ppc/syscall_nr.h ++++ b/linux-user/ppc/syscall_nr.h +@@ -17,15 +17,15 @@ + #define TARGET_NR_time 13 + #define TARGET_NR_mknod 14 + #define TARGET_NR_chmod 15 +-#define TARGET_NR_lchown32 16 ++#define TARGET_NR_lchown 16 + #define TARGET_NR_break 17 + #define TARGET_NR_oldstat 18 + #define TARGET_NR_lseek 19 + #define TARGET_NR_getpid 20 + #define TARGET_NR_mount 21 + #define TARGET_NR_umount 22 +-#define TARGET_NR_setuid32 23 +-#define TARGET_NR_getuid32 24 ++#define TARGET_NR_setuid 23 ++#define TARGET_NR_getuid 24 + #define TARGET_NR_stime 25 + #define TARGET_NR_ptrace 26 + #define TARGET_NR_alarm 27 +@@ -47,11 +47,11 @@ + #define TARGET_NR_times 43 + #define TARGET_NR_prof 44 + #define TARGET_NR_brk 45 +-#define TARGET_NR_setgid32 46 +-#define TARGET_NR_getgid32 47 ++#define TARGET_NR_setgid 46 ++#define TARGET_NR_getgid 47 + #define TARGET_NR_signal 48 +-#define TARGET_NR_geteuid32 49 +-#define TARGET_NR_getegid32 50 ++#define TARGET_NR_geteuid 49 ++#define TARGET_NR_getegid 50 + #define TARGET_NR_acct 51 + #define TARGET_NR_umount2 52 + #define TARGET_NR_lock 53 +@@ -71,8 +71,8 @@ + #define TARGET_NR_sigaction 67 + #define TARGET_NR_sgetmask 68 + #define TARGET_NR_ssetmask 69 +-#define TARGET_NR_setreuid32 70 +-#define TARGET_NR_setregid32 71 ++#define TARGET_NR_setreuid 70 ++#define TARGET_NR_setregid 71 + #define TARGET_NR_sigsuspend 72 + #define TARGET_NR_sigpending 73 + #define TARGET_NR_sethostname 74 +@@ -81,8 +81,8 @@ + #define TARGET_NR_getrusage 77 + #define TARGET_NR_gettimeofday 78 + #define TARGET_NR_settimeofday 79 +-#define TARGET_NR_getgroups32 80 +-#define TARGET_NR_setgroups32 81 ++#define TARGET_NR_getgroups 80 ++#define TARGET_NR_setgroups 81 + #define TARGET_NR_select 82 + #define TARGET_NR_symlink 83 + #define TARGET_NR_oldlstat 84 +@@ -96,7 +96,7 @@ + #define TARGET_NR_truncate 92 + #define TARGET_NR_ftruncate 93 + #define TARGET_NR_fchmod 94 +-#define TARGET_NR_fchown32 95 ++#define TARGET_NR_fchown 95 + #define TARGET_NR_getpriority 96 + #define TARGET_NR_setpriority 97 + #define TARGET_NR_profil 98 +@@ -139,8 +139,8 @@ + #define TARGET_NR_sysfs 135 + #define TARGET_NR_personality 136 + #define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +-#define TARGET_NR_setfsuid32 138 +-#define TARGET_NR_setfsgid32 139 ++#define TARGET_NR_setfsuid 138 ++#define TARGET_NR_setfsgid 139 + #define TARGET_NR__llseek 140 + #define TARGET_NR_getdents 141 + #define TARGET_NR__newselect 142 +@@ -182,7 +182,7 @@ + #define TARGET_NR_rt_sigsuspend 178 + #define TARGET_NR_pread64 179 + #define TARGET_NR_pwrite64 180 +-#define TARGET_NR_chown32 181 ++#define TARGET_NR_chown 181 + #define TARGET_NR_getcwd 182 + #define TARGET_NR_capget 183 + #define TARGET_NR_capset 184 +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index 78c6488..0cbe396 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -49,7 +49,7 @@ + #define TARGET_IOC_TYPEBITS 8 + + #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ +- || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) ++ || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) || defined(TARGET_PPC) + /* 16 bit uid wrappers emulation */ + #define USE_UID16 + #endif +-- +1.6.2.1 + diff --git a/0019-Rewrite-mmap_find_vma-to-work-fine-on-64-bit-hosts.patch b/0019-Rewrite-mmap_find_vma-to-work-fine-on-64-bit-hosts.patch new file mode 100644 index 00000000..27091fa3 --- /dev/null +++ b/0019-Rewrite-mmap_find_vma-to-work-fine-on-64-bit-hosts.patch @@ -0,0 +1,125 @@ +From c77c088e30c44fc8677d7d95cb2180d8dfb43b1c Mon Sep 17 00:00:00 2001 +From: Kirill A. Shutemov +Date: Wed, 17 Jun 2009 15:14:43 +0200 +Subject: [PATCH 19/33] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets + +From: Kirill A. Shutemov + +qemu's page table can be incomple if /proc/self/maps is unavailable or +host allocating a memory with mmap(), so we can't use it to find free +memory area. + +New version mmap_find_vma() uses mmap() without MAP_FIXED to find free +memory. + +From: Kirill A. Shutemov + +Signed-off-by: Kirill A. Shutemov +Signed-off-by: Riku Voipio +--- + linux-user/mmap.c | 79 +++++++++++++++++++++++++++++------------------------ + 1 files changed, 43 insertions(+), 36 deletions(-) + +diff --git a/linux-user/mmap.c b/linux-user/mmap.c +index 9ca8f6f..8d94783 100644 +--- a/linux-user/mmap.c ++++ b/linux-user/mmap.c +@@ -277,52 +277,59 @@ static abi_ulong mmap_next_start = 0x40000000; + + unsigned long last_brk; + +-/* find a free memory area of size 'size'. The search starts at +- 'start'. If 'start' == 0, then a default start address is used. +- Return -1 if error. +-*/ +-/* page_init() marks pages used by the host as reserved to be sure not +- to use them. */ ++/* ++ * Find and reserve a free memory area of size 'size'. The search ++ * starts at 'start'. ++ * It must be called with mmap_lock() held. ++ * Return -1 if error. ++ */ + abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) + { +- abi_ulong addr, addr1, addr_start; +- int prot; +- unsigned long new_brk; +- +- new_brk = (unsigned long)sbrk(0); +- if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) { +- /* This is a hack to catch the host allocating memory with brk(). +- If it uses mmap then we loose. +- FIXME: We really want to avoid the host allocating memory in +- the first place, and maybe leave some slack to avoid switching +- to mmap. */ +- page_set_flags(last_brk & TARGET_PAGE_MASK, +- TARGET_PAGE_ALIGN(new_brk), +- PAGE_RESERVED); +- } +- last_brk = new_brk; ++ void *ptr; ++ abi_ulong addr; + + size = HOST_PAGE_ALIGN(size); +- start = start & qemu_host_page_mask; ++ start &= qemu_host_page_mask; ++ ++ /* If 'start' == 0, then a default start address is used. */ ++ if (start == 0) ++ start = mmap_next_start; ++ + addr = start; +- if (addr == 0) +- addr = mmap_next_start; +- addr_start = addr; ++ + for(;;) { +- prot = 0; +- for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { +- prot |= page_get_flags(addr1); +- } +- if (prot == 0) ++ /* ++ * Reserve needed memory area to avoid a race. ++ * It should be discarded using: ++ * - mmap() with MAP_FIXED flag ++ * - mremap() with MREMAP_FIXED flag ++ * - shmat() with SHM_REMAP flag ++ */ ++ ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE, ++ MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); ++ ++ /* ENOMEM, if host address space has no memory */ ++ if (ptr == MAP_FAILED) ++ return (abi_ulong)-1; ++ ++ /* If address fits target address space we've found what we need */ ++ if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1) + break; ++ ++ /* Unmap and try again with new page */ ++ munmap(ptr, size); + addr += qemu_host_page_size; +- /* we found nothing */ +- if (addr == addr_start) ++ ++ /* ENOMEM if we check whole of target address space */ ++ if (addr == start) + return (abi_ulong)-1; + } +- if (start == 0) +- mmap_next_start = addr + size; +- return addr; ++ ++ /* Update default start address */ ++ if (start == mmap_next_start) ++ mmap_next_start = (unsigned long)ptr + size; ++ ++ return h2g(ptr); + } + + #define SNDRV_PCM_MMAP_OFFSET_STATUS 0x80000000 +-- +1.6.2.1 + diff --git a/0020-TCG-sync-op-32-bit-targets-fixed.patch b/0020-TCG-sync-op-32-bit-targets-fixed.patch new file mode 100644 index 00000000..77393ae2 --- /dev/null +++ b/0020-TCG-sync-op-32-bit-targets-fixed.patch @@ -0,0 +1,82 @@ +From 3d1745fd8e80e99b435b63b650b9b31202aace6c Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 24 Jul 2009 17:25:37 +0200 +Subject: [PATCH 20/33] TCG "sync" op (32-bit targets fixed) + +sync allows concurrent accesses to locations in memory through different TCG +variables. This comes in handy when you are emulating CPU registers that can +be used as either 32 or 64 bit, as TCG doesn't know anything about aliases. +See the s390x target for an example. + +Fixed to not break 32-bit target builds. + +Signed-off-by: Ulrich Hecht +--- + tcg/tcg-op.h | 12 ++++++++++++ + tcg/tcg-opc.h | 2 ++ + tcg/tcg.c | 6 ++++++ + 3 files changed, 20 insertions(+), 0 deletions(-) + +diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h +index f3f2f71..6bcaf5b 100644 +--- a/tcg/tcg-op.h ++++ b/tcg/tcg-op.h +@@ -316,6 +316,18 @@ static inline void tcg_gen_br(int label) + tcg_gen_op1i(INDEX_op_br, label); + } + ++static inline void tcg_gen_sync_i32(TCGv_i32 arg) ++{ ++ tcg_gen_op1_i32(INDEX_op_sync_i32, arg); ++} ++ ++#if TCG_TARGET_REG_BITS == 64 ++static inline void tcg_gen_sync_i64(TCGv_i64 arg) ++{ ++ tcg_gen_op1_i64(INDEX_op_sync_i64, arg); ++} ++#endif ++ + static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg) + { + if (!TCGV_EQUAL_I32(ret, arg)) +diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h +index 3a095fc..654a45f 100644 +--- a/tcg/tcg-opc.h ++++ b/tcg/tcg-opc.h +@@ -40,6 +40,7 @@ DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ + DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + ++DEF2(sync_i32, 0, 1, 0, 0) + DEF2(mov_i32, 1, 1, 0, 0) + DEF2(movi_i32, 1, 0, 1, 0) + /* load/store */ +@@ -103,6 +104,7 @@ DEF2(neg_i32, 1, 1, 0, 0) + #endif + + #if TCG_TARGET_REG_BITS == 64 ++DEF2(sync_i64, 0, 1, 0, 0) + DEF2(mov_i64, 1, 1, 0, 0) + DEF2(movi_i64, 1, 0, 1, 0) + /* load/store */ +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 299bff6..86e16fa 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -1927,6 +1927,12 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, + // dump_regs(s); + #endif + switch(opc) { ++ case INDEX_op_sync_i32: ++#if TCG_TARGET_REG_BITS == 64 ++ case INDEX_op_sync_i64: ++#endif ++ temp_save(s, args[0], s->reserved_regs); ++ break; + case INDEX_op_mov_i32: + #if TCG_TARGET_REG_BITS == 64 + case INDEX_op_mov_i64: +-- +1.6.2.1 + diff --git a/0021-S-390-CPU-emulation.patch b/0021-S-390-CPU-emulation.patch new file mode 100644 index 00000000..e3ea35fd --- /dev/null +++ b/0021-S-390-CPU-emulation.patch @@ -0,0 +1,4753 @@ +From 6f64dc32ad5765393ec33b766a8de833963fd46f Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 24 Jul 2009 16:58:54 +0200 +Subject: [PATCH 21/33] S/390 CPU emulation + +Currently only does userspace with 64-bit addressing, but it's quite good +at that. + +Signed-off-by: Ulrich Hecht +--- + cpu-exec.c | 42 + + disas.c | 3 + + s390-dis.c | 4 +- + target-s390x/cpu.h | 131 +++ + target-s390x/exec.h | 51 + + target-s390x/helper.c | 81 ++ + target-s390x/helpers.h | 128 +++ + target-s390x/op_helper.c | 1719 ++++++++++++++++++++++++++++++++ + target-s390x/translate.c | 2479 ++++++++++++++++++++++++++++++++++++++++++++++ + 9 files changed, 4636 insertions(+), 2 deletions(-) + create mode 100644 target-s390x/cpu.h + create mode 100644 target-s390x/exec.h + create mode 100644 target-s390x/helper.c + create mode 100644 target-s390x/helpers.h + create mode 100644 target-s390x/op_helper.c + create mode 100644 target-s390x/translate.c + +diff --git a/cpu-exec.c b/cpu-exec.c +index 2385d56..855ea3e 100644 +--- a/cpu-exec.c ++++ b/cpu-exec.c +@@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1) + #elif defined(TARGET_MIPS) + #elif defined(TARGET_SH4) + #elif defined(TARGET_CRIS) ++#elif defined(TARGET_S390X) + /* XXXXX */ + #else + #error unsupported target CPU +@@ -712,6 +713,7 @@ int cpu_exec(CPUState *env1) + #elif defined(TARGET_SH4) + #elif defined(TARGET_ALPHA) + #elif defined(TARGET_CRIS) ++#elif defined(TARGET_S390X) + /* XXXXX */ + #else + #error unsupported target CPU +@@ -1234,6 +1236,46 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + return 1; + } + ++#elif defined (TARGET_S390X) ++static inline int handle_cpu_signal(unsigned long pc, unsigned long address, ++ int is_write, sigset_t *old_set, ++ void *puc) ++{ ++ TranslationBlock *tb; ++ int ret; ++ ++ if (cpu_single_env) ++ env = cpu_single_env; /* XXX: find a correct solution for multithread */ ++#if defined(DEBUG_SIGNAL) ++ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", ++ pc, address, is_write, *(unsigned long *)old_set); ++#endif ++ /* XXX: locking issue */ ++ if (is_write && page_unprotect(h2g(address), pc, puc)) { ++ return 1; ++ } ++ ++ /* see if it is an MMU fault */ ++ ret = cpu_s390x_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); ++ if (ret < 0) ++ return 0; /* not an MMU fault */ ++ if (ret == 0) ++ return 1; /* the MMU fault was handled without causing real CPU fault */ ++ ++ /* now we have a real cpu fault */ ++ tb = tb_find_pc(pc); ++ if (tb) { ++ /* the PC is inside the translated code. It means that we have ++ a virtual CPU fault */ ++ cpu_restore_state(tb, env, pc, puc); ++ } ++ /* we restore the process signal mask as the sigreturn should ++ do it (XXX: use sigsetjmp) */ ++ sigprocmask(SIG_SETMASK, old_set, NULL); ++ cpu_loop_exit(); ++ /* never comes here */ ++ return 1; ++} + #else + #error unsupported target CPU + #endif +diff --git a/disas.c b/disas.c +index af5a9ea..da5b1a5 100644 +--- a/disas.c ++++ b/disas.c +@@ -195,6 +195,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) + #elif defined(TARGET_CRIS) + disasm_info.mach = bfd_mach_cris_v32; + print_insn = print_insn_crisv32; ++#elif defined(TARGET_S390X) ++ disasm_info.mach = bfd_mach_s390_64; ++ print_insn = print_insn_s390; + #elif defined(TARGET_MICROBLAZE) + disasm_info.mach = bfd_arch_microblaze; + print_insn = print_insn_microblaze; +diff --git a/s390-dis.c b/s390-dis.c +index 86dd84f..9a73a57 100644 +--- a/s390-dis.c ++++ b/s390-dis.c +@@ -191,10 +191,10 @@ init_disasm (struct disassemble_info *info) + // switch (info->mach) + // { + // case bfd_mach_s390_31: +- current_arch_mask = 1 << S390_OPCODE_ESA; ++// current_arch_mask = 1 << S390_OPCODE_ESA; + // break; + // case bfd_mach_s390_64: +-// current_arch_mask = 1 << S390_OPCODE_ZARCH; ++ current_arch_mask = 1 << S390_OPCODE_ZARCH; + // break; + // default: + // abort (); +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +new file mode 100644 +index 0000000..3505df4 +--- /dev/null ++++ b/target-s390x/cpu.h +@@ -0,0 +1,131 @@ ++/* ++ * S/390 virtual CPU header ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ++ */ ++#ifndef CPU_S390X_H ++#define CPU_S390X_H ++ ++#define TARGET_LONG_BITS 64 ++ ++#define ELF_MACHINE EM_S390 ++ ++#define CPUState struct CPUS390XState ++ ++#include "cpu-defs.h" ++ ++#include "softfloat.h" ++ ++#define NB_MMU_MODES 2 // guess ++#define MMU_USER_IDX 0 // guess ++ ++typedef union FPReg { ++ struct { ++#ifdef WORDS_BIGENDIAN ++ float32 e; ++ int32_t __pad; ++#else ++ int32_t __pad; ++ float32 e; ++#endif ++ }; ++ float64 d; ++ uint64_t i; ++} FPReg; ++ ++typedef struct CPUS390XState { ++ uint64_t regs[16]; /* GP registers */ ++ ++ uint32_t aregs[16]; /* access registers */ ++ ++ uint32_t fpc; /* floating-point control register */ ++ FPReg fregs[16]; /* FP registers */ ++ float_status fpu_status; /* passed to softfloat lib */ ++ ++ struct { ++ uint64_t mask; ++ uint64_t addr; ++ } psw; ++ ++ int cc; /* condition code (0-3) */ ++ ++ uint64_t __excp_addr; ++ ++ CPU_COMMON ++} CPUS390XState; ++ ++#if defined(CONFIG_USER_ONLY) ++static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) ++{ ++ if (newsp) ++ env->regs[15] = newsp; ++ env->regs[0] = 0; ++} ++#endif ++ ++CPUS390XState *cpu_s390x_init(const char *cpu_model); ++void s390x_translate_init(void); ++int cpu_s390x_exec(CPUS390XState *s); ++void cpu_s390x_close(CPUS390XState *s); ++void do_interrupt (CPUState *env); ++ ++/* you can call this signal handler from your SIGBUS and SIGSEGV ++ signal handlers to inform the virtual CPU of exceptions. non zero ++ is returned if the signal was handled by the virtual CPU. */ ++int cpu_s390x_signal_handler(int host_signum, void *pinfo, ++ void *puc); ++int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, ++ int mmu_idx, int is_softmuu); ++ ++void cpu_lock(void); ++void cpu_unlock(void); ++ ++static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) ++{ ++ env->aregs[0] = newtls >> 32; ++ env->aregs[1] = newtls & 0xffffffffULL; ++} ++ ++#define TARGET_PAGE_BITS 12 // guess ++ ++#define cpu_init cpu_s390x_init ++#define cpu_exec cpu_s390x_exec ++#define cpu_gen_code cpu_s390x_gen_code ++#define cpu_signal_handler cpu_s390x_signal_handler ++//#define cpu_list s390x_cpu_list ++ ++#include "cpu-all.h" ++#include "exec-all.h" ++ ++#define EXCP_OPEX 1 /* operation exception (sigill) */ ++#define EXCP_SVC 2 /* supervisor call (syscall) */ ++#define EXCP_ADDR 5 /* addressing exception */ ++#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ ++ ++static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) ++{ ++ env->psw.addr = tb->pc; ++} ++ ++static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, ++ target_ulong *cs_base, int *flags) ++{ ++ *pc = env->psw.addr; ++ *cs_base = 0; ++ *flags = env->psw.mask; // guess ++} ++#endif +diff --git a/target-s390x/exec.h b/target-s390x/exec.h +new file mode 100644 +index 0000000..5198359 +--- /dev/null ++++ b/target-s390x/exec.h +@@ -0,0 +1,51 @@ ++/* ++ * S/390 execution defines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ++ */ ++ ++#include "dyngen-exec.h" ++ ++register struct CPUS390XState *env asm(AREG0); ++ ++#include "cpu.h" ++#include "exec-all.h" ++ ++static inline int cpu_has_work(CPUState *env) ++{ ++ return env->interrupt_request & CPU_INTERRUPT_HARD; // guess ++} ++ ++static inline void regs_to_env(void) ++{ ++} ++ ++static inline void env_to_regs(void) ++{ ++} ++ ++static inline int cpu_halted(CPUState *env) ++{ ++ if (!env->halted) { ++ return 0; ++ } ++ if (cpu_has_work(env)) { ++ env->halted = 0; ++ return 0; ++ } ++ return EXCP_HALTED; ++} +diff --git a/target-s390x/helper.c b/target-s390x/helper.c +new file mode 100644 +index 0000000..5407c62 +--- /dev/null ++++ b/target-s390x/helper.c +@@ -0,0 +1,81 @@ ++/* ++ * S/390 helpers ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++ ++#include "cpu.h" ++#include "exec-all.h" ++#include "gdbstub.h" ++#include "qemu-common.h" ++ ++CPUS390XState *cpu_s390x_init(const char *cpu_model) ++{ ++ CPUS390XState *env; ++ static int inited = 0; ++ ++ env = qemu_mallocz(sizeof(CPUS390XState)); ++ cpu_exec_init(env); ++ if (!inited) { ++ inited = 1; ++ s390x_translate_init(); ++ } ++ ++ env->cpu_model_str = cpu_model; ++ cpu_reset(env); ++ qemu_init_vcpu(env); ++ return env; ++} ++ ++#if defined(CONFIG_USER_ONLY) ++ ++void do_interrupt (CPUState *env) ++{ ++ env->exception_index = -1; ++} ++ ++int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ++ int mmu_idx, int is_softmmu) ++{ ++ //fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n", __FUNCTION__, address, rw, mmu_idx, is_softmmu); ++ env->exception_index = EXCP_ADDR; ++ env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ ++ return 1; ++} ++ ++target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ++{ ++ return addr; ++} ++ ++#endif /* CONFIG_USER_ONLY */ ++ ++void cpu_reset(CPUS390XState *env) ++{ ++ if (qemu_loglevel_mask(CPU_LOG_RESET)) { ++ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); ++ log_cpu_state(env, 0); ++ } ++ ++ memset(env, 0, offsetof(CPUS390XState, breakpoints)); ++ /* FIXME: reset vector? */ ++ tlb_flush(env, 1); ++} +diff --git a/target-s390x/helpers.h b/target-s390x/helpers.h +new file mode 100644 +index 0000000..0ba2086 +--- /dev/null ++++ b/target-s390x/helpers.h +@@ -0,0 +1,128 @@ ++#include "def-helper.h" ++ ++DEF_HELPER_1(exception, void, i32) ++DEF_HELPER_4(nc, i32, i32, i32, i32, i32) ++DEF_HELPER_4(oc, i32, i32, i32, i32, i32) ++DEF_HELPER_4(xc, i32, i32, i32, i32, i32) ++DEF_HELPER_4(mvc, void, i32, i32, i32, i32) ++DEF_HELPER_4(clc, i32, i32, i32, i32, i32) ++DEF_HELPER_4(lmg, void, i32, i32, i32, s32) ++DEF_HELPER_4(stmg, void, i32, i32, i32, s32) ++DEF_HELPER_FLAGS_1(set_cc_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) ++DEF_HELPER_FLAGS_1(set_cc_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) ++DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) ++DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) ++DEF_HELPER_FLAGS_1(set_cc_nz_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32) ++DEF_HELPER_FLAGS_1(set_cc_nz_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64) ++DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) ++DEF_HELPER_4(brc, void, i32, i32, i64, s32) ++DEF_HELPER_3(brctg, void, i64, i64, s32) ++DEF_HELPER_3(brct, void, i32, i64, s32) ++DEF_HELPER_4(brcl, void, i32, i32, i64, s64) ++DEF_HELPER_4(bcr, void, i32, i32, i64, i64) ++DEF_HELPER_4(bc, void, i32, i32, i64, i64) ++DEF_HELPER_FLAGS_2(cmp_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64) ++DEF_HELPER_FLAGS_2(cmp_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) ++DEF_HELPER_FLAGS_2(cmp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32) ++DEF_HELPER_FLAGS_2(cmp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64) ++DEF_HELPER_3(clm, i32, i32, i32, i64) ++DEF_HELPER_3(stcm, void, i32, i32, i64) ++DEF_HELPER_2(mlg, void, i32, i64) ++DEF_HELPER_2(dlg, void, i32, i64) ++DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) ++DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) ++DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) ++DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) ++DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) ++DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) ++DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) ++DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) ++DEF_HELPER_3(srst, i32, i32, i32, i32) ++DEF_HELPER_3(clst, i32, i32, i32, i32) ++DEF_HELPER_3(mvst, i32, i32, i32, i32) ++DEF_HELPER_3(csg, i32, i32, i64, i32) ++DEF_HELPER_3(cdsg, i32, i32, i64, i32) ++DEF_HELPER_3(cs, i32, i32, i64, i32) ++DEF_HELPER_4(ex, i32, i32, i64, i64, i64) ++DEF_HELPER_FLAGS_2(tm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) ++DEF_HELPER_FLAGS_2(tmxx, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i32) ++DEF_HELPER_2(abs_i32, i32, i32, s32) ++DEF_HELPER_2(nabs_i32, i32, i32, s32) ++DEF_HELPER_2(abs_i64, i32, i32, s64) ++DEF_HELPER_2(nabs_i64, i32, i32, s64) ++DEF_HELPER_3(stcmh, i32, i32, i64, i32) ++DEF_HELPER_3(icmh, i32, i32, i64, i32) ++DEF_HELPER_2(ipm, void, i32, i32) ++DEF_HELPER_3(addc_u32, i32, i32, i32, i32) ++DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) ++DEF_HELPER_3(stam, void, i32, i64, i32) ++DEF_HELPER_3(mvcle, i32, i32, i64, i32) ++DEF_HELPER_3(clcle, i32, i32, i64, i32) ++DEF_HELPER_4(slb, i32, i32, i32, i32, i32) ++DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) ++DEF_HELPER_2(cefbr, void, i32, s32) ++DEF_HELPER_2(cdfbr, void, i32, s32) ++DEF_HELPER_2(cxfbr, void, i32, s32) ++DEF_HELPER_2(cegbr, void, i32, s64) ++DEF_HELPER_2(cdgbr, void, i32, s64) ++DEF_HELPER_2(cxgbr, void, i32, s64) ++DEF_HELPER_2(adbr, i32, i32, i32) ++DEF_HELPER_2(aebr, i32, i32, i32) ++DEF_HELPER_2(sebr, i32, i32, i32) ++DEF_HELPER_2(sdbr, i32, i32, i32) ++DEF_HELPER_2(debr, void, i32, i32) ++DEF_HELPER_2(dxbr, void, i32, i32) ++DEF_HELPER_2(mdbr, void, i32, i32) ++DEF_HELPER_2(mxbr, void, i32, i32) ++DEF_HELPER_2(ldebr, void, i32, i32) ++DEF_HELPER_2(ldxbr, void, i32, i32) ++DEF_HELPER_2(lxdbr, void, i32, i32) ++DEF_HELPER_2(ledbr, void, i32, i32) ++DEF_HELPER_2(lexbr, void, i32, i32) ++DEF_HELPER_2(lpebr, i32, i32, i32) ++DEF_HELPER_2(lpdbr, i32, i32, i32) ++DEF_HELPER_2(lpxbr, i32, i32, i32) ++DEF_HELPER_2(ltebr, i32, i32, i32) ++DEF_HELPER_2(ltdbr, i32, i32, i32) ++DEF_HELPER_2(ltxbr, i32, i32, i32) ++DEF_HELPER_2(lcebr, i32, i32, i32) ++DEF_HELPER_2(lcdbr, i32, i32, i32) ++DEF_HELPER_2(lcxbr, i32, i32, i32) ++DEF_HELPER_2(ceb, i32, i32, i64) ++DEF_HELPER_2(aeb, i32, i32, i64) ++DEF_HELPER_2(deb, void, i32, i64) ++DEF_HELPER_2(meeb, void, i32, i64) ++DEF_HELPER_2(cdb, i32, i32, i64) ++DEF_HELPER_2(adb, i32, i32, i64) ++DEF_HELPER_2(seb, i32, i32, i64) ++DEF_HELPER_2(sdb, i32, i32, i64) ++DEF_HELPER_2(mdb, void, i32, i64) ++DEF_HELPER_2(ddb, void, i32, i64) ++DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) ++DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) ++DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) ++DEF_HELPER_3(cgebr, i32, i32, i32, i32) ++DEF_HELPER_3(cgdbr, i32, i32, i32, i32) ++DEF_HELPER_3(cgxbr, i32, i32, i32, i32) ++DEF_HELPER_1(lzer, void, i32) ++DEF_HELPER_1(lzdr, void, i32) ++DEF_HELPER_1(lzxr, void, i32) ++DEF_HELPER_3(cfebr, i32, i32, i32, i32) ++DEF_HELPER_3(cfdbr, i32, i32, i32, i32) ++DEF_HELPER_3(cfxbr, i32, i32, i32, i32) ++DEF_HELPER_2(axbr, i32, i32, i32) ++DEF_HELPER_2(sxbr, i32, i32, i32) ++DEF_HELPER_2(meebr, void, i32, i32) ++DEF_HELPER_2(ddbr, void, i32, i32) ++DEF_HELPER_3(madb, void, i32, i64, i32) ++DEF_HELPER_3(maebr, void, i32, i32, i32) ++DEF_HELPER_3(madbr, void, i32, i32, i32) ++DEF_HELPER_3(msdbr, void, i32, i32, i32) ++DEF_HELPER_2(lxdb, void, i32, i64) ++DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) ++DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) ++DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) ++DEF_HELPER_2(flogr, i32, i32, i64) ++DEF_HELPER_2(sqdbr, void, i32, i32) ++ ++#include "def-helper.h" +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +new file mode 100644 +index 0000000..5de4d08 +--- /dev/null ++++ b/target-s390x/op_helper.c +@@ -0,0 +1,1719 @@ ++/* ++ * S/390 helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ++ */ ++ ++#include "exec.h" ++#include "helpers.h" ++#include ++ ++//#define DEBUG_HELPER ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++/* raise an exception */ ++void HELPER(exception)(uint32_t excp) ++{ ++ HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); ++ env->exception_index = excp; ++ cpu_loop_exit(); ++} ++ ++/* and on array */ ++uint32_t HELPER(nc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) ++{ ++ uint64_t dest = env->regs[b >> 4] + d1; ++ uint64_t src = env->regs[b & 0xf] + d2; ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) & ldub(src + i); ++ if (x) cc = 1; ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* xor on array */ ++uint32_t HELPER(xc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) ++{ ++ uint64_t dest = env->regs[b >> 4] + d1; ++ uint64_t src = env->regs[b & 0xf] + d2; ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) ^ ldub(src + i); ++ if (x) cc = 1; ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* or on array */ ++uint32_t HELPER(oc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) ++{ ++ uint64_t dest = env->regs[b >> 4] + d1; ++ uint64_t src = env->regs[b & 0xf] + d2; ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) | ldub(src + i); ++ if (x) cc = 1; ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* memcopy */ ++void HELPER(mvc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) ++{ ++ uint64_t dest = env->regs[b >> 4] + d1; ++ uint64_t src = env->regs[b & 0xf] + d2; ++ int i; ++ HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); ++ for (i = 0; i <= l; i++) { ++ stb(dest + i, ldub(src + i)); ++ } ++} ++ ++/* compare unsigned byte arrays */ ++uint32_t HELPER(clc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) ++{ ++ uint64_t s1 = env->regs[b >> 4] + d1; ++ uint64_t s2 = env->regs[b & 0xf] + d2; ++ int i; ++ unsigned char x,y; ++ uint32_t cc; ++ HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); ++ for (i = 0; i <= l; i++) { ++ x = ldub(s1 + i); ++ y = ldub(s2 + i); ++ HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); ++ if (x < y) { ++ cc = 1; ++ goto done; ++ } ++ else if (x > y) { ++ cc = 2; ++ goto done; ++ } ++ } ++ cc = 0; ++done: ++ HELPER_LOG("\n"); ++ return cc; ++} ++ ++/* load multiple 64-bit registers from memory */ ++void HELPER(lmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) ++{ ++ uint64_t src = env->regs[b2] + d2; ++ for (;;) { ++ env->regs[r1] = ldq(src); ++ src += 8; ++ if (r1 == r3) break; ++ r1 = (r1 + 1) & 15; ++ } ++} ++ ++/* store multiple 64-bit registers to memory */ ++void HELPER(stmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) ++{ ++ uint64_t dest = env->regs[b2] + d2; ++ HELPER_LOG("%s: r1 %d r3 %d\n", __FUNCTION__, r1, r3); ++ for (;;) { ++ HELPER_LOG("storing r%d in 0x%lx\n", r1, dest); ++ stq(dest, env->regs[r1]); ++ dest += 8; ++ if (r1 == r3) break; ++ r1 = (r1 + 1) & 15; ++ } ++} ++ ++/* set condition code for signed 32-bit arithmetics */ ++uint32_t HELPER(set_cc_s32)(int32_t v) ++{ ++ if (v < 0) return 1; ++ else if (v > 0) return 2; ++ else return 0; ++} ++ ++/* set condition code for signed 64-bit arithmetics */ ++uint32_t HELPER(set_cc_s64)(int64_t v) ++{ ++ if (v < 0) return 1; ++ else if (v > 0) return 2; ++ else return 0; ++} ++ ++/* set condition code for signed 32-bit two's complement */ ++uint32_t HELPER(set_cc_comp_s32)(int32_t v) ++{ ++ if ((uint32_t)v == 0x80000000UL) return 3; ++ else if (v < 0) return 1; ++ else if (v > 0) return 2; ++ else return 0; ++} ++ ++/* set condition code for signed 64-bit two's complement */ ++uint32_t HELPER(set_cc_comp_s64)(int64_t v) ++{ ++ if ((uint64_t)v == 0x8000000000000000ULL) return 3; ++ else if (v < 0) return 1; ++ else if (v > 0) return 2; ++ else return 0; ++} ++ ++/* set negative/zero condition code for 32-bit logical op */ ++uint32_t HELPER(set_cc_nz_u32)(uint32_t v) ++{ ++ if (v) return 1; ++ else return 0; ++} ++ ++/* set negative/zero condition code for 64-bit logical op */ ++uint32_t HELPER(set_cc_nz_u64)(uint64_t v) ++{ ++ if (v) return 1; ++ else return 0; ++} ++ ++/* set condition code for insert character under mask insn */ ++uint32_t HELPER(set_cc_icm)(uint32_t mask, uint32_t val) ++{ ++ HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); ++ uint32_t cc; ++ if (!val || !mask) cc = 0; ++ else { ++ while (mask != 1) { ++ mask >>= 1; ++ val >>= 8; ++ } ++ if (val & 0x80) cc = 1; ++ else cc = 2; ++ } ++ return cc; ++} ++ ++/* relative conditional branch */ ++void HELPER(brc)(uint32_t cc, uint32_t mask, uint64_t pc, int32_t offset) ++{ ++ if ( mask & ( 1 << (3 - cc) ) ) { ++ env->psw.addr = pc + offset; ++ } ++ else { ++ env->psw.addr = pc + 4; ++ } ++} ++ ++/* branch relative on 64-bit count (condition is computed inline, this only ++ does the branch */ ++void HELPER(brctg)(uint64_t flag, uint64_t pc, int32_t offset) ++{ ++ if (flag) { ++ env->psw.addr = pc + offset; ++ } ++ else { ++ env->psw.addr = pc + 4; ++ } ++ HELPER_LOG("%s: pc 0x%lx flag %ld psw.addr 0x%lx\n", __FUNCTION__, pc, flag, ++ env->psw.addr); ++} ++ ++/* branch relative on 32-bit count (condition is computed inline, this only ++ does the branch */ ++void HELPER(brct)(uint32_t flag, uint64_t pc, int32_t offset) ++{ ++ if (flag) { ++ env->psw.addr = pc + offset; ++ } ++ else { ++ env->psw.addr = pc + 4; ++ } ++ HELPER_LOG("%s: pc 0x%lx flag %d psw.addr 0x%lx\n", __FUNCTION__, pc, flag, ++ env->psw.addr); ++} ++ ++/* relative conditional branch with long displacement */ ++void HELPER(brcl)(uint32_t cc, uint32_t mask, uint64_t pc, int64_t offset) ++{ ++ if ( mask & ( 1 << (3 - cc) ) ) { ++ env->psw.addr = pc + offset; ++ } ++ else { ++ env->psw.addr = pc + 6; ++ } ++ HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx\n", __FUNCTION__, pc, env->psw.addr); ++} ++ ++/* conditional branch to register (register content is passed as target) */ ++void HELPER(bcr)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) ++{ ++ if ( mask & ( 1 << (3 - cc) ) ) { ++ env->psw.addr = target; ++ } ++ else { ++ env->psw.addr = pc + 2; ++ } ++} ++ ++/* conditional branch to address (address is passed as target) */ ++void HELPER(bc)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) ++{ ++ if ( mask & ( 1 << (3 - cc) ) ) { ++ env->psw.addr = target; ++ } ++ else { ++ env->psw.addr = pc + 4; ++ } ++ HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx r2 0x%lx r5 0x%lx\n", __FUNCTION__, ++ pc, env->psw.addr, env->regs[2], env->regs[5]); ++} ++ ++/* 64-bit unsigned comparison */ ++uint32_t HELPER(cmp_u64)(uint64_t o1, uint64_t o2) ++{ ++ if (o1 < o2) return 1; ++ else if (o1 > o2) return 2; ++ else return 0; ++} ++ ++/* 32-bit unsigned comparison */ ++uint32_t HELPER(cmp_u32)(uint32_t o1, uint32_t o2) ++{ ++ HELPER_LOG("%s: o1 0x%x o2 0x%x\n", __FUNCTION__, o1, o2); ++ if (o1 < o2) return 1; ++ else if (o1 > o2) return 2; ++ else return 0; ++} ++ ++/* 64-bit signed comparison */ ++uint32_t HELPER(cmp_s64)(int64_t o1, int64_t o2) ++{ ++ HELPER_LOG("%s: o1 %ld o2 %ld\n", __FUNCTION__, o1, o2); ++ if (o1 < o2) return 1; ++ else if (o1 > o2) return 2; ++ else return 0; ++} ++ ++/* 32-bit signed comparison */ ++uint32_t HELPER(cmp_s32)(int32_t o1, int32_t o2) ++{ ++ if (o1 < o2) return 1; ++ else if (o1 > o2) return 2; ++ else return 0; ++} ++ ++/* compare logical under mask */ ++uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) ++{ ++ uint8_t r,d; ++ uint32_t cc; ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); ++ cc = 0; ++ while (mask) { ++ if (mask & 8) { ++ d = ldub(addr); ++ r = (r1 & 0xff000000UL) >> 24; ++ HELPER_LOG("mask 0x%x %02x/%02x (0x%lx) ", mask, r, d, addr); ++ if (r < d) { ++ cc = 1; ++ break; ++ } ++ else if (r > d) { ++ cc = 2; ++ break; ++ } ++ addr++; ++ } ++ mask = (mask << 1) & 0xf; ++ r1 <<= 8; ++ } ++ HELPER_LOG("\n"); ++ return cc; ++} ++ ++/* store character under mask */ ++void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) ++{ ++ uint8_t r; ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); ++ while (mask) { ++ if (mask & 8) { ++ r = (r1 & 0xff000000UL) >> 24; ++ stb(addr, r); ++ HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); ++ addr++; ++ } ++ mask = (mask << 1) & 0xf; ++ r1 <<= 8; ++ } ++ HELPER_LOG("\n"); ++} ++ ++/* 64/64 -> 128 unsigned multiplication */ ++void HELPER(mlg)(uint32_t r1, uint64_t v2) ++{ ++ __uint128_t res = (__uint128_t)env->regs[r1 + 1]; ++ res *= (__uint128_t)v2; ++ env->regs[r1] = (uint64_t)(res >> 64); ++ env->regs[r1 + 1] = (uint64_t)res; ++} ++ ++/* 128 -> 64/64 unsigned division */ ++void HELPER(dlg)(uint32_t r1, uint64_t v2) ++{ ++ __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | ++ (env->regs[r1+1]); ++ uint64_t divisor = v2; ++ __uint128_t quotient = dividend / divisor; ++ env->regs[r1+1] = quotient; ++ __uint128_t remainder = dividend % divisor; ++ env->regs[r1] = remainder; ++ HELPER_LOG("%s: dividend 0x%016lx%016lx divisor 0x%lx quotient 0x%lx rem 0x%lx\n", ++ __FUNCTION__, (uint64_t)(dividend >> 64), (uint64_t)dividend, divisor, (uint64_t)quotient, ++ (uint64_t)remainder); ++} ++ ++/* set condition code for 64-bit signed addition */ ++uint32_t HELPER(set_cc_add64)(int64_t a1, int64_t a2, int64_t ar) ++{ ++ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } ++ else { ++ if (ar < 0) return 1; ++ else if (ar > 0) return 2; ++ else return 0; ++ } ++} ++ ++/* set condition code for 64-bit unsigned addition */ ++uint32_t HELPER(set_cc_addu64)(uint64_t a1, uint64_t a2, uint64_t ar) ++{ ++ if (ar == 0) { ++ if (a1) return 2; ++ else return 0; ++ } ++ else { ++ if (ar < a1 || ar < a2) { ++ return 3; ++ } ++ else { ++ return 1; ++ } ++ } ++} ++ ++/* set condition code for 32-bit signed addition */ ++uint32_t HELPER(set_cc_add32)(int32_t a1, int32_t a2, int32_t ar) ++{ ++ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } ++ else { ++ if (ar < 0) return 1; ++ else if (ar > 0) return 2; ++ else return 0; ++ } ++} ++ ++/* set condition code for 32-bit unsigned addition */ ++uint32_t HELPER(set_cc_addu32)(uint32_t a1, uint32_t a2, uint32_t ar) ++{ ++ if (ar == 0) { ++ if (a1) return 2; ++ else return 0; ++ } ++ else { ++ if (ar < a1 || ar < a2) { ++ return 3; ++ } ++ else { ++ return 1; ++ } ++ } ++} ++ ++/* set condition code for 64-bit signed subtraction */ ++uint32_t HELPER(set_cc_sub64)(int64_t s1, int64_t s2, int64_t sr) ++{ ++ if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { ++ return 3; /* overflow */ ++ } ++ else { ++ if (sr < 0) return 1; ++ else if (sr > 0) return 2; ++ else return 0; ++ } ++} ++ ++/* set condition code for 32-bit signed subtraction */ ++uint32_t HELPER(set_cc_sub32)(int32_t s1, int32_t s2, int32_t sr) ++{ ++ if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { ++ return 3; /* overflow */ ++ } ++ else { ++ if (sr < 0) return 1; ++ else if (sr > 0) return 2; ++ else return 0; ++ } ++} ++ ++/* set condition code for 32-bit unsigned subtraction */ ++uint32_t HELPER(set_cc_subu32)(uint32_t s1, uint32_t s2, uint32_t sr) ++{ ++ if (sr == 0) return 2; ++ else { ++ if (s2 > s1) return 1; ++ else return 3; ++ } ++} ++ ++/* set condition code for 64-bit unsigned subtraction */ ++uint32_t HELPER(set_cc_subu64)(uint64_t s1, uint64_t s2, uint64_t sr) ++{ ++ if (sr == 0) return 2; ++ else { ++ if (s2 > s1) return 1; ++ else return 3; ++ } ++} ++ ++/* search string (c is byte to search, r2 is string, r1 end of string) */ ++uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ HELPER_LOG("%s: c %d *r1 0x%lx *r2 0x%lx\n", __FUNCTION__, c, env->regs[r1], ++ env->regs[r2]); ++ uint64_t i; ++ uint32_t cc; ++ for (i = env->regs[r2]; i != env->regs[r1]; i++) { ++ if (ldub(i) == c) { ++ env->regs[r1] = i; ++ cc = 1; ++ return cc; ++ } ++ } ++ cc = 2; ++ return cc; ++} ++ ++/* unsigned string compare (c is string terminator) */ ++uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ uint64_t s1 = env->regs[r1]; ++ uint64_t s2 = env->regs[r2]; ++ uint8_t v1, v2; ++ uint32_t cc; ++ c = c & 0xff; ++#ifdef CONFIG_USER_ONLY ++ if (!c) { ++ HELPER_LOG("%s: comparing '%s' and '%s'\n", ++ __FUNCTION__, (char*)s1, (char*)s2); ++ } ++#endif ++ for (;;) { ++ v1 = ldub(s1); ++ v2 = ldub(s2); ++ if (v1 == c || v2 == c) break; ++ if (v1 != v2) break; ++ s1++; s2++; ++ } ++ ++ if (v1 == v2) cc = 0; ++ else { ++ if (v1 < v2) cc = 1; ++ else cc = 2; ++ env->regs[r1] = s1; ++ env->regs[r2] = s2; ++ } ++ return cc; ++} ++ ++/* string copy (c is string terminator) */ ++uint32_t HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ uint64_t dest = env->regs[r1]; ++ uint64_t src = env->regs[r2]; ++ uint8_t v; ++ c = c & 0xff; ++#ifdef CONFIG_USER_ONLY ++ if (!c) { ++ HELPER_LOG("%s: copying '%s' to 0x%lx\n", __FUNCTION__, (char*)src, dest); ++ } ++#endif ++ for (;;) { ++ v = ldub(src); ++ stb(dest, v); ++ if (v == c) break; ++ src++; dest++; ++ } ++ env->regs[r1] = dest; ++ return 1; ++} ++ ++/* compare and swap 64-bit */ ++uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ uint64_t v2 = ldq(a2); ++ if (env->regs[r1] == v2) { ++ cc = 0; ++ stq(a2, env->regs[r3]); ++ } ++ else { ++ cc = 1; ++ env->regs[r1] = v2; ++ } ++ return cc; ++} ++ ++/* compare double and swap 64-bit */ ++uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ __uint128_t v2 = (((__uint128_t)ldq(a2)) << 64) | (__uint128_t)ldq(a2 + 8); ++ __uint128_t v1 = (((__uint128_t)env->regs[r1]) << 64) | (__uint128_t)env->regs[r1 + 1]; ++ if (v1 == v2) { ++ cc = 0; ++ stq(a2, env->regs[r3]); ++ stq(a2 + 8, env->regs[r3 + 1]); ++ } ++ else { ++ cc = 1; ++ env->regs[r1] = v2 >> 64; ++ env->regs[r1 + 1] = v2 & 0xffffffffffffffffULL; ++ } ++ return cc; ++} ++ ++/* compare and swap 32-bit */ ++uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); ++ uint32_t v2 = ldl(a2); ++ if (((uint32_t)env->regs[r1]) == v2) { ++ cc = 0; ++ stl(a2, (uint32_t)env->regs[r3]); ++ } ++ else { ++ cc = 1; ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; ++ } ++ return cc; ++} ++ ++/* execute instruction ++ this instruction executes an insn modified with the contents of r1 ++ it does not change the executed instruction in memory ++ it does not change the program counter ++ in other words: tricky... ++ currently implemented by interpreting the cases it is most commonly used in ++ */ ++uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) ++{ ++ uint16_t insn = lduw(addr); ++ HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, ++ insn); ++ if ((insn & 0xf0ff) == 0xd000) { ++ uint32_t l, insn2, b, d1, d2; ++ l = v1 & 0xff; ++ insn2 = ldl(addr + 2); ++ b = (((insn2 >> 28) & 0xf) << 4) | ((insn2 >> 12) & 0xf); ++ d1 = (insn2 >> 16) & 0xfff; ++ d2 = insn2 & 0xfff; ++ switch (insn & 0xf00) { ++ case 0x200: helper_mvc(l, b, d1, d2); return cc; break; ++ case 0x500: return helper_clc(l, b, d1, d2); break; ++ case 0x700: return helper_xc(l, b, d1, d2); break; ++ default: helper_exception(23); break; ++ } ++ } ++ else if ((insn & 0xff00) == 0x0a00) { /* supervisor call */ ++ HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); ++ env->psw.addr = ret; ++ helper_exception(EXCP_EXECUTE_SVC + ((insn | v1) & 0xff)); ++ } ++ else { ++ helper_exception(23); ++ } ++ return cc; ++} ++ ++/* set condition code for test under mask */ ++uint32_t HELPER(tm)(uint32_t val, uint32_t mask) ++{ ++ HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); ++ uint16_t r = val & mask; ++ if (r == 0) return 0; ++ else if (r == mask) return 3; ++ else return 1; ++} ++ ++/* set condition code for test under mask */ ++uint32_t HELPER(tmxx)(uint64_t val, uint32_t mask) ++{ ++ uint16_t r = val & mask; ++ HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); ++ if (r == 0) return 0; ++ else if (r == mask) return 3; ++ else { ++ while (!(mask & 0x8000)) { ++ mask <<= 1; ++ val <<= 1; ++ } ++ if (val & 0x8000) return 2; ++ else return 1; ++ } ++} ++ ++/* absolute value 32-bit */ ++uint32_t HELPER(abs_i32)(uint32_t reg, int32_t val) ++{ ++ uint32_t cc; ++ if (val == 0x80000000UL) cc = 3; ++ else if (val) cc = 1; ++ else cc = 0; ++ ++ if (val < 0) { ++ env->regs[reg] = -val; ++ } ++ else { ++ env->regs[reg] = val; ++ } ++ return cc; ++} ++ ++/* negative absolute value 32-bit */ ++uint32_t HELPER(nabs_i32)(uint32_t reg, int32_t val) ++{ ++ uint32_t cc; ++ if (val) cc = 1; ++ else cc = 0; ++ ++ if (val < 0) { ++ env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | val; ++ } ++ else { ++ env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | ((uint32_t)-val); ++ } ++ return cc; ++} ++ ++/* absolute value 64-bit */ ++uint32_t HELPER(abs_i64)(uint32_t reg, int64_t val) ++{ ++ uint32_t cc; ++ if (val == 0x8000000000000000ULL) cc = 3; ++ else if (val) cc = 1; ++ else cc = 0; ++ ++ if (val < 0) { ++ env->regs[reg] = -val; ++ } ++ else { ++ env->regs[reg] = val; ++ } ++ return cc; ++} ++ ++/* negative absolute value 64-bit */ ++uint32_t HELPER(nabs_i64)(uint32_t reg, int64_t val) ++{ ++ uint32_t cc; ++ if (val) cc = 1; ++ else cc = 0; ++ ++ if (val < 0) { ++ env->regs[reg] = val; ++ } ++ else { ++ env->regs[reg] = -val; ++ } ++ return cc; ++} ++ ++/* add with carry 32-bit unsigned */ ++uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t r1, uint32_t v2) ++{ ++ uint32_t res; ++ uint32_t v1 = env->regs[r1] & 0xffffffffUL; ++ res = v1 + v2; ++ if (cc & 2) res++; ++ ++ if (res == 0) { ++ if (v1) cc = 2; ++ else cc = 0; ++ } ++ else { ++ if (res < v1 || res < v2) ++ cc = 3; ++ else ++ cc = 1; ++ } ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; ++ return cc; ++} ++ ++/* CC for add with carry 64-bit unsigned (isn't this a duplicate of some other CC function?) */ ++uint32_t HELPER(set_cc_addc_u64)(uint64_t v1, uint64_t v2, uint64_t res) ++{ ++ uint32_t cc; ++ if (res == 0) { ++ if (v1) cc = 2; ++ else cc = 0; ++ } ++ else { ++ if (res < v1 || res < v2) { ++ cc = 3; ++ } ++ else { ++ cc = 1; ++ } ++ } ++ return cc; ++} ++ ++/* store character under mask high ++ operates on the upper half of r1 */ ++uint32_t HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) ++{ ++ int pos = 56; /* top of the upper half of r1 */ ++ ++ while (mask) { ++ if (mask & 8) { ++ stb(address, (env->regs[r1] >> pos) & 0xff); ++ address++; ++ } ++ mask = (mask << 1) & 0xf; ++ pos -= 8; ++ } ++ return 0; ++} ++ ++/* insert character under mask high ++ same as icm, but operates on the upper half of r1 */ ++uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) ++{ ++ int pos = 56; /* top of the upper half of r1 */ ++ uint64_t rmask = 0xff00000000000000ULL; ++ uint8_t val = 0; ++ int ccd = 0; ++ uint32_t cc; ++ ++ cc = 0; ++ ++ while (mask) { ++ if (mask & 8) { ++ env->regs[r1] &= ~rmask; ++ val = ldub(address); ++ if ((val & 0x80) && !ccd) cc = 1; ++ ccd = 1; ++ if (val && cc == 0) cc = 2; ++ env->regs[r1] |= (uint64_t)val << pos; ++ address++; ++ } ++ mask = (mask << 1) & 0xf; ++ pos -= 8; ++ rmask >>= 8; ++ } ++ return cc; ++} ++ ++/* insert psw mask and condition code into r1 */ ++void HELPER(ipm)(uint32_t cc, uint32_t r1) ++{ ++ uint64_t r = env->regs[r1]; ++ r &= 0xffffffff00ffffffULL; ++ r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); ++ env->regs[r1] = r; ++ HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, cc, env->psw.mask, r); ++} ++ ++/* store access registers r1 to r3 in memory at a2 */ ++void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ for (i = r1; i != ((r3 + 1) & 15); i = (i + 1) & 15) { ++ stl(a2, env->aregs[i]); ++ a2 += 4; ++ } ++} ++ ++/* move long extended ++ another memcopy insn with more bells and whistles */ ++uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ uint64_t destlen = env->regs[r1 + 1]; ++ uint64_t dest = env->regs[r1]; ++ uint64_t srclen = env->regs[r3 + 1]; ++ uint64_t src = env->regs[r3]; ++ uint8_t pad = a2 & 0xff; ++ uint8_t v; ++ uint32_t cc; ++ if (destlen == srclen) cc = 0; ++ else if (destlen < srclen) cc = 1; ++ else cc = 2; ++ if (srclen > destlen) srclen = destlen; ++ for(;destlen && srclen;src++,dest++,destlen--,srclen--) { ++ v = ldub(src); ++ stb(dest, v); ++ } ++ for(;destlen;dest++,destlen--) { ++ stb(dest, pad); ++ } ++ env->regs[r1 + 1] = destlen; ++ env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, ++ we trunc'ed it */ ++ env->regs[r1] = dest; ++ env->regs[r3] = src; ++ ++ return cc; ++} ++ ++/* compare logical long extended ++ memcompare insn with padding */ ++uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ uint64_t destlen = env->regs[r1 + 1]; ++ uint64_t dest = env->regs[r1]; ++ uint64_t srclen = env->regs[r3 + 1]; ++ uint64_t src = env->regs[r3]; ++ uint8_t pad = a2 & 0xff; ++ uint8_t v1 = 0,v2 = 0; ++ uint32_t cc = 0; ++ if (!(destlen || srclen)) return cc; ++ if (srclen > destlen) srclen = destlen; ++ for(;destlen || srclen;src++,dest++,destlen--,srclen--) { ++ if (srclen) v1 = ldub(src); ++ else v1 = pad; ++ if (destlen) v2 = ldub(dest); ++ else v2 = pad; ++ if (v1 != v2) break; ++ } ++ ++ env->regs[r1 + 1] = destlen; ++ env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, ++ we trunc'ed it */ ++ env->regs[r1] = dest; ++ env->regs[r3] = src; ++ ++ if (v1 < v2) cc = 1; ++ else if (v1 > v2) cc = 2; ++ ++ return cc; ++} ++ ++/* subtract unsigned v2 from v1 with borrow */ ++uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v1, uint32_t v2) ++{ ++ uint32_t res = v1 + (~v2) + (cc >> 1); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; ++ if (cc & 2) { /* borrow */ ++ if (v1) return 1; ++ else return 0; ++ } ++ else { ++ if (v1) return 3; ++ else return 2; ++ } ++} ++ ++/* subtract unsigned v2 from v1 with borrow */ ++uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) ++{ ++ uint64_t res = v1 + (~v2) + (cc >> 1); ++ env->regs[r1] = res; ++ if (cc & 2) { /* borrow */ ++ if (v1) return 1; ++ else return 0; ++ } ++ else { ++ if (v1) return 3; ++ else return 2; ++ } ++} ++ ++/* union used for splitting/joining 128-bit floats to/from 64-bit FP regs */ ++typedef union { ++ struct { ++#ifdef WORDS_BIGENDIAN ++ uint64_t h; ++ uint64_t l; ++#else ++ uint64_t l; ++ uint64_t h; ++#endif ++ }; ++ float128 x; ++} FP128; ++ ++/* condition codes for binary FP ops */ ++static uint32_t set_cc_f32(float32 v1, float32 v2) ++{ ++ if (float32_is_nan(v1) || float32_is_nan(v2)) return 3; ++ else if (float32_eq(v1, v2, &env->fpu_status)) return 0; ++ else if (float32_lt(v1, v2, &env->fpu_status)) return 1; ++ else return 2; ++} ++ ++static uint32_t set_cc_f64(float64 v1, float64 v2) ++{ ++ if (float64_is_nan(v1) || float64_is_nan(v2)) return 3; ++ else if (float64_eq(v1, v2, &env->fpu_status)) return 0; ++ else if (float64_lt(v1, v2, &env->fpu_status)) return 1; ++ else return 2; ++} ++ ++/* condition codes for unary FP ops */ ++static uint32_t set_cc_nz_f32(float32 v) ++{ ++ if (float32_is_nan(v)) return 3; ++ else if (float32_is_zero(v)) return 0; ++ else if (float32_is_neg(v)) return 1; ++ else return 2; ++} ++ ++static uint32_t set_cc_nz_f64(float64 v) ++{ ++ if (float64_is_nan(v)) return 3; ++ else if (float64_is_zero(v)) return 0; ++ else if (float64_is_neg(v)) return 1; ++ else return 2; ++} ++ ++static uint32_t set_cc_nz_f128(float128 v) ++{ ++ if (float128_is_nan(v)) return 3; ++ else if (float128_is_zero(v)) return 0; ++ else if (float128_is_neg(v)) return 1; ++ else return 2; ++} ++ ++/* convert 32-bit int to 64-bit float */ ++void HELPER(cdfbr)(uint32_t f1, int32_t v2) ++{ ++ HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); ++ env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); ++} ++ ++/* convert 32-bit int to 128-bit float */ ++void HELPER(cxfbr)(uint32_t f1, int32_t v2) ++{ ++ FP128 v1; ++ v1.x = int32_to_float128(v2, &env->fpu_status); ++ env->fregs[f1].i = v1.h; ++ env->fregs[f1 + 2].i = v1.l; ++} ++ ++/* convert 64-bit int to 32-bit float */ ++void HELPER(cegbr)(uint32_t f1, int64_t v2) ++{ ++ HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); ++ env->fregs[f1].e = int64_to_float32(v2, &env->fpu_status); ++} ++ ++/* convert 64-bit int to 64-bit float */ ++void HELPER(cdgbr)(uint32_t f1, int64_t v2) ++{ ++ HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); ++ env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); ++} ++ ++/* convert 64-bit int to 128-bit float */ ++void HELPER(cxgbr)(uint32_t f1, int64_t v2) ++{ ++ FP128 x1; ++ x1.x = int64_to_float128(v2, &env->fpu_status); ++ HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, x1.h, x1.l); ++ env->fregs[f1].i = x1.h; ++ env->fregs[f1 + 2].i = x1.l; ++} ++ ++/* convert 32-bit int to 32-bit float */ ++void HELPER(cefbr)(uint32_t f1, int32_t v2) ++{ ++ env->fregs[f1].e = int32_to_float32(v2, &env->fpu_status); ++ HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, env->fregs[f1].e, f1); ++} ++ ++/* 32-bit FP addition RR */ ++uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_add(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); ++ return set_cc_nz_f32(env->fregs[f1].e); ++} ++ ++/* 64-bit FP addition RR */ ++uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* 32-bit FP subtraction RR */ ++uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_sub(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); ++ return set_cc_nz_f32(env->fregs[f1].e); ++} ++ ++/* 64-bit FP subtraction RR */ ++uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); ++ HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* 32-bit FP division RR */ ++void HELPER(debr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_div(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); ++} ++ ++/* 128-bit FP division RR */ ++void HELPER(dxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ FP128 res; ++ res.x = float128_div(v1.x, v2.x, &env->fpu_status); ++ env->fregs[f1].i = res.h; ++ env->fregs[f1 + 2].i = res.l; ++} ++ ++/* 64-bit FP multiplication RR */ ++void HELPER(mdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); ++} ++ ++/* 128-bit FP multiplication RR */ ++void HELPER(mxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ FP128 res; ++ res.x = float128_mul(v1.x, v2.x, &env->fpu_status); ++ //HELPER_LOG("%s: 0x%ld * 0x%ld = 0x%ld\n", __FUNCTION__, v1.x, v2.x, res.x); ++ env->fregs[f1].i = res.h; ++ env->fregs[f1 + 2].i = res.l; ++} ++ ++/* convert 32-bit float to 64-bit float */ ++void HELPER(ldebr)(uint32_t r1, uint32_t r2) ++{ ++ env->fregs[r1].d = float32_to_float64(env->fregs[r2].e, &env->fpu_status); ++} ++ ++/* convert 128-bit float to 64-bit float */ ++void HELPER(ldxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 x2; ++ x2.h = env->fregs[f2].i; ++ x2.l = env->fregs[f2 + 2].i; ++ //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); ++ env->fregs[f1].d = float128_to_float64(x2.x, &env->fpu_status); ++ HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++void HELPER(lxdbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 res; ++ res.x = float64_to_float128(env->fregs[f2].d, &env->fpu_status); ++ env->fregs[f1].i = res.h; ++ env->fregs[f1 + 2].i = res.l; ++} ++ ++/* convert 64-bit float to 32-bit float */ ++void HELPER(ledbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 d2 = env->fregs[f2].d; ++ env->fregs[f1].e = float64_to_float32(d2, &env->fpu_status); ++} ++ ++/* convert 128-bit float to 32-bit float */ ++void HELPER(lexbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 x2; ++ x2.h = env->fregs[f2].i; ++ x2.l = env->fregs[f2 + 2].i; ++ //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); ++ env->fregs[f1].e = float128_to_float32(x2.x, &env->fpu_status); ++ HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].e); ++} ++ ++/* absolute value of 32-bit float */ ++uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1; ++ float32 v2 = env->fregs[f2].d; ++ if (float32_is_neg(v2)) { ++ v1 = float32_abs(v2); ++ } ++ else { ++ v1 = v2; ++ } ++ env->fregs[f1].d = v1; ++ return set_cc_nz_f32(v1); ++} ++ ++/* absolute value of 64-bit float */ ++uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 v1; ++ float64 v2 = env->fregs[f2].d; ++ if (float64_is_neg(v2)) { ++ v1 = float64_abs(v2); ++ } ++ else { ++ v1 = v2; ++ } ++ env->fregs[f1].d = v1; ++ return set_cc_nz_f64(v1); ++} ++ ++/* absolute value of 128-bit float */ ++uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ if (float128_is_neg(v2.x)) { ++ v1.x = float128_abs(v2.x); ++ } ++ else { ++ v1 = v2; ++ } ++ env->fregs[f1].i = v1.h; ++ env->fregs[f1 + 2].i = v1.l; ++ return set_cc_nz_f128(v1.x); ++} ++ ++/* load and test 64-bit float */ ++uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = env->fregs[f2].d; ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* load and test 32-bit float */ ++uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = env->fregs[f2].e; ++ return set_cc_nz_f32(env->fregs[f1].e); ++} ++ ++/* load and test 128-bit float */ ++uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 x; ++ x.h = env->fregs[f2].i; ++ x.l = env->fregs[f2 + 2].i; ++ env->fregs[f1].i = x.h; ++ env->fregs[f1 + 2].i = x.l; ++ return set_cc_nz_f128(x.x); ++} ++ ++/* negative absolute of 32-bit float */ ++uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_sub(float32_zero, env->fregs[f2].e, &env->fpu_status); ++ return set_cc_nz_f32(env->fregs[f1].e); ++} ++ ++/* negative absolute of 64-bit float */ ++uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_sub(float64_zero, env->fregs[f2].d, &env->fpu_status); ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 x1, x2; ++ x2.h = env->fregs[f2].i; ++ x2.l = env->fregs[f2 + 2].i; ++ x1.x = float128_sub(float64_to_float128(float64_zero, &env->fpu_status), x2.x, &env->fpu_status); ++ env->fregs[f1].i = x1.h; ++ env->fregs[f1 + 2].i = x1.l; ++ return set_cc_nz_f128(x1.x); ++} ++ ++/* 32-bit FP compare RM */ ++uint32_t HELPER(ceb)(uint32_t f1, uint64_t a2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ union { ++ float32 e; ++ uint32_t i; ++ } v2; ++ v2.i = ldl(a2); ++ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); ++ return set_cc_f32(v1, v2.e); ++} ++ ++/* 32-bit FP addition RM */ ++uint32_t HELPER(aeb)(uint32_t f1, uint64_t a2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ union { ++ float32 e; ++ uint32_t i; ++ } v2; ++ v2.i = ldl(a2); ++ HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); ++ env->fregs[f1].e = float32_add(v1, v2.e, &env->fpu_status); ++ return set_cc_nz_f32(env->fregs[f1].e); ++} ++ ++/* 32-bit FP division RM */ ++void HELPER(deb)(uint32_t f1, uint64_t a2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ union { ++ float32 e; ++ uint32_t i; ++ } v2; ++ v2.i = ldl(a2); ++ HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, v1, f1, v2.e); ++ env->fregs[f1].e = float32_div(v1, v2.e, &env->fpu_status); ++} ++ ++/* 32-bit FP multiplication RM */ ++void HELPER(meeb)(uint32_t f1, uint64_t a2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ union { ++ float32 e; ++ uint32_t i; ++ } v2; ++ v2.i = ldl(a2); ++ HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); ++ env->fregs[f1].e = float32_mul(v1, v2.e, &env->fpu_status); ++} ++ ++/* 32-bit FP compare RR */ ++uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ float32 v2 = env->fregs[f2].e;; ++ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2); ++ return set_cc_f32(v1, v2); ++} ++ ++/* 64-bit FP compare RR */ ++uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ float64 v2 = env->fregs[f2].d;; ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2); ++ return set_cc_f64(v1, v2); ++} ++ ++/* 128-bit FP compare RR */ ++uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ //HELPER_LOG("%s: comparing %llf from f%d and %llf\n", __FUNCTION__, v1.x, f1, v2.x); ++ if (float128_is_nan(v1.x) || float128_is_nan(v2.x)) return 3; ++ else if (float128_eq(v1.x, v2.x, &env->fpu_status)) return 0; ++ else if (float128_lt(v1.x, v2.x, &env->fpu_status)) return 1; ++ else return 2; ++} ++ ++/* 64-bit FP compare RM */ ++uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); ++ return set_cc_f64(v1, v2.d); ++} ++ ++/* 64-bit FP addition RM */ ++uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); ++ env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); ++ return set_cc_nz_f64(v1); ++} ++ ++/* 32-bit FP subtraction RM */ ++uint32_t HELPER(seb)(uint32_t f1, uint64_t a2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ union { ++ float32 e; ++ uint32_t i; ++ } v2; ++ v2.i = ldl(a2); ++ env->fregs[f1].e = v1 = float32_sub(v1, v2.e, &env->fpu_status); ++ return set_cc_nz_f32(v1); ++} ++ ++/* 64-bit FP subtraction RM */ ++uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); ++ return set_cc_nz_f64(v1); ++} ++ ++/* 64-bit FP multiplication RM */ ++void HELPER(mdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2.d); ++ env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); ++} ++ ++/* 64-bit FP division RM */ ++void HELPER(ddb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, v1, f1, v2.d); ++ env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); ++} ++ ++static void set_round_mode(int m3) ++{ ++ switch (m3) { ++ case 0: break; /* current mode */ ++ case 1: /* biased round no nearest */ ++ case 4: /* round to nearest */ ++ set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); ++ break; ++ case 5: /* round to zero */ ++ set_float_rounding_mode(float_round_to_zero, &env->fpu_status); ++ break; ++ case 6: /* round to +inf */ ++ set_float_rounding_mode(float_round_up, &env->fpu_status); ++ break; ++ case 7: /* round to -inf */ ++ set_float_rounding_mode(float_round_down, &env->fpu_status); ++ break; ++ } ++} ++ ++/* convert 32-bit float to 64-bit int */ ++uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float32 v2 = env->fregs[f2].e; ++ set_round_mode(m3); ++ env->regs[r1] = float32_to_int64(v2, &env->fpu_status); ++ return set_cc_nz_f32(v2); ++} ++ ++/* convert 64-bit float to 64-bit int */ ++uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float64 v2 = env->fregs[f2].d; ++ set_round_mode(m3); ++ env->regs[r1] = float64_to_int64(v2, &env->fpu_status); ++ return set_cc_nz_f64(v2); ++} ++ ++/* convert 128-bit float to 64-bit int */ ++uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ set_round_mode(m3); ++ env->regs[r1] = float128_to_int64(v2.x, &env->fpu_status); ++ if (float128_is_nan(v2.x)) return 3; ++ else if (float128_is_zero(v2.x)) return 0; ++ else if (float128_is_neg(v2.x)) return 1; ++ else return 2; ++} ++ ++/* convert 32-bit float to 32-bit int */ ++uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float32 v2 = env->fregs[f2].e; ++ set_round_mode(m3); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float32_to_int32(v2, &env->fpu_status); ++ return set_cc_nz_f32(v2); ++} ++ ++/* convert 64-bit float to 32-bit int */ ++uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float64 v2 = env->fregs[f2].d; ++ set_round_mode(m3); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float64_to_int32(v2, &env->fpu_status); ++ return set_cc_nz_f64(v2); ++} ++ ++/* convert 128-bit float to 32-bit int */ ++uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float128_to_int32(v2.x, &env->fpu_status); ++ return set_cc_nz_f128(v2.x); ++} ++ ++/* load 32-bit FP zero */ ++void HELPER(lzer)(uint32_t f1) ++{ ++ env->fregs[f1].e = float32_zero; ++} ++ ++/* load 64-bit FP zero */ ++void HELPER(lzdr)(uint32_t f1) ++{ ++ env->fregs[f1].d = float64_zero; ++} ++ ++/* load 128-bit FP zero */ ++void HELPER(lzxr)(uint32_t f1) ++{ ++ FP128 x; ++ x.x = float64_to_float128(float64_zero, &env->fpu_status); ++ env->fregs[f1].i = x.h; ++ env->fregs[f1 + 1].i = x.l; ++} ++ ++/* 128-bit FP subtraction RR */ ++uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ FP128 res; ++ res.x = float128_sub(v1.x, v2.x, &env->fpu_status); ++ env->fregs[f1].i = res.h; ++ env->fregs[f1 + 2].i = res.l; ++ return set_cc_nz_f128(res.x); ++} ++ ++/* 128-bit FP addition RR */ ++uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) ++{ ++ FP128 v1; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ FP128 v2; ++ v2.h = env->fregs[f2].i; ++ v2.l = env->fregs[f2 + 2].i; ++ FP128 res; ++ res.x = float128_add(v1.x, v2.x, &env->fpu_status); ++ env->fregs[f1].i = res.h; ++ env->fregs[f1 + 2].i = res.l; ++ return set_cc_nz_f128(res.x); ++} ++ ++/* 32-bit FP multiplication RR */ ++void HELPER(meebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_mul(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); ++} ++ ++/* 64-bit FP division RR */ ++void HELPER(ddbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and add RM */ ++void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) ++{ ++ HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ env->fregs[f1].d = float64_add(env->fregs[f1].d, float64_mul(v2.d, env->fregs[f3].d, &env->fpu_status), &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and add RR */ ++void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); ++ env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and subtract RR */ ++void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); ++ env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); ++} ++ ++/* 32-bit FP multiply and add RR */ ++void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ env->fregs[f1].e = float32_add(env->fregs[f1].e, float32_mul(env->fregs[f2].e, env->fregs[f3].e, &env->fpu_status), &env->fpu_status); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++void HELPER(lxdb)(uint32_t f1, uint64_t a2) ++{ ++ union { ++ float64 d; ++ uint64_t i; ++ } v2; ++ v2.i = ldq(a2); ++ FP128 v1; ++ v1.x = float64_to_float128(v2.d, &env->fpu_status); ++ env->fregs[f1].i = v1.h; ++ env->fregs[f1 + 2].i = v1.l; ++} ++ ++/* test data class 32-bit */ ++uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) ++{ ++ float32 v1 = env->fregs[f1].e; ++ int neg = float32_is_neg(v1); ++ uint32_t cc = 0; ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); ++ if (float32_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; ++ else if (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; ++ else if (float32_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; ++ else if (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; ++ else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* test data class 64-bit */ ++uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ int neg = float64_is_neg(v1); ++ uint32_t cc = 0; ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); ++ if (float64_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; ++ else if (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; ++ else if (float64_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; ++ else if (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; ++ else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* test data class 128-bit */ ++uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) ++{ ++ FP128 v1; ++ uint32_t cc = 0; ++ v1.h = env->fregs[f1].i; ++ v1.l = env->fregs[f1 + 2].i; ++ ++ int neg = float128_is_neg(v1.x); ++ if (float128_is_zero(v1.x) && (m2 & (1 << (11-neg)))) cc = 1; ++ else if (float128_is_infinity(v1.x) && (m2 & (1 << (5-neg)))) cc = 1; ++ else if (float128_is_nan(v1.x) && (m2 & (1 << (3-neg)))) cc = 1; ++ else if (float128_is_signaling_nan(v1.x) && (m2 & (1 << (1-neg)))) cc = 1; ++ else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* find leftmost one */ ++uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) ++{ ++ uint64_t res = 0; ++ uint64_t ov2 = v2; ++ while (!(v2 & 0x8000000000000000ULL) && v2) { ++ v2 <<= 1; ++ res++; ++ } ++ if (!v2) { ++ env->regs[r1] = 64; ++ env->regs[r1 + 1] = 0; ++ return 0; ++ } ++ else { ++ env->regs[r1] = res; ++ env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); ++ return 2; ++ } ++} ++ ++/* square root 64-bit RR */ ++void HELPER(sqdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); ++} +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +new file mode 100644 +index 0000000..e477389 +--- /dev/null ++++ b/target-s390x/translate.c +@@ -0,0 +1,2479 @@ ++/* ++ * S/390 translation ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define S390X_DEBUG_DISAS ++#ifdef S390X_DEBUG_DISAS ++# define LOG_DISAS(...) qemu_log(__VA_ARGS__) ++#else ++# define LOG_DISAS(...) do { } while (0) ++#endif ++ ++#include "cpu.h" ++#include "exec-all.h" ++#include "disas.h" ++#include "tcg-op.h" ++#include "qemu-log.h" ++ ++/* global register indexes */ ++static TCGv_ptr cpu_env; ++ ++#include "gen-icount.h" ++#include "helpers.h" ++#define GEN_HELPER 1 ++#include "helpers.h" ++ ++typedef struct DisasContext DisasContext; ++struct DisasContext { ++ uint64_t pc; ++ int is_jmp; ++ CPUS390XState *env; ++}; ++ ++#define DISAS_EXCP 4 ++#define DISAS_SVC 5 ++ ++void cpu_dump_state(CPUState *env, FILE *f, ++ int (*cpu_fprintf)(FILE *f, const char *fmt, ...), ++ int flags) ++{ ++ int i; ++ for (i = 0; i < 16; i++) { ++ cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]); ++ if ((i % 4) == 3) cpu_fprintf(f, "\n"); ++ else cpu_fprintf(f, " "); ++ } ++ for (i = 0; i < 16; i++) { ++ cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]); ++ if ((i % 4) == 3) cpu_fprintf(f, "\n"); ++ else cpu_fprintf(f, " "); ++ } ++ cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc); ++} ++ ++#define TCGREGS ++ ++static TCGv global_cc; ++#ifdef TCGREGS ++/* registers stored in TCG variables enhance performance */ ++static TCGv tcgregs[16]; ++static TCGv tcgregs32[16]; ++#endif ++static TCGv cc; ++static TCGv psw_addr; ++ ++void s390x_translate_init(void) ++{ ++ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); ++ global_cc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc), "global_cc"); ++#ifdef TCGREGS ++ int i; ++ char rn[4]; ++ for (i = 0; i < 16; i++) { ++ sprintf(rn, "R%d", i); ++ tcgregs[i] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, regs[i]), strdup(rn)); ++ sprintf(rn, "r%d", i); ++ tcgregs32[i] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, regs[i]) ++#ifdef WORDS_BIGENDIAN ++ + 4 ++#endif ++ , strdup(rn)); ++ } ++#endif ++ psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.addr), "psw_addr"); ++} ++ ++#ifdef TCGREGS ++static inline void sync_reg64(int reg) ++{ ++ tcg_gen_sync_i64(tcgregs[reg]); ++} ++static inline void sync_reg32(int reg) ++{ ++ tcg_gen_sync_i32(tcgregs32[reg]); ++} ++#endif ++ ++static TCGv load_reg(int reg) ++{ ++ TCGv r = tcg_temp_new_i64(); ++#ifdef TCGREGS ++ sync_reg32(reg); ++ tcg_gen_mov_i64(r, tcgregs[reg]); ++ return r; ++#else ++ tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, regs[reg])); ++ return r; ++#endif ++} ++ ++static TCGv load_freg(int reg) ++{ ++ TCGv r = tcg_temp_new_i64(); ++ tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, fregs[reg].d)); ++ return r; ++} ++ ++static TCGv load_freg32(int reg) ++{ ++ TCGv r = tcg_temp_new_i32(); ++ tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].e)); ++ return r; ++} ++ ++static void load_reg32_var(TCGv r, int reg) ++{ ++#ifdef TCGREGS ++ sync_reg64(reg); ++ tcg_gen_mov_i32(r, tcgregs32[reg]); ++#else ++#ifdef WORDS_BIGENDIAN ++ tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg]) + 4); ++#else ++ tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg])); ++#endif ++#endif ++} ++ ++static TCGv load_reg32(int reg) ++{ ++ TCGv r = tcg_temp_new_i32(); ++ load_reg32_var(r, reg); ++ return r; ++} ++ ++static void store_reg(int reg, TCGv v) ++{ ++#ifdef TCGREGS ++ sync_reg32(reg); ++ tcg_gen_mov_i64(tcgregs[reg], v); ++#else ++ tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, regs[reg])); ++#endif ++} ++ ++static void store_freg(int reg, TCGv v) ++{ ++ tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, fregs[reg].d)); ++} ++ ++static void store_reg32(int reg, TCGv v) ++{ ++#ifdef TCGREGS ++ sync_reg64(reg); ++ tcg_gen_mov_i32(tcgregs32[reg], v); ++#else ++#ifdef WORDS_BIGENDIAN ++ tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 4); ++#else ++ tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg])); ++#endif ++#endif ++} ++ ++static void store_reg8(int reg, TCGv v) ++{ ++#ifdef TCGREGS ++ TCGv tmp = tcg_temp_new_i32(); ++ sync_reg64(reg); ++ tcg_gen_andi_i32(tmp, tcgregs32[reg], 0xffffff00UL); ++ tcg_gen_or_i32(tcgregs32[reg], tmp, v); ++ tcg_temp_free(tmp); ++#else ++#ifdef WORDS_BIGENDIAN ++ tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 7); ++#else ++ tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg])); ++#endif ++#endif ++} ++ ++static void store_freg32(int reg, TCGv v) ++{ ++ tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, fregs[reg].e)); ++} ++ ++static void gen_illegal_opcode(DisasContext *s) ++{ ++ TCGv tmp = tcg_temp_new_i64(); ++ tcg_gen_movi_i64(tmp, 42); ++ gen_helper_exception(tmp); ++ s->is_jmp = DISAS_EXCP; ++} ++ ++#define DEBUGINSN LOG_DISAS("insn: 0x%lx\n", insn); ++ ++static TCGv get_address(int x2, int b2, int d2) ++{ ++ TCGv tmp = 0,tmp2 = 0; ++ if (d2) tmp = tcg_const_i64(d2); ++ if (x2) { ++ if (d2) { ++ tmp2 = load_reg(x2); ++ tcg_gen_add_i64(tmp, tmp, tmp2); ++ tcg_temp_free(tmp2); ++ } ++ else { ++ tmp = load_reg(x2); ++ } ++ } ++ if (b2) { ++ if (d2 || x2) { ++ tmp2 = load_reg(b2); ++ tcg_gen_add_i64(tmp, tmp, tmp2); ++ tcg_temp_free(tmp2); ++ } ++ else { ++ tmp = load_reg(b2); ++ } ++ } ++ ++ if (!(d2 || x2 || b2)) tmp = tcg_const_i64(0); ++ ++ return tmp; ++} ++ ++static inline void set_cc_nz_u32(TCGv val) ++{ ++ gen_helper_set_cc_nz_u32(cc, val); ++} ++ ++static inline void set_cc_nz_u64(TCGv val) ++{ ++ gen_helper_set_cc_nz_u64(cc, val); ++} ++ ++static inline void set_cc_s32(TCGv val) ++{ ++ gen_helper_set_cc_s32(cc, val); ++} ++ ++static inline void set_cc_s64(TCGv val) ++{ ++ gen_helper_set_cc_s64(cc, val); ++} ++ ++static inline void cmp_s32(TCGv v1, TCGv v2) ++{ ++ gen_helper_cmp_s32(cc, v1, v2); ++} ++ ++static inline void cmp_u32(TCGv v1, TCGv v2) ++{ ++ gen_helper_cmp_u32(cc, v1, v2); ++} ++ ++/* this is a hysterical raisin */ ++static inline void cmp_s32c(TCGv v1, int32_t v2) ++{ ++ gen_helper_cmp_s32(cc, v1, tcg_const_i32(v2)); ++} ++static inline void cmp_u32c(TCGv v1, uint32_t v2) ++{ ++ gen_helper_cmp_u32(cc, v1, tcg_const_i32(v2)); ++} ++ ++ ++static inline void cmp_s64(TCGv v1, TCGv v2) ++{ ++ gen_helper_cmp_s64(cc, v1, v2); ++} ++ ++static inline void cmp_u64(TCGv v1, TCGv v2) ++{ ++ gen_helper_cmp_u64(cc, v1, v2); ++} ++ ++/* see cmp_[su]32c() */ ++static inline void cmp_s64c(TCGv v1, int64_t v2) ++{ ++ gen_helper_cmp_s64(cc, v1, tcg_const_i64(v2)); ++} ++static inline void cmp_u64c(TCGv v1, uint64_t v2) ++{ ++ gen_helper_cmp_u64(cc, v1, tcg_const_i64(v2)); ++} ++ ++static void gen_bcr(uint32_t mask, int tr, uint64_t offset) ++{ ++ TCGv target; ++ if (mask == 0xf) { /* unconditional */ ++ target = load_reg(tr); ++ tcg_gen_mov_i64(psw_addr, target); ++ } ++ else { ++ gen_helper_bcr(cc, tcg_const_i32(mask), (target = load_reg(tr)), tcg_const_i64(offset)); ++ } ++ tcg_temp_free(target); ++} ++ ++static void gen_brc(uint32_t mask, uint64_t pc, int32_t offset) ++{ ++ if (mask == 0xf) { /* unconditional */ ++ tcg_gen_movi_i64(psw_addr, pc + offset); ++ } ++ else { ++ gen_helper_brc(cc, tcg_const_i32(mask), tcg_const_i64(pc), tcg_const_i32(offset)); ++ } ++} ++ ++static void gen_set_cc_add64(TCGv v1, TCGv v2, TCGv vr) ++{ ++ gen_helper_set_cc_add64(cc, v1, v2, vr); ++} ++ ++static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ ++ LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); ++ tmp = get_address(x2, b2, d2); ++ switch (op) { ++ case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ ++ case 0x4: /* lg r1,d2(x2,b2) */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ store_reg(r1, tmp2); ++ if (op == 0x2) set_cc_s64(tmp2); ++ break; ++ case 0x12: /* LT R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ set_cc_s32(tmp2); ++ break; ++ case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ ++ case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ if (op == 0xc) { ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ else { ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ tmp = load_reg(r1); ++ tcg_gen_mul_i64(tmp, tmp, tmp2); ++ store_reg(r1, tmp); ++ break; ++ case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ ++ case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ if (op == 0x1d) { ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ else { ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tmp = load_reg(r1 + 1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_div_i64(tmp3, tmp, tmp2); ++ store_reg(r1 + 1, tmp3); ++ tcg_gen_rem_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ break; ++ case 0x8: /* AG R1,D2(X2,B2) [RXY] */ ++ case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ ++ case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ ++ case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ ++ if (op == 0x1a) { ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_ext32u_i64(tmp2, tmp2); ++ } ++ else if (op == 0x18) { ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ else { ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tmp = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_add_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ switch (op) { ++ case 0x8: case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; ++ case 0xa: case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x9: /* SG R1,D2(X2,B2) [RXY] */ ++ case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ ++ case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ ++ case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ ++ if (op == 0x19) { ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ else if (op == 0x1b) { ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_ext32u_i64(tmp2, tmp2); ++ } ++ else { ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tmp = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_sub_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ switch (op) { ++ case 0x9: case 0x19: gen_helper_set_cc_sub64(cc, tmp, tmp2, tmp3); break; ++ case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ ++ case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ switch (op) { ++ case 0x14: tcg_gen_ext32s_i64(tmp2, tmp2); break; ++ case 0x16: tcg_gen_ext32u_i64(tmp2, tmp2); break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp2); ++ break; ++ case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ tcg_gen_ext16s_i64(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ break; ++ case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_ext32u_i64(tmp2, tmp2); ++ tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); ++ store_reg(r1, tmp2); ++ break; ++ case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_bswap32_i32(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ break; ++ case 0x20: /* CG R1,D2(X2,B2) [RXY] */ ++ case 0x21: /* CLG R1,D2(X2,B2) */ ++ case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ ++ case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ switch (op) { ++ case 0x20: ++ case 0x21: ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ break; ++ case 0x30: ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ break; ++ case 0x31: ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_ext32u_i64(tmp2, tmp2); ++ break; ++ default: ++ tcg_abort(); ++ } ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x20: case 0x30: cmp_s64(tmp, tmp2); break; ++ case 0x21: case 0x31: cmp_u64(tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x24: /* stg r1, d2(x2,b2) */ ++ tmp2 = load_reg(r1); ++ tcg_gen_qemu_st64(tmp2, tmp, 1); ++ break; ++ case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tcg_gen_bswap32_i32(tmp2, tmp2); ++ tcg_gen_qemu_st32(tmp2, tmp, 1); ++ break; ++ case 0x50: /* STY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st32(tmp2, tmp, 1); ++ break; ++ case 0x57: /* XY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp3, tmp, 1); ++ tcg_gen_xor_i32(tmp, tmp2, tmp3); ++ store_reg32(r1, tmp); ++ set_cc_nz_u32(tmp); ++ break; ++ case 0x58: /* LY R1,D2(X2,B2) [RXY] */ ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp3, tmp, 1); ++ store_reg32(r1, tmp3); ++ break; ++ case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ ++ case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp3, tmp, 1); ++ switch (op) { ++ case 0x5a: tcg_gen_add_i32(tmp, tmp2, tmp3); break; ++ case 0x5b: tcg_gen_sub_i32(tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp); ++ switch (op) { ++ case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp3, tmp); break; ++ case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp3, tmp); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ ++ store_reg(r1, tmp); ++ break; ++ case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st8(tmp2, tmp, 1); ++ break; ++ case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp3, tmp, 1); ++ store_reg8(r1, tmp3); ++ break; ++ case 0x76: /* LB R1,D2(X2,B2) [RXY] */ ++ case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8s(tmp2, tmp, 1); ++ switch (op) { ++ case 0x76: ++ tcg_gen_ext8s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x77: ++ tcg_gen_ext8s_i64(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ tcg_gen_ext16s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x80: /* NG R1,D2(X2,B2) [RXY] */ ++ case 0x81: /* OG R1,D2(X2,B2) [RXY] */ ++ case 0x82: /* XG R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp3, tmp, 1); ++ switch (op) { ++ case 0x80: tcg_gen_and_i64(tmp, tmp2, tmp3); break; ++ case 0x81: tcg_gen_or_i64(tmp, tmp2, tmp3); break; ++ case 0x82: tcg_gen_xor_i64(tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ set_cc_nz_u64(tmp); ++ break; ++ case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tmp = tcg_const_i32(r1); ++ gen_helper_mlg(tmp, tmp2); ++ break; ++ case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tmp = tcg_const_i32(r1); ++ gen_helper_dlg(tmp, tmp2); ++ break; ++ case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tmp = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(tmp3, cc, 1); ++ tcg_gen_andi_i64(tmp3, tmp3, 1); ++ tcg_gen_add_i64(tmp3, tmp2, tmp3);; ++ tcg_gen_add_i64(tmp3, tmp, tmp3); ++ store_reg(r1, tmp3); ++ gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tmp = load_reg(r1); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); ++ break; ++ case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ store_reg(r1, tmp2); ++ break; ++ case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16u(tmp2, tmp, 1); ++ store_reg(r1, tmp2); ++ break; ++ case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld16u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tmp = tcg_const_i32(r1); ++ gen_helper_addc_u32(cc, cc, tmp, tmp2); ++ break; ++ case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slb(cc, cc, tmp3, tmp, tmp2); ++ break; ++ default: ++ LOG_DISAS("illegal e3 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2) ++{ ++ TCGv tmp = 0,tmp2 = 0,tmp3 = 0,tmp4 = 0; ++ int i; ++ ++ LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); ++ switch (op) { ++ case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ ++ case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ ++ case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ ++ case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ ++ if (b2) { ++ tmp = get_address(0, b2, d2); ++ tcg_gen_andi_i64(tmp, tmp, 0x3f); ++ } ++ else tmp = tcg_const_i32(d2 & 0x3f); ++ tmp2 = load_reg(r3); ++ tmp3 = tcg_temp_new_i64(); ++ switch (op) { ++ case 0xc: tcg_gen_shr_i64(tmp3, tmp2, tmp); break; ++ case 0xd: tcg_gen_shl_i64(tmp3, tmp2, tmp); break; ++ case 0xa: tcg_gen_sar_i64(tmp3, tmp2, tmp); break; ++ case 0x1c: tcg_gen_rotl_i64(tmp3, tmp2, tmp); break; ++ default: tcg_abort(); break; ++ } ++ store_reg(r1, tmp3); ++ if (op == 0xa) set_cc_s64(tmp3); ++ break; ++ case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ ++ if (b2) { ++ tmp = get_address(0, b2, d2); ++ tcg_gen_andi_i64(tmp, tmp, 0x3f); ++ } ++ else tmp = tcg_const_i32(d2 & 0x3f); ++ tmp2 = load_reg32(r3); ++ tmp3 = tcg_temp_new_i32(); ++ switch (op) { ++ case 0x1d: tcg_gen_rotl_i32(tmp3, tmp2, tmp); break; ++ default: tcg_abort(); break; ++ } ++ store_reg32(r1, tmp3); ++ break; ++ case 0x4: /* LMG R1,R3,D2(B2) [RSY] */ ++ case 0x24: /* stmg */ ++ /* Apparently, unrolling lmg/stmg of any size gains performance - ++ even for very long ones... */ ++ if (r3 > r1) { ++ tmp = get_address(0, b2, d2); ++ for (i = r1; i <= r3; i++) { ++ if (op == 0x4) { ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ store_reg(i, tmp2); ++ /* At least one register is usually read after an lmg ++ (br %rsomething), which is why freeing them is ++ detrimental to performance */ ++ } ++ else { ++ tmp2 = load_reg(i); ++ tcg_gen_qemu_st64(tmp2, tmp, 1); ++ /* R15 is usually read after an stmg; other registers ++ generally aren't and can be free'd */ ++ if (i != 15) tcg_temp_free(tmp2); ++ } ++ tcg_gen_addi_i64(tmp, tmp, 8); ++ } ++ tmp2 = 0; ++ } ++ else { ++ tmp = tcg_const_i32(r1); ++ tmp2 = tcg_const_i32(r3); ++ tmp3 = tcg_const_i32(b2); ++ tmp4 = tcg_const_i32(d2); ++ if (op == 0x4) gen_helper_lmg(tmp, tmp2, tmp3, tmp4); ++ else gen_helper_stmg(tmp, tmp2, tmp3, tmp4); ++ } ++ break; ++ case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ ++ tmp2 = get_address(0, b2, d2); ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_stcmh(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ ++ tmp2 = get_address(0, b2, d2); ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_csg(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ ++ tmp2 = get_address(0, b2, d2); ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_cdsg(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x51: /* TMY D1(B1),I2 [SIY] */ ++ tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ tmp = tcg_const_i32((r1 << 4) | r3); ++ gen_helper_tm(cc, tmp2, tmp); ++ break; ++ case 0x52: /* MVIY D1(B1),I2 [SIY] */ ++ tmp2 = tcg_const_i32((r1 << 4) | r3); ++ tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ ++ tcg_gen_qemu_st8(tmp2, tmp, 1); ++ break; ++ case 0x55: /* CLIY D1(B1),I2 [SIY] */ ++ tmp3 = get_address(0, b2, d2); /* SIY -> this is the 1st operand */ ++ tmp = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp, tmp3, 1); ++ cmp_u32c(tmp, (r1 << 4) | r3); ++ break; ++ case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ ++ tmp2 = get_address(0, b2, d2); ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_icmh(cc, tmp, tmp2, tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal eb operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++ if (tmp4) tcg_temp_free(tmp4); ++} ++ ++static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) ++{ ++ TCGv tmp, tmp2, tmp3 = 0; ++ tmp2 = get_address(x2, b2, d2); ++ tmp = tcg_const_i32(r1); ++ switch (op) { ++ case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_lxdb(tmp, tmp2); ++ break; ++ case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_ceb(cc, tmp, tmp2); ++ break; ++ case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_aeb(cc, tmp, tmp2); ++ break; ++ case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_seb(cc, tmp, tmp2); ++ break; ++ case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_deb(tmp, tmp2); ++ break; ++ case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_tceb(cc, tmp, tmp2); ++ break; ++ case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_tcdb(cc, tmp, tmp2); ++ break; ++ case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ ++ gen_helper_tcxb(cc, tmp, tmp2); ++ break; ++ case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ ++ gen_helper_meeb(tmp, tmp2); ++ break; ++ case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_cdb(cc, tmp, tmp2); ++ break; ++ case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ ++ gen_helper_adb(cc, tmp, tmp2); ++ break; ++ case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_sdb(cc, tmp, tmp2); ++ break; ++ case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_mdb(tmp, tmp2); ++ break; ++ case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ ++ gen_helper_ddb(tmp, tmp2); ++ break; ++ case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ ++ /* for RXF insns, r1 is R3 and r1b is R1 */ ++ tmp3 = tcg_const_i32(r1b); ++ gen_helper_madb(tmp3, tmp2, tmp); ++ break; ++ default: ++ LOG_DISAS("illegal ed operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++} ++ ++static void disas_a5(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp = 0,tmp2 = 0; ++ uint64_t vtmp; ++ LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); ++ switch (op) { ++ case 0x0: /* IIHH R1,I2 [RI] */ ++ case 0x1: /* IIHL R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ vtmp = i2; ++ switch (op) { ++ case 0x0: tcg_gen_andi_i64(tmp, tmp, 0x0000ffffffffffffULL); vtmp <<= 48; break; ++ case 0x1: tcg_gen_andi_i64(tmp, tmp, 0xffff0000ffffffffULL); vtmp <<= 32; break; ++ default: tcg_abort(); ++ } ++ tcg_gen_ori_i64(tmp, tmp, vtmp); ++ store_reg(r1, tmp); ++ break; ++ case 0x4: /* NIHH R1,I2 [RI] */ ++ case 0x8: /* OIHH R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x4: ++ tmp2 = tcg_const_i64( (((uint64_t)i2) << 48) | 0x0000ffffffffffffULL); ++ tcg_gen_and_i64(tmp, tmp, tmp2); ++ break; ++ case 0x8: ++ tmp2 = tcg_const_i64(((uint64_t)i2) << 48); ++ tcg_gen_or_i64(tmp, tmp, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ tcg_gen_shri_i64(tmp2, tmp, 48); ++ tcg_gen_trunc_i64_i32(tmp2, tmp2); ++ set_cc_nz_u32(tmp2); ++ break; ++ case 0x5: /* NIHL R1,I2 [RI] */ ++ case 0x9: /* OIHL R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x5: ++ tmp2 = tcg_const_i64( (((uint64_t)i2) << 32) | 0xffff0000ffffffffULL); ++ tcg_gen_and_i64(tmp, tmp, tmp2); ++ break; ++ case 0x9: ++ tmp2 = tcg_const_i64(((uint64_t)i2) << 32); ++ tcg_gen_or_i64(tmp, tmp, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ tcg_gen_shri_i64(tmp2, tmp, 32); ++ tcg_gen_trunc_i64_i32(tmp2, tmp2); ++ tcg_gen_andi_i32(tmp2, tmp2, 0xffff); ++ set_cc_nz_u32(tmp2); ++ break; ++ case 0x6: /* NILH R1,I2 [RI] */ ++ case 0xa: /* OILH R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x6: ++ tmp2 = tcg_const_i64( (((uint64_t)i2) << 16) | 0xffffffff0000ffffULL); ++ tcg_gen_and_i64(tmp, tmp, tmp2); ++ break; ++ case 0xa: ++ tmp2 = tcg_const_i64(((uint64_t)i2) << 16); ++ tcg_gen_or_i64(tmp, tmp, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ tcg_gen_shri_i64(tmp2, tmp, 16); ++ tcg_gen_trunc_i64_i32(tmp2, tmp2); ++ tcg_gen_andi_i32(tmp2, tmp2, 0xffff); ++ set_cc_nz_u32(tmp2); ++ break; ++ case 0x7: /* NILL R1,I2 [RI] */ ++ case 0xb: /* OILL R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x7: ++ tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); ++ tcg_gen_and_i64(tmp, tmp, tmp2); ++ break; ++ case 0xb: ++ tmp2 = tcg_const_i64(i2); ++ tcg_gen_or_i64(tmp, tmp, tmp2); ++ break; ++ default: tcg_abort(); break; ++ } ++ store_reg(r1, tmp); ++ tcg_gen_trunc_i64_i32(tmp, tmp); ++ tcg_gen_andi_i32(tmp, tmp, 0xffff); ++ set_cc_nz_u32(tmp); /* signedness should not matter here */ ++ break; ++ case 0xc: /* LLIHH R1,I2 [RI] */ ++ tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); ++ store_reg(r1, tmp); ++ break; ++ case 0xd: /* LLIHL R1,I2 [RI] */ ++ tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); ++ store_reg(r1, tmp); ++ break; ++ case 0xe: /* LLILH R1,I2 [RI] */ ++ tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); ++ store_reg(r1, tmp); ++ break; ++ case 0xf: /* LLILL R1,I2 [RI] */ ++ tmp = tcg_const_i64(i2); ++ store_reg(r1, tmp); ++ break; ++ default: ++ LOG_DISAS("illegal a5 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++} ++ ++static void disas_a7(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp = 0,tmp2 = 0,tmp3 = 0; ++ LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); ++ switch (op) { ++ case 0x0: /* TMLH or TMH R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tcg_gen_shri_i64(tmp, tmp, 16); ++ tmp2 = tcg_const_i32((uint16_t)i2); ++ gen_helper_tmxx(cc, tmp, tmp2); ++ break; ++ case 0x1: /* TMLL or TML R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tmp2 = tcg_const_i32((uint16_t)i2); ++ gen_helper_tmxx(cc, tmp, tmp2); ++ break; ++ case 0x2: /* TMHH R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tcg_gen_shri_i64(tmp, tmp, 48); ++ tmp2 = tcg_const_i32((uint16_t)i2); ++ gen_helper_tmxx(cc, tmp, tmp2); ++ break; ++ case 0x3: /* TMHL R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tcg_gen_shri_i64(tmp, tmp, 32); ++ tmp2 = tcg_const_i32((uint16_t)i2); ++ gen_helper_tmxx(cc, tmp, tmp2); ++ break; ++ case 0x4: /* brc m1, i2 */ ++ /* FIXME: optimize m1 == 0xf (unconditional) case */ ++ gen_brc(r1, s->pc, i2 * 2); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x5: /* BRAS R1,I2 [RI] */ ++ tmp = tcg_const_i64(s->pc + 4); ++ store_reg(r1, tmp); ++ tmp = tcg_const_i64(s->pc + i2 * 2); ++ tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x6: /* BRCT R1,I2 [RI] */ ++ tmp = load_reg32(r1); ++ tcg_gen_subi_i32(tmp, tmp, 1); ++ store_reg32(r1, tmp); ++ tmp2 = tcg_const_i64(s->pc); ++ tmp3 = tcg_const_i32(i2 * 2); ++ gen_helper_brct(tmp, tmp2, tmp3); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x7: /* BRCTG R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tcg_gen_subi_i64(tmp, tmp, 1); ++ store_reg(r1, tmp); ++ tmp2 = tcg_const_i64(s->pc); ++ tmp3 = tcg_const_i32(i2 * 2); ++ gen_helper_brctg(tmp, tmp2, tmp3); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x8: /* lhi r1, i2 */ ++ tmp = tcg_const_i32(i2); ++ store_reg32(r1, tmp); ++ break; ++ case 0x9: /* lghi r1, i2 */ ++ tmp = tcg_const_i64(i2); ++ store_reg(r1, tmp); ++ break; ++ case 0xa: /* AHI R1,I2 [RI] */ ++ tmp = load_reg32(r1); ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_addi_i32(tmp3, tmp, i2); ++ store_reg32(r1, tmp3); ++ tmp2 = tcg_const_i32(i2); ++ gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); ++ break; ++ case 0xb: /* aghi r1, i2 */ ++ tmp = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_addi_i64(tmp3, tmp, i2); ++ store_reg(r1, tmp3); ++ tmp2 = tcg_const_i64(i2); ++ gen_set_cc_add64(tmp, tmp2, tmp3); ++ break; ++ case 0xc: /* MHI R1,I2 [RI] */ ++ tmp = load_reg32(r1); ++ tcg_gen_muli_i32(tmp, tmp, i2); ++ store_reg32(r1, tmp); ++ break; ++ case 0xd: /* MGHI R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ tcg_gen_muli_i64(tmp, tmp, i2); ++ store_reg(r1, tmp); ++ break; ++ case 0xe: /* CHI R1,I2 [RI] */ ++ tmp = load_reg32(r1); ++ cmp_s32c(tmp, i2); ++ break; ++ case 0xf: /* CGHI R1,I2 [RI] */ ++ tmp = load_reg(r1); ++ cmp_s64c(tmp, i2); ++ break; ++ default: ++ LOG_DISAS("illegal a7 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_b2(DisasContext *s, int op, int r1, int r2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); ++ switch (op) { ++ case 0x22: /* IPM R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_ipm(cc, tmp); ++ break; ++ case 0x4e: /* SAR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, aregs[r1])); ++ break; ++ case 0x4f: /* EAR R1,R2 [RRE] */ ++ tmp = tcg_temp_new_i32(); ++ tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, aregs[r2])); ++ store_reg32(r1, tmp); ++ break; ++ case 0x52: /* MSR R1,R2 [RRE] */ ++ tmp = load_reg32(r1); ++ tmp2 = load_reg32(r2); ++ tcg_gen_mul_i32(tmp, tmp, tmp2); ++ store_reg32(r1, tmp); ++ break; ++ case 0x55: /* MVST R1,R2 [RRE] */ ++ tmp = load_reg32(0); ++ tmp2 = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r2); ++ gen_helper_mvst(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x5d: /* CLST R1,R2 [RRE] */ ++ tmp = load_reg32(0); ++ tmp2 = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r2); ++ gen_helper_clst(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x5e: /* SRST R1,R2 [RRE] */ ++ tmp = load_reg32(0); ++ tmp2 = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r2); ++ gen_helper_srst(cc, tmp, tmp2, tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal b2 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); ++#define FP_HELPER(i) \ ++ tmp = tcg_const_i32(r1); \ ++ tmp2 = tcg_const_i32(r2); \ ++ gen_helper_ ## i (tmp, tmp2); ++#define FP_HELPER_CC(i) \ ++ tmp = tcg_const_i32(r1); \ ++ tmp2 = tcg_const_i32(r2); \ ++ gen_helper_ ## i (cc, tmp, tmp2); ++ ++ switch (op) { ++ case 0x0: /* LPEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lpebr); break; ++ case 0x2: /* LTEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(ltebr); break; ++ case 0x3: /* LCEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lcebr); break; ++ case 0x4: /* LDEBR R1,R2 [RRE] */ ++ FP_HELPER(ldebr); break; ++ case 0x5: /* LXDBR R1,R2 [RRE] */ ++ FP_HELPER(lxdbr); break; ++ case 0x9: /* CEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(cebr); break; ++ case 0xa: /* AEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(aebr); break; ++ case 0xb: /* SEBR R1,R2 [RRE] */ ++ FP_HELPER_CC(sebr); break; ++ case 0xd: /* DEBR R1,R2 [RRE] */ ++ FP_HELPER(debr); break; ++ case 0x10: /* LPDBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lpdbr); break; ++ case 0x12: /* LTDBR R1,R2 [RRE] */ ++ FP_HELPER_CC(ltdbr); break; ++ case 0x13: /* LCDBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lcdbr); break; ++ case 0x15: /* SQBDR R1,R2 [RRE] */ ++ FP_HELPER(sqdbr); break; ++ case 0x17: /* MEEBR R1,R2 [RRE] */ ++ FP_HELPER(meebr); break; ++ case 0x19: /* CDBR R1,R2 [RRE] */ ++ FP_HELPER_CC(cdbr); break; ++ case 0x1a: /* ADBR R1,R2 [RRE] */ ++ FP_HELPER_CC(adbr); break; ++ case 0x1b: /* SDBR R1,R2 [RRE] */ ++ FP_HELPER_CC(sdbr); break; ++ case 0x1c: /* MDBR R1,R2 [RRE] */ ++ FP_HELPER(mdbr); break; ++ case 0x1d: /* DDBR R1,R2 [RRE] */ ++ FP_HELPER(ddbr); break; ++ case 0xe: /* MAEBR R1,R3,R2 [RRF] */ ++ case 0x1e: /* MADBR R1,R3,R2 [RRF] */ ++ case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ ++ /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ ++ tmp = tcg_const_i32(m3); ++ tmp2 = tcg_const_i32(r2); ++ tmp3 = tcg_const_i32(r1); ++ switch (op) { ++ case 0xe: gen_helper_maebr(tmp, tmp3, tmp2); break; ++ case 0x1e: gen_helper_madbr(tmp, tmp3, tmp2); break; ++ case 0x1f: gen_helper_msdbr(tmp, tmp3, tmp2); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x40: /* LPXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lpxbr); break; ++ case 0x42: /* LTXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(ltxbr); break; ++ case 0x43: /* LCXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(lcxbr); break; ++ case 0x44: /* LEDBR R1,R2 [RRE] */ ++ FP_HELPER(ledbr); break; ++ case 0x45: /* LDXBR R1,R2 [RRE] */ ++ FP_HELPER(ldxbr); break; ++ case 0x46: /* LEXBR R1,R2 [RRE] */ ++ FP_HELPER(lexbr); break; ++ case 0x49: /* CXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(cxbr); break; ++ case 0x4a: /* AXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(axbr); break; ++ case 0x4b: /* SXBR R1,R2 [RRE] */ ++ FP_HELPER_CC(sxbr); break; ++ case 0x4c: /* MXBR R1,R2 [RRE] */ ++ FP_HELPER(mxbr); break; ++ case 0x4d: /* DXBR R1,R2 [RRE] */ ++ FP_HELPER(dxbr); break; ++ case 0x65: /* LXR R1,R2 [RRE] */ ++ tmp = load_freg(r2); ++ store_freg(r1, tmp); ++ tmp = load_freg(r2 + 2); ++ store_freg(r1 + 2, tmp); ++ break; ++ case 0x74: /* LZER R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzer(tmp); ++ break; ++ case 0x75: /* LZDR R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzdr(tmp); ++ break; ++ case 0x76: /* LZXR R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzxr(tmp); ++ break; ++ case 0x84: /* SFPC R1 [RRE] */ ++ tmp = load_reg32(r1); ++ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fpc)); ++ break; ++ case 0x8c: /* EFPC R1 [RRE] */ ++ tmp = tcg_temp_new_i32(); ++ tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); ++ store_reg32(r1, tmp); ++ break; ++ case 0x94: /* CEFBR R1,R2 [RRE] */ ++ case 0x95: /* CDFBR R1,R2 [RRE] */ ++ case 0x96: /* CXFBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg32(r2); ++ switch (op) { ++ case 0x94: gen_helper_cefbr(tmp, tmp2); break; ++ case 0x95: gen_helper_cdfbr(tmp, tmp2); break; ++ case 0x96: gen_helper_cxfbr(tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x98: /* CFEBR R1,R2 [RRE] */ ++ case 0x99: /* CFDBR R1,R2 [RRE] */ ++ case 0x9a: /* CFXBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = tcg_const_i32(r2); ++ tmp3 = tcg_const_i32(m3); ++ switch (op) { ++ case 0x98: gen_helper_cfebr(cc, tmp, tmp2, tmp3); break; ++ case 0x99: gen_helper_cfdbr(cc, tmp, tmp2, tmp3); break; ++ case 0x9a: gen_helper_cfxbr(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0xa4: /* CEGBR R1,R2 [RRE] */ ++ case 0xa5: /* CDGBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg(r2); ++ switch (op) { ++ case 0xa4: gen_helper_cegbr(tmp, tmp2); break; ++ case 0xa5: gen_helper_cdgbr(tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0xa6: /* CXGBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg(r2); ++ gen_helper_cxgbr(tmp, tmp2); ++ break; ++ case 0xa8: /* CGEBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = tcg_const_i32(r2); ++ tmp3 = tcg_const_i32(m3); ++ gen_helper_cgebr(cc, tmp, tmp2, tmp3); ++ break; ++ case 0xa9: /* CGDBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = tcg_const_i32(r2); ++ tmp3 = tcg_const_i32(m3); ++ gen_helper_cgdbr(cc, tmp, tmp2, tmp3); ++ break; ++ case 0xaa: /* CGXBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = tcg_const_i32(r2); ++ tmp3 = tcg_const_i32(m3); ++ gen_helper_cgxbr(cc, tmp, tmp2, tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal b3 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_b9(DisasContext *s, int op, int r1, int r2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); ++ switch (op) { ++ case 0: /* LPGR R1,R2 [RRE] */ ++ case 0x10: /* LPGFR R1,R2 [RRE] */ ++ if (op == 0) { ++ tmp2 = load_reg(r2); ++ } ++ else { ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ tmp = tcg_const_i32(r1); ++ gen_helper_abs_i64(cc, tmp, tmp2); ++ break; ++ case 1: /* LNGR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_nabs_i64(cc, tmp, tmp2); ++ break; ++ case 2: /* LTGR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ if (r1 != r2) store_reg(r1, tmp); ++ set_cc_s64(tmp); ++ break; ++ case 3: /* LCGR R1,R2 [RRE] */ ++ case 0x13: /* LCGFR R1,R2 [RRE] */ ++ if (op == 0x13) { ++ tmp = load_reg32(r2); ++ tcg_gen_ext32s_i64(tmp, tmp); ++ } ++ else { ++ tmp = load_reg(r2); ++ } ++ tcg_gen_neg_i64(tmp, tmp); ++ store_reg(r1, tmp); ++ gen_helper_set_cc_comp_s64(cc, tmp); ++ break; ++ case 4: /* LGR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ store_reg(r1, tmp); ++ break; ++ case 0x6: /* LGBR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tcg_gen_ext8s_i64(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ break; ++ case 8: /* AGR R1,R2 [RRE] */ ++ case 0xa: /* ALGR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ tmp2 = load_reg(r2); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_add_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ switch (op) { ++ case 0x8: gen_set_cc_add64(tmp, tmp2, tmp3); break; ++ case 0xa: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 9: /* SGR R1,R2 [RRE] */ ++ case 0xb: /* SLGR R1,R2 [RRE] */ ++ case 0x1b: /* SLGFR R1,R2 [RRE] */ ++ case 0x19: /* SGFR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0x1b: case 0x19: ++ tmp2 = load_reg32(r2); ++ if (op == 0x19) tcg_gen_ext32s_i64(tmp2, tmp2); ++ else tcg_gen_ext32u_i64(tmp2, tmp2); ++ break; ++ default: ++ tmp2 = load_reg(r2); ++ break; ++ } ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_sub_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ switch (op) { ++ case 9: case 0x19: gen_helper_set_cc_sub64(cc, tmp,tmp2,tmp3); break; ++ case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0xc: /* MSGR R1,R2 [RRE] */ ++ case 0x1c: /* MSGFR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ tmp2 = load_reg(r2); ++ if (op == 0x1c) tcg_gen_ext32s_i64(tmp2, tmp2); ++ tcg_gen_mul_i64(tmp, tmp, tmp2); ++ store_reg(r1, tmp); ++ break; ++ case 0xd: /* DSGR R1,R2 [RRE] */ ++ case 0x1d: /* DSGFR R1,R2 [RRE] */ ++ tmp = load_reg(r1 + 1); ++ if (op == 0xd) { ++ tmp2 = load_reg(r2); ++ } ++ else { ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext32s_i64(tmp2, tmp2); ++ } ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_div_i64(tmp3, tmp, tmp2); ++ store_reg(r1 + 1, tmp3); ++ tcg_gen_rem_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ break; ++ case 0x14: /* LGFR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_ext32s_i64(tmp2, tmp); ++ store_reg(r1, tmp2); ++ break; ++ case 0x16: /* LLGFR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_ext32u_i64(tmp, tmp); ++ store_reg(r1, tmp); ++ break; ++ case 0x17: /* LLGTR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i32(tmp, tmp, 0x7fffffffUL); ++ tcg_gen_ext32u_i64(tmp, tmp); ++ store_reg(r1, tmp); ++ break; ++ case 0x18: /* AGFR R1,R2 [RRE] */ ++ case 0x1a: /* ALGFR R1,R2 [RRE] */ ++ tmp2 = load_reg32(r2); ++ switch (op) { ++ case 0x18: tcg_gen_ext32s_i64(tmp2, tmp2); break; ++ case 0x1a: tcg_gen_ext32u_i64(tmp2, tmp2); break; ++ default: tcg_abort(); ++ } ++ tmp = load_reg(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_add_i64(tmp3, tmp, tmp2); ++ store_reg(r1, tmp3); ++ switch (op) { ++ case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; ++ case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ break; ++ case 0x20: /* CGR R1,R2 [RRE] */ ++ case 0x30: /* CGFR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ if (op == 0x30) tcg_gen_ext32s_i64(tmp2, tmp2); ++ tmp = load_reg(r1); ++ cmp_s64(tmp, tmp2); ++ break; ++ case 0x21: /* CLGR R1,R2 [RRE] */ ++ case 0x31: /* CLGFR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ if (op == 0x31) tcg_gen_ext32u_i64(tmp2, tmp2); ++ tmp = load_reg(r1); ++ cmp_u64(tmp, tmp2); ++ break; ++ case 0x26: /* LBR R1,R2 [RRE] */ ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext8s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x27: /* LHR R1,R2 [RRE] */ ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext16s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x80: /* NGR R1,R2 [RRE] */ ++ case 0x81: /* OGR R1,R2 [RRE] */ ++ case 0x82: /* XGR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ tmp2 = load_reg(r2); ++ switch (op) { ++ case 0x80: tcg_gen_and_i64(tmp, tmp, tmp2); break; ++ case 0x81: tcg_gen_or_i64(tmp, tmp, tmp2); break; ++ case 0x82: tcg_gen_xor_i64(tmp, tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ set_cc_nz_u64(tmp); ++ break; ++ case 0x83: /* FLOGR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_flogr(cc, tmp, tmp2); ++ break; ++ case 0x84: /* LLGCR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ tcg_gen_andi_i64(tmp, tmp, 0xff); ++ store_reg(r1, tmp); ++ break; ++ case 0x85: /* LLGHR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ tcg_gen_andi_i64(tmp, tmp, 0xffff); ++ store_reg(r1, tmp); ++ break; ++ case 0x87: /* DLGR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg(r2); ++ gen_helper_dlg(tmp, tmp2); ++ break; ++ case 0x88: /* ALCGR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ tmp2 = load_reg(r2); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(tmp3, cc, 1); ++ tcg_gen_andi_i64(tmp3, tmp3, 1); ++ tcg_gen_add_i64(tmp3, tmp2, tmp3); ++ tcg_gen_add_i64(tmp3, tmp, tmp3); ++ store_reg(r1, tmp3); ++ gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x89: /* SLBGR R1,R2 [RRE] */ ++ tmp = load_reg(r1); ++ tmp2 = load_reg(r2); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); ++ break; ++ case 0x94: /* LLCR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i32(tmp, tmp, 0xff); ++ store_reg32(r1, tmp); ++ break; ++ case 0x95: /* LLHR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i32(tmp, tmp, 0xffff); ++ store_reg32(r1, tmp); ++ break; ++ case 0x98: /* ALCR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg32(r2); ++ gen_helper_addc_u32(cc, cc, tmp, tmp2); ++ break; ++ case 0x99: /* SLBR R1,R2 [RRE] */ ++ tmp = load_reg32(r1); ++ tmp2 = load_reg32(r2); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slb(cc, cc, tmp3, tmp, tmp2); ++ break; ++ default: ++ LOG_DISAS("illegal b9 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_c0(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); ++ uint64_t target = s->pc + i2 * 2; ++ /* FIXME: huh? */ target &= 0xffffffff; ++ switch (op) { ++ case 0: /* larl r1, i2 */ ++ tmp = tcg_const_i64(target); ++ store_reg(r1, tmp); ++ break; ++ case 0x1: /* LGFI R1,I2 [RIL] */ ++ tmp = tcg_const_i64((int64_t)i2); ++ store_reg(r1, tmp); ++ break; ++ case 0x4: /* BRCL M1,I2 [RIL] */ ++ tmp = tcg_const_i32(r1); /* aka m1 */ ++ tmp2 = tcg_const_i64(s->pc); ++ tmp3 = tcg_const_i64(i2 * 2); ++ gen_helper_brcl(cc, tmp, tmp2, tmp3); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x5: /* brasl r1, i2 */ ++ tmp = tcg_const_i64(s->pc + 6); ++ store_reg(r1, tmp); ++ tmp = tcg_const_i64(target); ++ tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); ++ s->is_jmp = DISAS_JUMP; ++ break; ++ case 0x7: /* XILF R1,I2 [RIL] */ ++ case 0xb: /* NILF R1,I2 [RIL] */ ++ case 0xd: /* OILF R1,I2 [RIL] */ ++ tmp = load_reg32(r1); ++ switch (op) { ++ case 0x7: tcg_gen_xori_i32(tmp, tmp, (uint32_t)i2); break; ++ case 0xb: tcg_gen_andi_i32(tmp, tmp, (uint32_t)i2); break; ++ case 0xd: tcg_gen_ori_i32(tmp, tmp, (uint32_t)i2); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp); ++ tcg_gen_trunc_i64_i32(tmp, tmp); ++ set_cc_nz_u32(tmp); ++ break; ++ case 0x9: /* IILF R1,I2 [RIL] */ ++ tmp = tcg_const_i32((uint32_t)i2); ++ store_reg32(r1, tmp); ++ break; ++ case 0xa: /* NIHF R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ switch (op) { ++ case 0xa: tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) | 0xffffffffULL); break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp); ++ tcg_gen_shr_i64(tmp, tmp, 32); ++ tcg_gen_trunc_i64_i32(tmp, tmp); ++ set_cc_nz_u32(tmp); ++ break; ++ case 0xe: /* LLIHF R1,I2 [RIL] */ ++ tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); ++ store_reg(r1, tmp); ++ break; ++ case 0xf: /* LLILF R1,I2 [RIL] */ ++ tmp = tcg_const_i64((uint32_t)i2); ++ store_reg(r1, tmp); ++ break; ++ default: ++ LOG_DISAS("illegal c0 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static void disas_c2(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp = 0, tmp2 = 0, tmp3 = 0; ++ switch (op) { ++ case 0x4: /* SLGFI R1,I2 [RIL] */ ++ case 0xa: /* ALGFI R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); ++ tmp3 = tcg_temp_new_i64(); ++ switch (op) { ++ case 0x4: ++ tcg_gen_sub_i64(tmp3, tmp, tmp2); ++ gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); ++ break; ++ case 0xa: ++ tcg_gen_add_i64(tmp3, tmp, tmp2); ++ gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp3); ++ break; ++ case 0x5: /* SLFI R1,I2 [RIL] */ ++ case 0xb: /* ALFI R1,I2 [RIL] */ ++ tmp = load_reg32(r1); ++ tmp2 = tcg_const_i32(i2); ++ tmp3 = tcg_temp_new_i32(); ++ switch (op) { ++ case 0x5: ++ tcg_gen_sub_i32(tmp3, tmp, tmp2); ++ gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); ++ break; ++ case 0xb: ++ tcg_gen_add_i32(tmp3, tmp, tmp2); ++ gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp3); ++ break; ++ case 0xc: /* CGFI R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ cmp_s64c(tmp, (int64_t)i2); ++ break; ++ case 0xe: /* CLGFI R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ cmp_u64c(tmp, (uint64_t)(uint32_t)i2); ++ break; ++ case 0xd: /* CFI R1,I2 [RIL] */ ++ case 0xf: /* CLFI R1,I2 [RIL] */ ++ tmp = load_reg32(r1); ++ switch (op) { ++ case 0xd: cmp_s32c(tmp, i2); break; ++ case 0xf: cmp_u32c(tmp, i2); break; ++ default: tcg_abort(); ++ } ++ break; ++ default: ++ LOG_DISAS("illegal c2 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static inline uint64_t ld_code2(uint64_t pc) { return (uint64_t)lduw_code(pc); } ++static inline uint64_t ld_code4(uint64_t pc) { return (uint64_t)ldl_code(pc); } ++static inline uint64_t ld_code6(uint64_t pc) ++{ ++ uint64_t opc; ++ opc = (uint64_t)lduw_code(pc) << 32; ++ opc |= (uint64_t)(unsigned int)ldl_code(pc+2); ++ return opc; ++} ++ ++static void disas_s390_insn(CPUState *env, DisasContext *s) ++{ ++ TCGv tmp = 0,tmp2 = 0,tmp3 = 0; ++ unsigned char opc; ++ uint64_t insn; ++ int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; ++ TCGv vl, vd1, vd2, vb; ++ ++ opc = ldub_code(s->pc); ++ LOG_DISAS("opc 0x%x\n", opc); ++ ++#define FETCH_DECODE_RR \ ++ insn = ld_code2(s->pc); \ ++ DEBUGINSN \ ++ r1 = (insn >> 4) & 0xf; \ ++ r2 = insn & 0xf; ++ ++#define FETCH_DECODE_RX \ ++ insn = ld_code4(s->pc); \ ++ DEBUGINSN \ ++ r1 = (insn >> 20) & 0xf; \ ++ x2 = (insn >> 16) & 0xf; \ ++ b2 = (insn >> 12) & 0xf; \ ++ d2 = insn & 0xfff; \ ++ tmp = get_address(x2, b2, d2); ++ ++#define FETCH_DECODE_RS \ ++ insn = ld_code4(s->pc); \ ++ DEBUGINSN \ ++ r1 = (insn >> 20) & 0xf; \ ++ r3 = (insn >> 16) & 0xf; /* aka m3 */ \ ++ b2 = (insn >> 12) & 0xf; \ ++ d2 = insn & 0xfff; ++ ++#define FETCH_DECODE_SI \ ++ insn = ld_code4(s->pc); \ ++ i2 = (insn >> 16) & 0xff; \ ++ b1 = (insn >> 12) & 0xf; \ ++ d1 = insn & 0xfff; \ ++ tmp = get_address(0, b1, d1); ++ ++ switch (opc) { ++ case 0x7: /* BCR M1,R2 [RR] */ ++ FETCH_DECODE_RR ++ if (r2) { ++ gen_bcr(r1, r2, s->pc); ++ s->is_jmp = DISAS_JUMP; ++ } ++ else { ++ /* FIXME: "serialization and checkpoint-synchronization function"? */ ++ } ++ s->pc += 2; ++ break; ++ case 0xa: /* SVC I [RR] */ ++ insn = ld_code2(s->pc); ++ DEBUGINSN ++ i = insn & 0xff; ++ tmp = tcg_const_i64(s->pc); ++ tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); ++ s->is_jmp = DISAS_SVC; ++ s->pc += 2; ++ break; ++ case 0xd: /* BASR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = tcg_const_i64(s->pc + 2); ++ store_reg(r1, tmp); ++ if (r2) { ++ tmp2 = load_reg(r2); ++ tcg_gen_st_i64(tmp2, cpu_env, offsetof(CPUState, psw.addr)); ++ s->is_jmp = DISAS_JUMP; ++ } ++ s->pc += 2; ++ break; ++ case 0x10: /* LPR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp2 = load_reg32(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_abs_i32(cc, tmp, tmp2); ++ s->pc += 2; ++ break; ++ case 0x11: /* LNR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp2 = load_reg32(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_nabs_i32(cc, tmp, tmp2); ++ s->pc += 2; ++ break; ++ case 0x12: /* LTR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r2); ++ if (r1 != r2) store_reg32(r1, tmp); ++ set_cc_s32(tmp); ++ s->pc += 2; ++ break; ++ case 0x13: /* LCR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r2); ++ tcg_gen_neg_i32(tmp, tmp); ++ store_reg32(r1, tmp); ++ gen_helper_set_cc_comp_s32(cc, tmp); ++ s->pc += 2; ++ break; ++ case 0x14: /* NR R1,R2 [RR] */ ++ case 0x16: /* OR R1,R2 [RR] */ ++ case 0x17: /* XR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp2 = load_reg32(r2); ++ tmp = load_reg32(r1); ++ switch (opc) { ++ case 0x14: tcg_gen_and_i32(tmp, tmp, tmp2); break; ++ case 0x16: tcg_gen_or_i32(tmp, tmp, tmp2); break; ++ case 0x17: tcg_gen_xor_i32(tmp, tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp); ++ set_cc_nz_u32(tmp); ++ s->pc += 2; ++ break; ++ case 0x18: /* LR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r2); ++ store_reg32(r1, tmp); ++ s->pc += 2; ++ break; ++ case 0x15: /* CLR R1,R2 [RR] */ ++ case 0x19: /* CR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r1); ++ tmp2 = load_reg32(r2); ++ switch (opc) { ++ case 0x15: cmp_u32(tmp, tmp2); break; ++ case 0x19: cmp_s32(tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ s->pc += 2; ++ break; ++ case 0x1a: /* AR R1,R2 [RR] */ ++ case 0x1e: /* ALR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r1); ++ tmp2 = load_reg32(r2); ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_add_i32(tmp3, tmp, tmp2); ++ store_reg32(r1, tmp3); ++ switch (opc) { ++ case 0x1a: gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); break; ++ case 0x1e: gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ s->pc += 2; ++ break; ++ case 0x1b: /* SR R1,R2 [RR] */ ++ case 0x1f: /* SLR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r1); ++ tmp2 = load_reg32(r2); ++ tmp3 = tcg_temp_new_i32(); ++ tcg_gen_sub_i32(tmp3, tmp, tmp2); ++ store_reg32(r1, tmp3); ++ switch (opc) { ++ case 0x1b: gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); break; ++ case 0x1f: gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); break; ++ default: tcg_abort(); ++ } ++ s->pc += 2; ++ break; ++ case 0x28: /* LDR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_freg(r2); ++ store_freg(r1, tmp); ++ s->pc += 2; ++ break; ++ case 0x38: /* LER R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_freg32(r2); ++ store_freg32(r1, tmp); ++ s->pc += 2; ++ break; ++ case 0x40: /* STH R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st16(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x41: /* la */ ++ FETCH_DECODE_RX ++ store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ ++ s->pc += 4; ++ break; ++ case 0x42: /* STC R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st8(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x43: /* IC R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ store_reg8(r1, tmp2); ++ s->pc += 4; ++ break; ++ case 0x44: /* EX R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_reg(r1); ++ tmp3 = tcg_const_i64(s->pc + 4); ++ gen_helper_ex(cc, cc, tmp2, tmp, tmp3); ++ s->pc += 4; ++ break; ++ case 0x47: /* BC M1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ /* FIXME: optimize m1 == 0xf (unconditional) case */ ++ tmp2 = tcg_const_i32(r1); /* aka m1 */ ++ tmp3 = tcg_const_i64(s->pc); ++ gen_helper_bc(cc, tmp2, tmp, tmp3); ++ s->is_jmp = DISAS_JUMP; ++ s->pc += 4; ++ break; ++ case 0x48: /* LH R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ s->pc += 4; ++ break; ++ case 0x49: /* CH R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ cmp_s32(tmp, tmp2); ++ s->pc += 4; ++ break; ++ case 0x4a: /* AH R1,D2(X2,B2) [RX] */ ++ case 0x4b: /* SH R1,D2(X2,B2) [RX] */ ++ case 0x4c: /* MH R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ tmp3 = tcg_temp_new_i32(); ++ switch (opc) { ++ case 0x4a: ++ tcg_gen_add_i32(tmp3, tmp, tmp2); ++ gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x4b: ++ tcg_gen_sub_i32(tmp3, tmp, tmp2); ++ gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); ++ break; ++ case 0x4c: ++ tcg_gen_mul_i32(tmp3, tmp, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp3); ++ s->pc += 4; ++ break; ++ case 0x50: /* st r1, d2(x2, b2) */ ++ FETCH_DECODE_RX ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st32(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x55: /* CL R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ cmp_u32(tmp, tmp2); ++ s->pc += 4; ++ break; ++ case 0x54: /* N R1,D2(X2,B2) [RX] */ ++ case 0x56: /* O R1,D2(X2,B2) [RX] */ ++ case 0x57: /* X R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ switch (opc) { ++ case 0x54: tcg_gen_and_i32(tmp, tmp, tmp2); break; ++ case 0x56: tcg_gen_or_i32(tmp, tmp, tmp2); break; ++ case 0x57: tcg_gen_xor_i32(tmp, tmp, tmp2); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp); ++ set_cc_nz_u32(tmp); ++ s->pc += 4; ++ break; ++ case 0x58: /* l r1, d2(x2, b2) */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ s->pc += 4; ++ break; ++ case 0x59: /* C R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tmp = load_reg32(r1); ++ cmp_s32(tmp, tmp2); ++ s->pc += 4; ++ break; ++ case 0x5a: /* A R1,D2(X2,B2) [RX] */ ++ case 0x5b: /* S R1,D2(X2,B2) [RX] */ ++ case 0x5e: /* AL R1,D2(X2,B2) [RX] */ ++ case 0x5f: /* SL R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_ld32s(tmp, tmp, 1); ++ tmp3 = tcg_temp_new_i32(); ++ switch (opc) { ++ case 0x5a: case 0x5e: tcg_gen_add_i32(tmp3, tmp2, tmp); break; ++ case 0x5b: case 0x5f: tcg_gen_sub_i32(tmp3, tmp2, tmp); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp3); ++ switch (opc) { ++ case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp, tmp3); break; ++ case 0x5e: gen_helper_set_cc_addu32(cc, tmp2, tmp, tmp3); break; ++ case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp, tmp3); break; ++ case 0x5f: gen_helper_set_cc_subu32(cc, tmp2, tmp, tmp3); break; ++ default: tcg_abort(); ++ } ++ s->pc += 4; ++ break; ++ case 0x60: /* STD R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_freg(r1); ++ tcg_gen_qemu_st64(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x68: /* LD R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ store_freg(r1, tmp2); ++ s->pc += 4; ++ break; ++ case 0x70: /* STE R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = load_freg32(r1); ++ tcg_gen_qemu_st32(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x71: /* MS R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ tmp = load_reg(r1); ++ tcg_gen_mul_i32(tmp, tmp, tmp2); ++ store_reg(r1, tmp); ++ s->pc += 4; ++ break; ++ case 0x78: /* LE R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_freg32(r1, tmp2); ++ s->pc += 4; ++ break; ++ case 0x88: /* SRL R1,D2(B2) [RS] */ ++ case 0x89: /* SLL R1,D2(B2) [RS] */ ++ case 0x8a: /* SRA R1,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp = get_address(0, b2, d2); ++ tcg_gen_andi_i64(tmp, tmp, 0x3f); ++ tmp2 = load_reg32(r1); ++ switch (opc) { ++ case 0x88: tcg_gen_shr_i32(tmp2, tmp2, tmp); break; ++ case 0x89: tcg_gen_shl_i32(tmp2, tmp2, tmp); break; ++ case 0x8a: tcg_gen_sar_i32(tmp2, tmp2, tmp); break; ++ default: tcg_abort(); ++ } ++ store_reg32(r1, tmp2); ++ if (opc == 0x8a) set_cc_s32(tmp2); ++ s->pc += 4; ++ break; ++ case 0x91: /* TM D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ tmp = tcg_const_i32(i2); ++ gen_helper_tm(cc, tmp2, tmp); ++ s->pc += 4; ++ break; ++ case 0x92: /* MVI D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_const_i32(i2); ++ tcg_gen_qemu_st8(tmp2, tmp, 1); ++ s->pc += 4; ++ break; ++ case 0x94: /* NI D1(B1),I2 [SI] */ ++ case 0x96: /* OI D1(B1),I2 [SI] */ ++ case 0x97: /* XI D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ switch (opc) { ++ case 0x94: tcg_gen_andi_i32(tmp2, tmp2, i2); break; ++ case 0x96: tcg_gen_ori_i32(tmp2, tmp2, i2); break; ++ case 0x97: tcg_gen_xori_i32(tmp2, tmp2, i2); break; ++ default: tcg_abort(); ++ } ++ tcg_gen_qemu_st8(tmp2, tmp, 1); ++ set_cc_nz_u32(tmp2); ++ s->pc += 4; ++ break; ++ case 0x95: /* CLI D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ cmp_u32c(tmp2, i2); ++ s->pc += 4; ++ break; ++ case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp = tcg_const_i32(r1); ++ tmp2 = get_address(0, b2, d2); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_stam(tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xa5: ++ insn = ld_code4(s->pc); ++ r1 = (insn >> 20) & 0xf; ++ op = (insn >> 16) & 0xf; ++ i2 = insn & 0xffff; ++ disas_a5(s, op, r1, i2); ++ s->pc += 4; ++ break; ++ case 0xa7: ++ insn = ld_code4(s->pc); ++ r1 = (insn >> 20) & 0xf; ++ op = (insn >> 16) & 0xf; ++ i2 = (short)insn; ++ disas_a7(s, op, r1, i2); ++ s->pc += 4; ++ break; ++ case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ tmp2 = get_address(0, b2, d2); ++ gen_helper_mvcle(cc, tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp = tcg_const_i32(r1); ++ tmp3 = tcg_const_i32(r3); ++ tmp2 = get_address(0, b2, d2); ++ gen_helper_clcle(cc, tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xb2: ++ insn = ld_code4(s->pc); ++ op = (insn >> 16) & 0xff; ++ switch (op) { ++ case 0x9c: /* STFPC D2(B2) [S] */ ++ d2 = insn & 0xfff; ++ b2 = (insn >> 12) & 0xf; ++ tmp = tcg_temp_new_i32(); ++ tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); ++ tmp2 = get_address(0, b2, d2); ++ tcg_gen_qemu_st32(tmp, tmp2, 1); ++ break; ++ default: ++ r1 = (insn >> 4) & 0xf; ++ r2 = insn & 0xf; ++ disas_b2(s, op, r1, r2); ++ break; ++ } ++ s->pc += 4; ++ break; ++ case 0xb3: ++ insn = ld_code4(s->pc); ++ op = (insn >> 16) & 0xff; ++ r3 = (insn >> 12) & 0xf; /* aka m3 */ ++ r1 = (insn >> 4) & 0xf; ++ r2 = insn & 0xf; ++ disas_b3(s, op, r3, r1, r2); ++ s->pc += 4; ++ break; ++ case 0xb9: ++ insn = ld_code4(s->pc); ++ r1 = (insn >> 4) & 0xf; ++ r2 = insn & 0xf; ++ op = (insn >> 16) & 0xff; ++ disas_b9(s, op, r1, r2); ++ s->pc += 4; ++ break; ++ case 0xba: /* CS R1,R3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp = tcg_const_i32(r1); ++ tmp2 = get_address(0, b2, d2); ++ tmp3 = tcg_const_i32(r3); ++ gen_helper_cs(cc, tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp3 = get_address(0, b2, d2); ++ tmp2 = tcg_const_i32(r3); /* aka m3 */ ++ tmp = load_reg32(r1); ++ gen_helper_clm(cc, tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ tmp3 = get_address(0, b2, d2); ++ tmp2 = tcg_const_i32(r3); /* aka m3 */ ++ tmp = load_reg32(r1); ++ gen_helper_stcm(tmp, tmp2, tmp3); ++ s->pc += 4; ++ break; ++ case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ ++ FETCH_DECODE_RS ++ if (r3 == 15) { /* effectively a 32-bit load */ ++ tmp = get_address(0, b2, d2); ++ tmp2 = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ tmp = tcg_const_i32(r3); ++ gen_helper_set_cc_icm(cc, tmp, tmp2); ++ } ++ else if (r3) { ++ uint32_t mask = 0x00ffffffUL; ++ uint32_t shift = 24; ++ int m3 = r3; ++ tmp3 = load_reg32(r1); ++ tmp = get_address(0, b2, d2); ++ tmp2 = tcg_temp_new_i32(); ++ while (m3) { ++ if (m3 & 8) { ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ if (shift) tcg_gen_shli_i32(tmp2, tmp2, shift); ++ tcg_gen_andi_i32(tmp3, tmp3, mask); ++ tcg_gen_or_i32(tmp3, tmp3, tmp2); ++ tcg_gen_addi_i64(tmp, tmp, 1); ++ } ++ m3 = (m3 << 1) & 0xf; ++ mask = (mask >> 8) | 0xff000000UL; ++ shift -= 8; ++ } ++ store_reg32(r1, tmp3); ++ tmp = tcg_const_i32(r3); ++ gen_helper_set_cc_icm(cc, tmp, tmp2); ++ } ++ else { ++ tmp = tcg_const_i32(0); ++ gen_helper_set_cc_icm(cc, tmp, tmp); /* i.e. env->cc = 0 */ ++ } ++ s->pc += 4; ++ break; ++ case 0xc0: ++ case 0xc2: ++ insn = ld_code6(s->pc); ++ r1 = (insn >> 36) & 0xf; ++ op = (insn >> 32) & 0xf; ++ i2 = (int)insn; ++ switch (opc) { ++ case 0xc0: disas_c0(s, op, r1, i2); break; ++ case 0xc2: disas_c2(s, op, r1, i2); break; ++ default: tcg_abort(); ++ } ++ s->pc += 6; ++ break; ++ case 0xd2: /* mvc d1(l, b1), d2(b2) */ ++ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ ++ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ ++ case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ ++ case 0xd7: /* xc d1(l, b1), d2(b2) */ ++ insn = ld_code6(s->pc); ++ vl = tcg_const_i32((insn >> 32) & 0xff); ++ b1 = (insn >> 28) & 0xf; ++ vd1 = tcg_const_i32((insn >> 16) & 0xfff); ++ b2 = (insn >> 12) & 0xf; ++ vd2 = tcg_const_i32(insn & 0xfff); ++ vb = tcg_const_i32((b1 << 4) | b2); ++ switch (opc) { ++ case 0xd2: gen_helper_mvc(vl, vb, vd1, vd2); break; ++ case 0xd4: gen_helper_nc(cc, vl, vb, vd1, vd2); break; ++ case 0xd5: gen_helper_clc(cc, vl, vb, vd1, vd2); break; ++ case 0xd6: gen_helper_oc(cc, vl, vb, vd1, vd2); break; ++ case 0xd7: gen_helper_xc(cc, vl, vb, vd1, vd2); break; ++ default: tcg_abort(); break; ++ } ++ s->pc += 6; ++ break; ++ case 0xe3: ++ insn = ld_code6(s->pc); ++ DEBUGINSN ++ d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; ++ disas_e3(s, /* op */ insn & 0xff, /* r1 */ (insn >> 36) & 0xf, /* x2 */ (insn >> 32) & 0xf, /* b2 */ (insn >> 28) & 0xf, d2 ); ++ s->pc += 6; ++ break; ++ case 0xeb: ++ insn = ld_code6(s->pc); ++ DEBUGINSN ++ op = insn & 0xff; ++ r1 = (insn >> 36) & 0xf; ++ r3 = (insn >> 32) & 0xf; ++ b2 = (insn >> 28) & 0xf; ++ d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; ++ disas_eb(s, op, r1, r3, b2, d2); ++ s->pc += 6; ++ break; ++ case 0xed: ++ insn = ld_code6(s->pc); ++ DEBUGINSN ++ op = insn & 0xff; ++ r1 = (insn >> 36) & 0xf; ++ x2 = (insn >> 32) & 0xf; ++ b2 = (insn >> 28) & 0xf; ++ d2 = (short)((insn >> 16) & 0xfff); ++ r1b = (insn >> 12) & 0xf; ++ disas_ed(s, op, r1, x2, b2, d2, r1b); ++ s->pc += 6; ++ break; ++ default: ++ LOG_DISAS("unimplemented opcode 0x%x\n", opc); ++ gen_illegal_opcode(s); ++ s->pc += 6; ++ break; ++ } ++ if (tmp) tcg_temp_free(tmp); ++ if (tmp2) tcg_temp_free(tmp2); ++ if (tmp3) tcg_temp_free(tmp3); ++} ++ ++static always_inline void gen_intermediate_code_internal (CPUState *env, ++ TranslationBlock *tb, ++ int search_pc) ++{ ++ DisasContext dc; ++ target_ulong pc_start; ++ uint64_t next_page_start; ++ uint16_t *gen_opc_end; ++ int j, lj = -1; ++ int num_insns, max_insns; ++ ++ pc_start = tb->pc; ++ ++ dc.pc = tb->pc; ++ dc.env = env; ++ dc.pc = pc_start; ++ dc.is_jmp = DISAS_NEXT; ++ ++ gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; ++ ++ next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; ++ ++ num_insns = 0; ++ max_insns = tb->cflags & CF_COUNT_MASK; ++ if (max_insns == 0) ++ max_insns = CF_COUNT_MASK; ++ ++ gen_icount_start(); ++#if 1 ++ cc = tcg_temp_local_new_i32(); ++ tcg_gen_mov_i32(cc, global_cc); ++#else ++ cc = global_cc; ++#endif ++ do { ++ if (search_pc) { ++ j = gen_opc_ptr - gen_opc_buf; ++ if (lj < j) { ++ lj++; ++ while (lj < j) ++ gen_opc_instr_start[lj++] = 0; ++ } ++ gen_opc_pc[lj] = dc.pc; ++ gen_opc_instr_start[lj] = 1; ++ gen_opc_icount[lj] = num_insns; ++ } ++ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) ++ gen_io_start(); ++#if defined S390X_DEBUG_DISAS ++ LOG_DISAS("pc " TARGET_FMT_lx "\n", ++ dc.pc); ++#endif ++ disas_s390_insn(env, &dc); ++ ++ num_insns++; ++ } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start && num_insns < max_insns); ++ tcg_gen_mov_i32(global_cc, cc); ++ tcg_temp_free(cc); ++ ++ if (!dc.is_jmp) { ++ tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); ++ } ++ ++ if (dc.is_jmp == DISAS_SVC) { ++ tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); ++ TCGv tmp = tcg_const_i32(EXCP_SVC); ++ gen_helper_exception(tmp); ++ } ++ ++ if (tb->cflags & CF_LAST_IO) ++ gen_io_end(); ++ /* Generate the return instruction */ ++ tcg_gen_exit_tb(0); ++ gen_icount_end(tb, num_insns); ++ *gen_opc_ptr = INDEX_op_end; ++ if (search_pc) { ++ j = gen_opc_ptr - gen_opc_buf; ++ lj++; ++ while (lj <= j) ++ gen_opc_instr_start[lj++] = 0; ++ } else { ++ tb->size = dc.pc - pc_start; ++ tb->icount = num_insns; ++ } ++#if defined S390X_DEBUG_DISAS ++ log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0); ++ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { ++ qemu_log("IN: %s\n", lookup_symbol(pc_start)); ++ log_target_disas(pc_start, dc.pc - pc_start, 1); ++ qemu_log("\n"); ++ } ++#endif ++} ++ ++void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) ++{ ++ gen_intermediate_code_internal(env, tb, 0); ++} ++ ++void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) ++{ ++ gen_intermediate_code_internal(env, tb, 1); ++} ++ ++void gen_pc_load(CPUState *env, TranslationBlock *tb, ++ unsigned long searched_pc, int pc_pos, void *puc) ++{ ++ env->psw.addr = gen_opc_pc[pc_pos]; ++} +-- +1.6.2.1 + diff --git a/0022-S-390-host-target-build-system-support.patch b/0022-S-390-host-target-build-system-support.patch new file mode 100644 index 00000000..e1a71f96 --- /dev/null +++ b/0022-S-390-host-target-build-system-support.patch @@ -0,0 +1,127 @@ +From 5353e78aaf5746e4d911d14df75557b1dac5166b Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 24 Jul 2009 17:03:48 +0200 +Subject: [PATCH 22/33] S/390 host/target build system support + +changes to configure and makefiles for S/390 host and target support, +fixed as suggested by Juan Quintela + +Signed-off-by: Ulrich Hecht +--- + Makefile.target | 9 +++++++++ + configure | 19 ++++++++++++++----- + 2 files changed, 23 insertions(+), 5 deletions(-) + +diff --git a/Makefile.target b/Makefile.target +index 9c9304c..1080bf0 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -84,6 +84,9 @@ CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH) + ifeq ($(ARCH),sparc64) + CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc + endif ++ifeq ($(ARCH),s390x) ++CPPFLAGS+=-I$(SRC_PATH)/tcg/s390 ++endif + ifdef CONFIG_SOFTFLOAT + libobj-y += fpu/softfloat.o + else +@@ -211,6 +214,9 @@ endif + ifeq ($(ARCH),s390) + LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + endif ++ifeq ($(ARCH),s390x) ++LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld ++endif + + ifeq ($(ARCH),sparc) + # -static is used to avoid g1/g3 usage by the dynamic linker +@@ -358,6 +364,9 @@ endif + ifeq ($(ARCH),s390) + LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + endif ++ifeq ($(ARCH),s390x) ++LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld ++endif + + ifeq ($(ARCH),sparc) + # -static is used to avoid g1/g3 usage by the dynamic linker +diff --git a/configure b/configure +index 97ca826..68fa1c1 100755 +--- a/configure ++++ b/configure +@@ -146,9 +146,12 @@ case "$cpu" in + ppc64) + cpu="ppc64" + ;; +- s390*) ++ s390) + cpu="s390" + ;; ++ s390x) ++ cpu="s390x" ++ ;; + sparc|sun4[cdmuv]) + cpu="sparc" + ;; +@@ -745,6 +748,7 @@ sh4eb-linux-user \ + sparc-linux-user \ + sparc64-linux-user \ + sparc32plus-linux-user \ ++s390x-linux-user \ + " + fi + # the following are Darwin specific +@@ -809,6 +813,7 @@ hostlongbits="32" + if test "$cpu" = "x86_64" \ + -o "$cpu" = "alpha" \ + -o "$cpu" = "ia64" \ ++ -o "$cpu" = "s390x" \ + -o "$cpu" = "sparc64" \ + -o "$cpu" = "ppc64"; then + hostlongbits="64" +@@ -1499,10 +1504,10 @@ echo "EXESUF=$EXESUF" >> $config_host_mak + echo "PTHREADLIBS=$PTHREADLIBS" >> $config_host_mak + echo "CLOCKLIBS=$CLOCKLIBS" >> $config_host_mak + case "$cpu" in +- i386|x86_64|alpha|cris|hppa|ia64|m68k|microbaze|mips|mips64|ppc|ppc64|s390|sparc|sparc64) ++ i386|x86_64|alpha|cris|hppa|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + ARCH=$cpu + ;; +- armv4b|arm4l) ++ armv4b|armv4l) + ARCH=arm + ;; + *) +@@ -1834,7 +1839,7 @@ config_h=$target_dir/config.h + target_arch2=`echo $target | cut -d '-' -f 1` + target_bigendian="no" + case "$target_arch2" in +- armeb|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|sh4eb|sparc|sparc64|sparc32plus) ++ armeb|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus) + target_bigendian=yes + ;; + esac +@@ -1994,6 +1999,10 @@ case "$target_arch2" in + echo "TARGET_ABI32=y" >> $config_mak + target_phys_bits=64 + ;; ++ s390x) ++ target_nptl="yes" ++ target_phys_bits=64 ++ ;; + *) + echo "Unsupported target CPU" + exit 1 +@@ -2062,7 +2071,7 @@ fi + echo "TARGET_XML_FILES=$list" >> $config_mak + + case "$target_arch2" in +- arm|armeb|m68k|microblaze|mips|mipsel|mipsn32|mipsn32el|mips64|mips64el|ppc|ppc64|ppc64abi32|ppcemb|sparc|sparc64|sparc32plus) ++ arm|armeb|m68k|microblaze|mips|mipsel|mipsn32|mipsn32el|mips64|mips64el|ppc|ppc64|ppc64abi32|ppcemb|s390x|sparc|sparc64|sparc32plus) + echo "CONFIG_SOFTFLOAT=y" >> $config_mak + ;; + esac +-- +1.6.2.1 + diff --git a/qemu-svn-s390.patch b/0023-S-390-host-support-for-TCG.patch similarity index 87% rename from qemu-svn-s390.patch rename to 0023-S-390-host-support-for-TCG.patch index 61ee9caf..6e3767ba 100644 --- a/qemu-svn-s390.patch +++ b/0023-S-390-host-support-for-TCG.patch @@ -1,7 +1,58 @@ -Index: s390x.ld -=================================================================== ---- s390x.ld (revision 0) -+++ s390x.ld (revision 0) +From 228583bc998d19294856092dadbeec5dc7087f12 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 24 Jul 2009 17:00:17 +0200 +Subject: [PATCH 23/33] S/390 host support for TCG + +S/390 TCG code generator as posted before + +improvements since last time: +- don't use R0 (often means "zero", not "register zero") +- optimized add_i32 immediate +- formatted for better compliance with the QEMU coding style + +Signed-off-by: Ulrich Hecht +--- + dyngen-exec.h | 2 +- + linux-user/syscall.c | 2 +- + s390x.ld | 194 +++++++++ + tcg/s390/tcg-target.c | 1145 +++++++++++++++++++++++++++++++++++++++++++++++++ + tcg/s390/tcg-target.h | 76 ++++ + 5 files changed, 1417 insertions(+), 2 deletions(-) + create mode 100644 s390x.ld + create mode 100644 tcg/s390/tcg-target.c + create mode 100644 tcg/s390/tcg-target.h + +diff --git a/dyngen-exec.h b/dyngen-exec.h +index c007763..606ee11 100644 +--- a/dyngen-exec.h ++++ b/dyngen-exec.h +@@ -119,7 +119,7 @@ extern int printf(const char *, ...); + + /* The return address may point to the start of the next instruction. + Subtracting one gets us the call instruction itself. */ +-#if defined(__s390__) ++#if defined(__s390__) && !defined(__s390x__) + # define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) + #elif defined(__arm__) + /* Thumb return addresses have the low bit set, so we need to subtract two. +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 87ceac7..548be54 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -182,7 +182,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ + #define __NR_sys_inotify_add_watch __NR_inotify_add_watch + #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch + +-#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) ++#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || defined(__s390x__) + #define __NR__llseek __NR_lseek + #endif + +diff --git a/s390x.ld b/s390x.ld +new file mode 100644 +index 0000000..7d1f2b7 +--- /dev/null ++++ b/s390x.ld @@ -0,0 +1,194 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-s390", "elf64-s390", @@ -197,88 +248,12 @@ Index: s390x.ld + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } +} -Index: dyngen-exec.h -=================================================================== ---- dyngen-exec.h (revision 6883) -+++ dyngen-exec.h (working copy) -@@ -162,7 +162,7 @@ - - /* The return address may point to the start of the next instruction. - Subtracting one gets us the call instruction itself. */ --#if defined(__s390__) -+#if defined(__s390__) && !defined(__s390x__) - # define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) - #elif defined(__arm__) - /* Thumb return addresses have the low bit set, so we need to subtract two. -Index: Makefile.target -=================================================================== ---- Makefile.target (revision 6883) -+++ Makefile.target (working copy) -@@ -145,6 +145,9 @@ - ifeq ($(ARCH),sparc64) - CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc - endif -+ifeq ($(ARCH),s390x) -+CPPFLAGS+=-I$(SRC_PATH)/tcg/s390 -+endif - ifdef CONFIG_SOFTFLOAT - LIBOBJS+=fpu/softfloat.o - else -@@ -271,6 +274,9 @@ - ifeq ($(ARCH),s390) - LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - endif -+ifeq ($(ARCH),s390x) -+LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -+endif - - ifeq ($(ARCH),sparc) - # -static is used to avoid g1/g3 usage by the dynamic linker -@@ -436,6 +442,9 @@ - ifeq ($(ARCH),s390) - LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld - endif -+ifeq ($(ARCH),s390x) -+LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -+endif - - ifeq ($(ARCH),sparc) - # -static is used to avoid g1/g3 usage by the dynamic linker -Index: s390-dis.c -=================================================================== ---- s390-dis.c (revision 6883) -+++ s390-dis.c (working copy) -@@ -195,10 +195,10 @@ - // switch (info->mach) - // { - // case bfd_mach_s390_31: -- current_arch_mask = 1 << S390_OPCODE_ESA; -+// current_arch_mask = 1 << S390_OPCODE_ESA; - // break; - // case bfd_mach_s390_64: --// current_arch_mask = 1 << S390_OPCODE_ZARCH; -+ current_arch_mask = 1 << S390_OPCODE_ZARCH; - // break; - // default: - // abort (); -Index: linux-user/syscall.c -=================================================================== ---- linux-user/syscall.c (revision 6883) -+++ linux-user/syscall.c (working copy) -@@ -184,7 +184,7 @@ - #define __NR_sys_inotify_add_watch __NR_inotify_add_watch - #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch - --#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) -+#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || defined(__s390x__) - #define __NR__llseek __NR_lseek - #endif - -Index: tcg/s390/tcg-target.c -=================================================================== ---- tcg/s390/tcg-target.c (revision 0) -+++ tcg/s390/tcg-target.c (revision 0) -@@ -0,0 +1,1082 @@ +diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c +new file mode 100644 +index 0000000..0b285cd +--- /dev/null ++++ b/tcg/s390/tcg-target.c +@@ -0,0 +1,1145 @@ +/* + * Tiny Code Generator for QEMU + * @@ -334,8 +309,7 @@ Index: tcg/s390/tcg-target.c + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, -+ TCG_REG_R15, -+ TCG_REG_R0, ++ /* TCG_REG_R0, many insns can't be used with R0, so we better avoid it for now */ + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, @@ -355,7 +329,6 @@ Index: tcg/s390/tcg-target.c +{ + switch (type) { + case R_390_PC32DBL: -+ //fprintf(stderr,"patching %p to 0x%lx (0x%lx)\n", code_ptr, value, (value - ((tcg_target_long)code_ptr + addend)) >> 1); + *(uint32_t*)code_ptr = (value - ((tcg_target_long)code_ptr + addend)) >> 1; + break; + default: @@ -370,6 +343,9 @@ Index: tcg/s390/tcg-target.c + return 4; +} + ++#define TCG_CT_CONST_S16 0x100 ++#define TCG_CT_CONST_U12 0x200 ++ +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ @@ -378,7 +354,7 @@ Index: tcg/s390/tcg-target.c + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + ct_str = *pct_str; -+ switch(ct_str[0]) { ++ switch (ct_str[0]) { + case 'L': /* qemu_ld constraint */ + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2); +#ifdef CONFIG_SOFTMMU @@ -395,6 +371,10 @@ Index: tcg/s390/tcg-target.c + case 'R': /* not R0 */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + break; ++ case 'I': ++ ct->ct &= ~TCG_CT_REG; ++ ct->ct |= TCG_CT_CONST_S16; ++ break; + default: + break; + } @@ -405,17 +385,19 @@ Index: tcg/s390/tcg-target.c +} + +/* Test if a constant matches the constraint. */ -+/* No idea what to do here, just eat everything. */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; -+ //fprintf(stderr,"tcg_target_const_match %ld ct %d\n",val,arg_ct->ct); + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; -+ else -+ return 0; ++ if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) ++ return 1; ++ if ((ct & TCG_CT_CONST_U12) && val == (val & 0xfff)) ++ return 1; ++ ++ return 0; +} + +#ifdef CONFIG_SOFTMMU @@ -494,6 +476,8 @@ Index: tcg/s390/tcg-target.c +#define B9_NGR 0x80 +#define B9_OGR 0x81 +#define B9_XGR 0x82 ++#define B9_DLGR 0x87 ++#define B9_DLR 0x97 + +/* emit (mostly) 32-bit register/register insns */ +static inline void tcg_out_rr(TCGContext* s, int op, int r1, int r2) @@ -510,6 +494,13 @@ Index: tcg/s390/tcg-target.c +#define RR_AR 0x1a +#define RR_SR 0x1b + ++static inline void tcg_out_a7(TCGContext *s, int op, int r1, int16_t i2) ++{ ++ tcg_out32(s, 0xa7000000UL | (r1 << 20) | (op << 16) | ((uint16_t)i2)); ++} ++#define A7_AHI 0xa ++#define A7_AHGI 0xb ++ +/* emit 64-bit shifts (EB prefix) */ +static inline void tcg_out_sh64(TCGContext* s, int op, int r0, int r1, int r2, int imm) +{ @@ -552,7 +543,7 @@ Index: tcg/s390/tcg-target.c + int ret, tcg_target_long arg) +{ + //fprintf(stderr,"tcg_out_movi ret 0x%x arg 0x%lx\n",ret,arg); -+ if(arg >= -0x8000 && arg < 0x8000) { /* signed immediate load */ ++ if (arg >= -0x8000 && arg < 0x8000) { /* signed immediate load */ + /* lghi %rret, arg */ + tcg_out32(s, 0xa7090000 | (ret << 20) | (arg & 0xffff)); + } @@ -560,11 +551,11 @@ Index: tcg/s390/tcg-target.c + /* llill %rret, arg */ + tcg_out32(s, 0xa50f0000 | (ret << 20) | arg); + } -+ else if (!(arg & 0xffffffff00000000UL)) { ++ else if (!(arg & 0xffffffff00000000UL) || type == TCG_TYPE_I32) { + /* llill %rret, arg */ + tcg_out32(s, 0xa50f0000 | (ret << 20) | (arg & 0xffff)); + /* iilh %rret, arg */ -+ tcg_out32(s, 0xa5020000 | (ret << 20) | (arg >> 16)); ++ tcg_out32(s, 0xa5020000 | (ret << 20) | ((arg & 0xffffffff) >> 16)); + } + else { + /* branch over constant and store its address in R13 */ @@ -587,7 +578,7 @@ Index: tcg/s390/tcg-target.c + if (type == TCG_TYPE_I32) op = E3_LLGF; /* 32-bit zero-extended */ + else op = E3_LG; /* 64-bit */ + -+ if(arg2 < -0x80000 || arg2 > 0x7ffff) { ++ if (arg2 < -0x80000 || arg2 > 0x7ffff) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, arg2); /* load the displacement */ + tcg_out_b9(s, B9_AGR, TCG_REG_R13, arg1); /* add the address */ + tcg_out_e3(s, op, arg, TCG_REG_R13, 0); /* load the data */ @@ -642,13 +633,17 @@ Index: tcg/s390/tcg-target.c + tcg_out32(s, 0xa7840000); /* je label1 (offset will be patched in later) */ + + /* call load helper */ ++#if TARGET_LONG_BITS == 32 ++ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); ++#else + tcg_out_b9(s, B9_LGR, arg0, addr_reg); ++#endif + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (tcg_target_ulong)qemu_ld_helpers[s_bits]); + tcg_out_rr(s, RR_BASR, TCG_REG_R14, TCG_REG_R13); + + /* sign extension */ -+ switch(opc) { ++ switch (opc) { + case 0 | 4: + tcg_out_sh64(s, SH64_SLLG, data_reg, arg0, SH64_REG_NONE, 56); + tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 56); @@ -689,11 +684,11 @@ Index: tcg/s390/tcg-target.c + arg0 = addr_reg; +#endif + -+ switch(opc) { ++ switch (opc) { + case 0: /* unsigned byte */ + tcg_out_e3(s, E3_LLGC, data_reg, arg0, 0); + break; -+ case 0 | 4: /* signed byte */ ++ case 0 | 4: /* signed byte */ + tcg_out_e3(s, E3_LGB, data_reg, arg0, 0); + break; + case 1: /* unsigned short */ @@ -706,7 +701,7 @@ Index: tcg/s390/tcg-target.c + tcg_out_b9(s, B9_NGR, data_reg, 13); +#endif + break; -+ case 1 | 4: /* signed short */ ++ case 1 | 4: /* signed short */ +#ifdef TARGET_WORDS_BIGENDIAN + tcg_out_e3(s, E3_LGH, data_reg, arg0, 0); +#else @@ -716,7 +711,7 @@ Index: tcg/s390/tcg-target.c + tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 48); +#endif + break; -+ case 2: /* unsigned int */ ++ case 2: /* unsigned int */ +#ifdef TARGET_WORDS_BIGENDIAN + tcg_out_e3(s, E3_LLGF, data_reg, arg0, 0); +#else @@ -734,7 +729,7 @@ Index: tcg/s390/tcg-target.c + tcg_out_b9(s, B9_LGFR, data_reg, data_reg); +#endif + break; -+ case 3: /* long (64 bit) */ ++ case 3: /* long (64 bit) */ +#ifdef TARGET_WORDS_BIGENDIAN + tcg_out_e3(s, E3_LG, data_reg, arg0, 0); +#else @@ -774,8 +769,13 @@ Index: tcg/s390/tcg-target.c + opc, data_reg, addr_reg, mem_index, s_bits); */ + +#ifdef CONFIG_SOFTMMU ++#if TARGET_LONG_BITS == 32 ++ tcg_out_b9(s, B9_LLGFR, arg1, addr_reg); ++ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); ++#else + tcg_out_b9(s, B9_LGR, arg1, addr_reg); + tcg_out_b9(s, B9_LGR, arg0, addr_reg); ++#endif + + tcg_out_sh64(s, SH64_SRLG, arg1, addr_reg, SH64_REG_NONE, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + @@ -792,8 +792,12 @@ Index: tcg/s390/tcg-target.c + + tcg_out_e3(s, E3_CG, arg0, arg1, 0); + ++#if TARGET_LONG_BITS == 32 ++ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); ++#else + tcg_out_b9(s, B9_LGR, arg0, addr_reg); -+ ++#endif ++ + /* jump to label1 */ + label1_ptr = (uint16_t*)s->code_ptr; + tcg_out32(s, 0xa7840000); /* je label1 */ @@ -827,33 +831,33 @@ Index: tcg/s390/tcg-target.c + arg0 = addr_reg; +#endif + -+ switch(opc) { -+ case 0: -+ tcg_out_store(s, ST_STC, data_reg, arg0, 0); -+ break; -+ case 1: ++ switch (opc) { ++ case 0: ++ tcg_out_store(s, ST_STC, data_reg, arg0, 0); ++ break; ++ case 1: +#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_store(s, ST_STH, data_reg, arg0, 0); ++ tcg_out_store(s, ST_STH, data_reg, arg0, 0); +#else -+ tcg_out_e3(s, E3_STRVH, data_reg, arg0, 0); ++ tcg_out_e3(s, E3_STRVH, data_reg, arg0, 0); +#endif -+ break; -+ case 2: ++ break; ++ case 2: +#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_store(s, ST_ST, data_reg, arg0, 0); ++ tcg_out_store(s, ST_ST, data_reg, arg0, 0); +#else -+ tcg_out_e3(s, E3_STRV, data_reg, arg0, 0); ++ tcg_out_e3(s, E3_STRV, data_reg, arg0, 0); +#endif -+ break; -+ case 3: ++ break; ++ case 3: +#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_STG, data_reg, arg0, 0); ++ tcg_out_e3(s, E3_STG, data_reg, arg0, 0); +#else -+ tcg_out_e3(s, E3_STRVG, data_reg, arg0, 0); ++ tcg_out_e3(s, E3_STRVG, data_reg, arg0, 0); +#endif -+ break; -+ default: -+ tcg_abort(); ++ break; ++ default: ++ tcg_abort(); + } + +#ifdef CONFIG_SOFTMMU @@ -867,7 +871,7 @@ Index: tcg/s390/tcg-target.c +{ + //fprintf(stderr,"tcg_out_st arg 0x%x arg1 0x%x arg2 0x%lx\n",arg,arg1,arg2); + if (type == TCG_TYPE_I32) { -+ if(((long)arg2) < -0x800 || ((long)arg2) > 0x7ff) { ++ if (((long)arg2) < -0x800 || ((long)arg2) > 0x7ff) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, arg2); + tcg_out_b9(s, B9_AGR, 13, arg1); + tcg_out_store(s, ST_ST, arg, TCG_REG_R13, 0); @@ -875,7 +879,7 @@ Index: tcg/s390/tcg-target.c + else tcg_out_store(s, ST_ST, arg, arg1, arg2); + } + else { -+ if(((long)arg2) < -0x80000 || ((long)arg2) > 0x7ffff) tcg_abort(); ++ if (((long)arg2) < -0x80000 || ((long)arg2) > 0x7ffff) tcg_abort(); + tcg_out_e3(s, E3_STG, arg, arg1, arg2); + } +} @@ -886,7 +890,7 @@ Index: tcg/s390/tcg-target.c + TCGLabel* l; + int op; + int op2; -+ //fprintf(stderr,"0x%x\n", INDEX_op_qemu_ld32s); ++ //fprintf(stderr,"0x%x\n", INDEX_op_divu_i32); + switch (opc) { + case INDEX_op_exit_tb: + //fprintf(stderr,"op 0x%x exit_tb 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); @@ -896,7 +900,7 @@ Index: tcg/s390/tcg-target.c + break; + case INDEX_op_goto_tb: + //fprintf(stderr,"op 0x%x goto_tb 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(s->tb_jmp_offset) { ++ if (s->tb_jmp_offset) { + tcg_abort(); + } + else { @@ -915,7 +919,7 @@ Index: tcg/s390/tcg-target.c + break; + case INDEX_op_call: + //fprintf(stderr,"op 0x%x call 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(const_args[0]) { ++ if (const_args[0]) { + tcg_target_long off = (args[0] - (tcg_target_long)s->code_ptr + 4) >> 1; /* FIXME: + 4? Where did that come from? */ + if (off > -0x80000000 && off < 0x7fffffff) { /* relative call */ + tcg_out_brasl(s, TCG_REG_R14, off << 1); @@ -966,10 +970,10 @@ Index: tcg/s390/tcg-target.c + tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]); + break; + case INDEX_op_ld32s_i64: -+ if(args[2] < -0x80000 || args[2] > 0x7ffff) { ++ if (args[2] < -0x80000 || args[2] > 0x7ffff) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, args[2]); /* load the displacement */ + tcg_out_b9(s, B9_AGR, TCG_REG_R13, args[1]); /* add the address */ -+ tcg_out_e3(s, E3_LGF, args[0], TCG_REG_R13, 0); /* load the data (sign-extended) */ ++ tcg_out_e3(s, E3_LGF, args[0], TCG_REG_R13, 0); /* load the data (sign-extended) */ + } + else { + tcg_out_e3(s, E3_LGF, args[0], args[1], args[2]); /* load the data (sign-extended) */ @@ -981,9 +985,9 @@ Index: tcg/s390/tcg-target.c + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + //fprintf(stderr,"op 0x%x st8_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) ++ if (((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) + tcg_out_store(s, ST_STC, args[0], args[1], args[2]); -+ else if(((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { ++ else if (((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { + tcg_out_e3(s, E3_STCY, args[0], args[1], args[2]); /* FIXME: requires long displacement facility */ + tcg_abort(); // untested + } @@ -992,9 +996,9 @@ Index: tcg/s390/tcg-target.c + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + //fprintf(stderr,"op 0x%x st16_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) ++ if (((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) + tcg_out_store(s, ST_STH, args[0], args[1], args[2]); -+ else if(((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { ++ else if (((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { + tcg_out_e3(s, E3_STHY, args[0], args[1], args[2]); /* FIXME: requires long displacement facility */ + tcg_abort(); // untested + } @@ -1016,10 +1020,17 @@ Index: tcg/s390/tcg-target.c + tcg_abort(); + break; + case INDEX_op_add_i32: -+ if(args[0] == args[1]) { ++ if (const_args[2]) { ++ if (args[0] == args[1]) tcg_out_a7(s, A7_AHI, args[1], args[2]); ++ else { ++ tcg_out_rr(s, RR_LR, args[0], args[1]); ++ tcg_out_a7(s, A7_AHI, args[0], args[2]); ++ } ++ } ++ else if (args[0] == args[1]) { + tcg_out_rr(s, RR_AR, args[1], args[2]); + } -+ else if(args[0] == args[2]) { ++ else if (args[0] == args[2]) { + tcg_out_rr(s, RR_AR, args[0], args[1]); + } + else { @@ -1029,10 +1040,10 @@ Index: tcg/s390/tcg-target.c + break; + case INDEX_op_sub_i32: + //fprintf(stderr,"op 0x%x sub_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(args[0] == args[1]) { ++ if (args[0] == args[1]) { + tcg_out_rr(s, RR_SR, args[1], args[2]); /* sr %ra0/1, %ra2 */ + } -+ else if(args[0] == args[2]) { ++ else if (args[0] == args[2]) { + tcg_out_rr(s, RR_LR, TCG_REG_R13, args[2]); /* lr %r13, %raa0/2 */ + tcg_out_rr(s, RR_LR, args[0], args[1]); /* lr %ra0/2, %ra1 */ + tcg_out_rr(s, RR_SR, args[0], TCG_REG_R13); /* sr %ra0/2, %r13 */ @@ -1045,10 +1056,10 @@ Index: tcg/s390/tcg-target.c + + case INDEX_op_sub_i64: + //fprintf(stderr,"op 0x%x sub_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(args[0] == args[1]) { ++ if (args[0] == args[1]) { + tcg_out_b9(s, B9_SGR, args[1], args[2]); /* sgr %ra0/1, %ra2 */ + } -+ else if(args[0] == args[2]) { ++ else if (args[0] == args[2]) { + tcg_out_b9(s, B9_LGR, TCG_REG_R13, args[2]); /* lgr %r13, %raa0/2 */ + tcg_out_b9(s, B9_LGR, args[0], args[1]); /* lgr %ra0/2, %ra1 */ + tcg_out_b9(s, B9_SGR, args[0], TCG_REG_R13); /* sgr %ra0/2, %r13 */ @@ -1060,10 +1071,10 @@ Index: tcg/s390/tcg-target.c + break; + case INDEX_op_add_i64: + //fprintf(stderr,"op 0x%x add_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(args[0] == args[1]) { ++ if (args[0] == args[1]) { + tcg_out_b9(s, B9_AGR, args[1], args[2]); + } -+ else if(args[0] == args[2]) { ++ else if (args[0] == args[2]) { + tcg_out_b9(s, B9_AGR, args[0], args[1]); + } + else { @@ -1075,10 +1086,12 @@ Index: tcg/s390/tcg-target.c + case INDEX_op_and_i32: + op = RR_NR; +do_logic_i32: -+ if(args[0] == args[1]) ++ if (args[0] == args[1]) { + tcg_out_rr(s, op, args[1], args[2]); /* xr %ra0/1, %ra2 */ -+ else if(args[0] == args[2]) ++ } ++ else if (args[0] == args[2]) { + tcg_out_rr(s, op, args[0], args[1]); /* xr %ra0/2, %ra1 */ ++ } + else { + tcg_out_rr(s, RR_LR, args[0], args[1]); /* lr %ra0, %ra1 */ + tcg_out_rr(s, op, args[0], args[2]); /* xr %ra0, %ra2 */ @@ -1091,10 +1104,12 @@ Index: tcg/s390/tcg-target.c + //fprintf(stderr,"op 0x%x and_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); + op = B9_NGR; +do_logic_i64: -+ if (args[0] == args[1]) ++ if (args[0] == args[1]) { + tcg_out_b9(s, op, args[0], args[2]); -+ else if (args[0] == args[2]) ++ } ++ else if (args[0] == args[2]) { + tcg_out_b9(s, op, args[0], args[1]); ++ } + else { + tcg_out_b9(s, B9_LGR, args[0], args[1]); + tcg_out_b9(s, op, args[0], args[2]); @@ -1124,33 +1139,50 @@ Index: tcg/s390/tcg-target.c + tcg_out32(s, 0xb2520000 | (args[0] << 4) | args[2]); /* msr %ra0/1, %ra2 */ + else if (args[0] == args[2]) + tcg_out32(s, 0xb2520000 | (args[0] << 4) | args[1]); /* msr %ra0/2, %ra1 */ -+ else tcg_abort(); ++ else { ++ tcg_out_rr(s, RR_LR, args[0], args[1]); ++ tcg_out32(s, 0xb2520000 | (args[0] << 4) | args[2]); /* msr %ra0, %ra2 */ ++ } + break; + case INDEX_op_mul_i64: + //fprintf(stderr,"op 0x%x mul_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if(args[0] == args[1]) { ++ if (args[0] == args[1]) { + tcg_out_b9(s, B9_MSGR, args[0], args[2]); + } -+ else if(args[0] == args[2]) { ++ else if (args[0] == args[2]) { + tcg_out_b9(s, B9_MSGR, args[0], args[1]); + } + else tcg_abort(); + break; + ++ case INDEX_op_divu_i32: ++ case INDEX_op_remu_i32: ++ //fprintf(stderr,"op 0x%x div/remu_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R12, 0); ++ tcg_out_rr(s, RR_LR, TCG_REG_R13, args[1]); ++ tcg_out_b9(s, B9_DLR, TCG_REG_R12, args[2]); ++ if (opc == INDEX_op_divu_i32) ++ tcg_out_rr(s, RR_LR, args[0], TCG_REG_R13); /* quotient */ ++ else ++ tcg_out_rr(s, RR_LR, args[0], TCG_REG_R12); /* remainder */ ++ break; ++ + case INDEX_op_shl_i32: + op = SH32_SLL; op2 = SH64_SLLG; +do_shift32: -+ if(const_args[2]) { -+ if(args[0] == args[1]) ++ if (const_args[2]) { ++ if (args[0] == args[1]) { + tcg_out_sh32(s, op, args[0], SH32_REG_NONE, args[2]); ++ } + else { + tcg_out_rr(s, RR_LR, args[0], args[1]); + tcg_out_sh32(s, op, args[0], SH32_REG_NONE, args[2]); + } + } + else { -+ if(args[0] == args[1]) ++ if (args[0] == args[1]) { + tcg_out_sh32(s, op, args[0], args[2], 0); ++ } + else + tcg_out_sh64(s, op2, args[0], args[1], args[2], 0); + } @@ -1161,7 +1193,7 @@ Index: tcg/s390/tcg-target.c + case INDEX_op_shl_i64: + op = SH64_SLLG; +do_shift64: -+ if(const_args[2]) { ++ if (const_args[2]) { + tcg_out_sh64(s, op, args[0], args[1], SH64_REG_NONE, args[2]); + } + else { @@ -1204,7 +1236,7 @@ Index: tcg/s390/tcg-target.c + } +do_brcond: + l = &s->labels[args[3]]; -+ if(l->has_value) { ++ if (l->has_value) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, l->u.value); + } + else { @@ -1253,10 +1285,15 @@ Index: tcg/s390/tcg-target.c + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + -+ { INDEX_op_add_i32, { "r", "r", "r" } }, ++ { INDEX_op_add_i32, { "r", "r", "rI" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + ++ { INDEX_op_div_i32, { "r", "r", "r" } }, ++ { INDEX_op_divu_i32, { "r", "r", "r" } }, ++ { INDEX_op_rem_i32, { "r", "r", "r" } }, ++ { INDEX_op_remu_i32, { "r", "r", "r" } }, ++ + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, @@ -1337,6 +1374,7 @@ Index: tcg/s390/tcg-target.c + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* frequently used as a temporary */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12); /* another temporary */ + + tcg_add_target_add_op_defs(s390_op_defs); +} @@ -1361,10 +1399,11 @@ Index: tcg/s390/tcg-target.c +{ + tcg_abort(); +} -Index: tcg/s390/tcg-target.h -=================================================================== ---- tcg/s390/tcg-target.h (revision 0) -+++ tcg/s390/tcg-target.h (revision 0) +diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h +new file mode 100644 +index 0000000..fcb28d1 +--- /dev/null ++++ b/tcg/s390/tcg-target.h @@ -0,0 +1,76 @@ +/* + * Tiny Code Generator for QEMU @@ -1393,7 +1432,7 @@ Index: tcg/s390/tcg-target.h + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN -+#undef TCG_TARGET_HAS_div_i32 ++#define TCG_TARGET_HAS_div_i32 +#undef TCG_TARGET_HAS_div_i64 +#undef TCG_TARGET_HAS_bswap_i32 +#define TCG_TARGET_HAS_neg_i32 @@ -1442,40 +1481,6 @@ Index: tcg/s390/tcg-target.h +#error not implemented +#endif +} -Index: configure -=================================================================== ---- configure (revision 6883) -+++ configure (working copy) -@@ -139,9 +139,12 @@ - ppc64) - cpu="ppc64" - ;; -- s390*) -+ s390) - cpu="s390" - ;; -+ s390x) -+ cpu="s390x" -+ ;; - sparc|sun4[cdmuv]) - cpu="sparc" - ;; -@@ -727,6 +730,7 @@ - if test "$cpu" = "x86_64" \ - -o "$cpu" = "alpha" \ - -o "$cpu" = "ia64" \ -+ -o "$cpu" = "s390x" \ - -o "$cpu" = "sparc64" \ - -o "$cpu" = "ppc64"; then - hostlongbits="64" -@@ -1311,6 +1315,10 @@ - echo "ARCH=s390" >> $config_mak - echo "#define HOST_S390 1" >> $config_h - ;; -+ s390x) -+ echo "ARCH=s390x" >> $config_mak -+ echo "#define HOST_S390X 1" >> $config_h -+ ;; - sparc) - echo "ARCH=sparc" >> $config_mak - echo "#define HOST_SPARC 1" >> $config_h +-- +1.6.2.1 + diff --git a/0024-linux-user-S-390-64-bit-s390x-support.patch b/0024-linux-user-S-390-64-bit-s390x-support.patch new file mode 100644 index 00000000..0c391536 --- /dev/null +++ b/0024-linux-user-S-390-64-bit-s390x-support.patch @@ -0,0 +1,1350 @@ +From 54dafd4a253d41b9027d9d77a849624f78074991 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 24 Jul 2009 16:57:31 +0200 +Subject: [PATCH 24/33] linux-user: S/390 64-bit (s390x) support + +code for running 64-bit S/390 Linux binaries + +Signed-off-by: Ulrich Hecht +--- + linux-user/elfload.c | 18 ++ + linux-user/main.c | 82 +++++++++ + linux-user/s390x/syscall.h | 25 +++ + linux-user/s390x/syscall_nr.h | 348 ++++++++++++++++++++++++++++++++++++++ + linux-user/s390x/target_signal.h | 26 +++ + linux-user/s390x/termbits.h | 283 +++++++++++++++++++++++++++++++ + linux-user/signal.c | 314 ++++++++++++++++++++++++++++++++++ + linux-user/syscall.c | 16 ++- + linux-user/syscall_defs.h | 56 ++++++- + qemu-binfmt-conf.sh | 5 +- + 10 files changed, 1166 insertions(+), 7 deletions(-) + create mode 100644 linux-user/s390x/syscall.h + create mode 100644 linux-user/s390x/syscall_nr.h + create mode 100644 linux-user/s390x/target_signal.h + create mode 100644 linux-user/s390x/termbits.h + +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index d31cca7..b81e8c9 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -679,6 +679,24 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i + + #endif /* TARGET_ALPHA */ + ++#ifdef TARGET_S390X ++ ++#define ELF_START_MMAP (0x20000000000ULL) ++ ++#define elf_check_arch(x) ( (x) == ELF_ARCH ) ++ ++#define ELF_CLASS ELFCLASS64 ++#define ELF_DATA ELFDATA2MSB ++#define ELF_ARCH EM_S390 ++ ++static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) ++{ ++ regs->psw.addr = infop->entry; ++ regs->gprs[15] = infop->start_stack; ++} ++ ++#endif /* TARGET_S390X */ ++ + #ifndef ELF_PLATFORM + #define ELF_PLATFORM (NULL) + #endif +diff --git a/linux-user/main.c b/linux-user/main.c +index 9038b58..d2f62e0 100644 +--- a/linux-user/main.c ++++ b/linux-user/main.c +@@ -2304,6 +2304,79 @@ void cpu_loop (CPUState *env) + } + #endif /* TARGET_ALPHA */ + ++#ifdef TARGET_S390X ++void cpu_loop(CPUS390XState *env) ++{ ++ int trapnr; ++ target_siginfo_t info; ++ ++ while (1) { ++ trapnr = cpu_s390x_exec (env); ++ ++ if ((trapnr & 0xffff0000) == EXCP_EXECUTE_SVC) { ++ int n = trapnr & 0xffff; ++ env->regs[2] = do_syscall(env, n, ++ env->regs[2], ++ env->regs[3], ++ env->regs[4], ++ env->regs[5], ++ env->regs[6], ++ env->regs[7]); ++ } ++ else switch (trapnr) { ++ case EXCP_INTERRUPT: ++ /* just indicate that signals should be handled asap */ ++ break; ++ case EXCP_DEBUG: ++ { ++ int sig; ++ ++ sig = gdb_handlesig (env, TARGET_SIGTRAP); ++ if (sig) { ++ info.si_signo = sig; ++ info.si_errno = 0; ++ info.si_code = TARGET_TRAP_BRKPT; ++ queue_signal(env, info.si_signo, &info); ++ } ++ } ++ break; ++ case EXCP_SVC: ++ { ++ int n = ldub(env->psw.addr - 1); ++ if (!n) n = env->regs[1]; /* syscalls > 255 */ ++ env->regs[2] = do_syscall(env, n, ++ env->regs[2], ++ env->regs[3], ++ env->regs[4], ++ env->regs[5], ++ env->regs[6], ++ env->regs[7]); ++ } ++ break; ++ case EXCP_ADDR: ++ { ++ info.si_signo = SIGSEGV; ++ info.si_errno = 0; ++ /* XXX: check env->error_code */ ++ info.si_code = TARGET_SEGV_MAPERR; ++ info._sifields._sigfault._addr = env->__excp_addr; ++ queue_signal(env, info.si_signo, &info); ++ } ++ break; ++ default: ++ printf ("Unhandled trap: 0x%x\n", trapnr); ++ if (trapnr == 42) { /* unimplemented insn */ ++ fprintf(stderr,"insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); ++ } ++ cpu_dump_state(env, stderr, fprintf, 0); ++ exit (1); ++ } ++ process_pending_signals (env); ++ } ++} ++ ++#endif /* TARGET_S390X */ ++ + static void usage(void) + { + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" +@@ -2900,6 +2973,15 @@ int main(int argc, char **argv, char **envp) + env->regs[15] = regs->acr; + env->pc = regs->erp; + } ++#elif defined(TARGET_S390X) ++ { ++ int i; ++ for (i = 0; i < 16; i++) { ++ env->regs[i] = regs->gprs[i]; ++ } ++ env->psw.mask = regs->psw.mask; ++ env->psw.addr = regs->psw.addr; ++ } + #else + #error unsupported target CPU + #endif +diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h +new file mode 100644 +index 0000000..a3812a8 +--- /dev/null ++++ b/linux-user/s390x/syscall.h +@@ -0,0 +1,25 @@ ++/* this typedef defines how a Program Status Word looks like */ ++typedef struct ++{ ++ abi_ulong mask; ++ abi_ulong addr; ++} __attribute__ ((aligned(8))) target_psw_t; ++ ++/* ++ * The pt_regs struct defines the way the registers are stored on ++ * the stack during a system call. ++ */ ++ ++#define TARGET_NUM_GPRS 16 ++ ++struct target_pt_regs ++{ ++ abi_ulong args[1]; ++ target_psw_t psw; ++ abi_ulong gprs[TARGET_NUM_GPRS]; ++ abi_ulong orig_gpr2; ++ unsigned short ilc; ++ unsigned short trap; ++}; ++ ++#define UNAME_MACHINE "s390x" +diff --git a/linux-user/s390x/syscall_nr.h b/linux-user/s390x/syscall_nr.h +new file mode 100644 +index 0000000..4a60b9a +--- /dev/null ++++ b/linux-user/s390x/syscall_nr.h +@@ -0,0 +1,348 @@ ++/* ++ * This file contains the system call numbers. ++ */ ++ ++#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_restart_syscall 7 ++#define TARGET_NR_creat 8 ++#define TARGET_NR_link 9 ++#define TARGET_NR_unlink 10 ++#define TARGET_NR_execve 11 ++#define TARGET_NR_chdir 12 ++#define TARGET_NR_mknod 14 ++#define TARGET_NR_chmod 15 ++#define TARGET_NR_lseek 19 ++#define TARGET_NR_getpid 20 ++#define TARGET_NR_mount 21 ++#define TARGET_NR_umount 22 ++#define TARGET_NR_ptrace 26 ++#define TARGET_NR_alarm 27 ++#define TARGET_NR_pause 29 ++#define TARGET_NR_utime 30 ++#define TARGET_NR_access 33 ++#define TARGET_NR_nice 34 ++#define TARGET_NR_sync 36 ++#define TARGET_NR_kill 37 ++#define TARGET_NR_rename 38 ++#define TARGET_NR_mkdir 39 ++#define TARGET_NR_rmdir 40 ++#define TARGET_NR_dup 41 ++#define TARGET_NR_pipe 42 ++#define TARGET_NR_times 43 ++#define TARGET_NR_brk 45 ++#define TARGET_NR_signal 48 ++#define TARGET_NR_acct 51 ++#define TARGET_NR_umount2 52 ++#define TARGET_NR_ioctl 54 ++#define TARGET_NR_fcntl 55 ++#define TARGET_NR_setpgid 57 ++#define TARGET_NR_umask 60 ++#define TARGET_NR_chroot 61 ++#define TARGET_NR_ustat 62 ++#define TARGET_NR_dup2 63 ++#define TARGET_NR_getppid 64 ++#define TARGET_NR_getpgrp 65 ++#define TARGET_NR_setsid 66 ++#define TARGET_NR_sigaction 67 ++#define TARGET_NR_sigsuspend 72 ++#define TARGET_NR_sigpending 73 ++#define TARGET_NR_sethostname 74 ++#define TARGET_NR_setrlimit 75 ++#define TARGET_NR_getrusage 77 ++#define TARGET_NR_gettimeofday 78 ++#define TARGET_NR_settimeofday 79 ++#define TARGET_NR_symlink 83 ++#define TARGET_NR_readlink 85 ++#define TARGET_NR_uselib 86 ++#define TARGET_NR_swapon 87 ++#define TARGET_NR_reboot 88 ++#define TARGET_NR_readdir 89 ++#define TARGET_NR_mmap 90 ++#define TARGET_NR_munmap 91 ++#define TARGET_NR_truncate 92 ++#define TARGET_NR_ftruncate 93 ++#define TARGET_NR_fchmod 94 ++#define TARGET_NR_getpriority 96 ++#define TARGET_NR_setpriority 97 ++#define TARGET_NR_statfs 99 ++#define TARGET_NR_fstatfs 100 ++#define TARGET_NR_socketcall 102 ++#define TARGET_NR_syslog 103 ++#define TARGET_NR_setitimer 104 ++#define TARGET_NR_getitimer 105 ++#define TARGET_NR_stat 106 ++#define TARGET_NR_lstat 107 ++#define TARGET_NR_fstat 108 ++#define TARGET_NR_lookup_dcookie 110 ++#define TARGET_NR_vhangup 111 ++#define TARGET_NR_idle 112 ++#define TARGET_NR_wait4 114 ++#define TARGET_NR_swapoff 115 ++#define TARGET_NR_sysinfo 116 ++#define TARGET_NR_ipc 117 ++#define TARGET_NR_fsync 118 ++#define TARGET_NR_sigreturn 119 ++#define TARGET_NR_clone 120 ++#define TARGET_NR_setdomainname 121 ++#define TARGET_NR_uname 122 ++#define TARGET_NR_adjtimex 124 ++#define TARGET_NR_mprotect 125 ++#define TARGET_NR_sigprocmask 126 ++#define TARGET_NR_create_module 127 ++#define TARGET_NR_init_module 128 ++#define TARGET_NR_delete_module 129 ++#define TARGET_NR_get_kernel_syms 130 ++#define TARGET_NR_quotactl 131 ++#define TARGET_NR_getpgid 132 ++#define TARGET_NR_fchdir 133 ++#define TARGET_NR_bdflush 134 ++#define TARGET_NR_sysfs 135 ++#define TARGET_NR_personality 136 ++#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ ++#define TARGET_NR_getdents 141 ++#define TARGET_NR_flock 143 ++#define TARGET_NR_msync 144 ++#define TARGET_NR_readv 145 ++#define TARGET_NR_writev 146 ++#define TARGET_NR_getsid 147 ++#define TARGET_NR_fdatasync 148 ++#define TARGET_NR__sysctl 149 ++#define TARGET_NR_mlock 150 ++#define TARGET_NR_munlock 151 ++#define TARGET_NR_mlockall 152 ++#define TARGET_NR_munlockall 153 ++#define TARGET_NR_sched_setparam 154 ++#define TARGET_NR_sched_getparam 155 ++#define TARGET_NR_sched_setscheduler 156 ++#define TARGET_NR_sched_getscheduler 157 ++#define TARGET_NR_sched_yield 158 ++#define TARGET_NR_sched_get_priority_max 159 ++#define TARGET_NR_sched_get_priority_min 160 ++#define TARGET_NR_sched_rr_get_interval 161 ++#define TARGET_NR_nanosleep 162 ++#define TARGET_NR_mremap 163 ++#define TARGET_NR_query_module 167 ++#define TARGET_NR_poll 168 ++#define TARGET_NR_nfsservctl 169 ++#define TARGET_NR_prctl 172 ++#define TARGET_NR_rt_sigreturn 173 ++#define TARGET_NR_rt_sigaction 174 ++#define TARGET_NR_rt_sigprocmask 175 ++#define TARGET_NR_rt_sigpending 176 ++#define TARGET_NR_rt_sigtimedwait 177 ++#define TARGET_NR_rt_sigqueueinfo 178 ++#define TARGET_NR_rt_sigsuspend 179 ++#define TARGET_NR_pread64 180 ++#define TARGET_NR_pwrite64 181 ++#define TARGET_NR_getcwd 183 ++#define TARGET_NR_capget 184 ++#define TARGET_NR_capset 185 ++#define TARGET_NR_sigaltstack 186 ++#define TARGET_NR_sendfile 187 ++#define TARGET_NR_getpmsg 188 ++#define TARGET_NR_putpmsg 189 ++#define TARGET_NR_vfork 190 ++#define TARGET_NR_pivot_root 217 ++#define TARGET_NR_mincore 218 ++#define TARGET_NR_madvise 219 ++#define TARGET_NR_getdents64 220 ++#define TARGET_NR_readahead 222 ++#define TARGET_NR_setxattr 224 ++#define TARGET_NR_lsetxattr 225 ++#define TARGET_NR_fsetxattr 226 ++#define TARGET_NR_getxattr 227 ++#define TARGET_NR_lgetxattr 228 ++#define TARGET_NR_fgetxattr 229 ++#define TARGET_NR_listxattr 230 ++#define TARGET_NR_llistxattr 231 ++#define TARGET_NR_flistxattr 232 ++#define TARGET_NR_removexattr 233 ++#define TARGET_NR_lremovexattr 234 ++#define TARGET_NR_fremovexattr 235 ++#define TARGET_NR_gettid 236 ++#define TARGET_NR_tkill 237 ++#define TARGET_NR_futex 238 ++#define TARGET_NR_sched_setaffinity 239 ++#define TARGET_NR_sched_getaffinity 240 ++#define TARGET_NR_tgkill 241 ++/* Number 242 is reserved for tux */ ++#define TARGET_NR_io_setup 243 ++#define TARGET_NR_io_destroy 244 ++#define TARGET_NR_io_getevents 245 ++#define TARGET_NR_io_submit 246 ++#define TARGET_NR_io_cancel 247 ++#define TARGET_NR_exit_group 248 ++#define TARGET_NR_epoll_create 249 ++#define TARGET_NR_epoll_ctl 250 ++#define TARGET_NR_epoll_wait 251 ++#define TARGET_NR_set_tid_address 252 ++#define TARGET_NR_fadvise64 253 ++#define TARGET_NR_timer_create 254 ++#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) ++#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) ++#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) ++#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) ++#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) ++#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) ++#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) ++#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) ++/* Number 263 is reserved for vserver */ ++#define TARGET_NR_statfs64 265 ++#define TARGET_NR_fstatfs64 266 ++#define TARGET_NR_remap_file_pages 267 ++/* Number 268 is reserved for new sys_mbind */ ++/* Number 269 is reserved for new sys_get_mempolicy */ ++/* Number 270 is reserved for new sys_set_mempolicy */ ++#define TARGET_NR_mq_open 271 ++#define TARGET_NR_mq_unlink 272 ++#define TARGET_NR_mq_timedsend 273 ++#define TARGET_NR_mq_timedreceive 274 ++#define TARGET_NR_mq_notify 275 ++#define TARGET_NR_mq_getsetattr 276 ++#define TARGET_NR_kexec_load 277 ++#define TARGET_NR_add_key 278 ++#define TARGET_NR_request_key 279 ++#define TARGET_NR_keyctl 280 ++#define TARGET_NR_waitid 281 ++#define TARGET_NR_ioprio_set 282 ++#define TARGET_NR_ioprio_get 283 ++#define TARGET_NR_inotify_init 284 ++#define TARGET_NR_inotify_add_watch 285 ++#define TARGET_NR_inotify_rm_watch 286 ++/* Number 287 is reserved for new sys_migrate_pages */ ++#define TARGET_NR_openat 288 ++#define TARGET_NR_mkdirat 289 ++#define TARGET_NR_mknodat 290 ++#define TARGET_NR_fchownat 291 ++#define TARGET_NR_futimesat 292 ++#define TARGET_NR_unlinkat 294 ++#define TARGET_NR_renameat 295 ++#define TARGET_NR_linkat 296 ++#define TARGET_NR_symlinkat 297 ++#define TARGET_NR_readlinkat 298 ++#define TARGET_NR_fchmodat 299 ++#define TARGET_NR_faccessat 300 ++#define TARGET_NR_pselect6 301 ++#define TARGET_NR_ppoll 302 ++#define TARGET_NR_unshare 303 ++#define TARGET_NR_set_robust_list 304 ++#define TARGET_NR_get_robust_list 305 ++#define TARGET_NR_splice 306 ++#define TARGET_NR_sync_file_range 307 ++#define TARGET_NR_tee 308 ++#define TARGET_NR_vmsplice 309 ++/* Number 310 is reserved for new sys_move_pages */ ++#define TARGET_NR_getcpu 311 ++#define TARGET_NR_epoll_pwait 312 ++#define TARGET_NR_utimes 313 ++#define TARGET_NR_fallocate 314 ++#define TARGET_NR_utimensat 315 ++#define TARGET_NR_signalfd 316 ++#define TARGET_NR_timerfd 317 ++#define TARGET_NR_eventfd 318 ++#define TARGET_NR_timerfd_create 319 ++#define TARGET_NR_timerfd_settime 320 ++#define TARGET_NR_timerfd_gettime 321 ++#define TARGET_NR_signalfd4 322 ++#define TARGET_NR_eventfd2 323 ++#define TARGET_NR_inotify_init1 324 ++#define TARGET_NR_pipe2 325 ++#define TARGET_NR_dup3 326 ++#define TARGET_NR_epoll_create1 327 ++#define NR_syscalls 328 ++ ++/* ++ * There are some system calls that are not present on 64 bit, some ++ * have a different name although they do the same (e.g. TARGET_NR_chown32 ++ * is TARGET_NR_chown on 64 bit). ++ */ ++#ifndef TARGET_S390X ++ ++#define TARGET_NR_time 13 ++#define TARGET_NR_lchown 16 ++#define TARGET_NR_setuid 23 ++#define TARGET_NR_getuid 24 ++#define TARGET_NR_stime 25 ++#define TARGET_NR_setgid 46 ++#define TARGET_NR_getgid 47 ++#define TARGET_NR_geteuid 49 ++#define TARGET_NR_getegid 50 ++#define TARGET_NR_setreuid 70 ++#define TARGET_NR_setregid 71 ++#define TARGET_NR_getrlimit 76 ++#define TARGET_NR_getgroups 80 ++#define TARGET_NR_setgroups 81 ++#define TARGET_NR_fchown 95 ++#define TARGET_NR_ioperm 101 ++#define TARGET_NR_setfsuid 138 ++#define TARGET_NR_setfsgid 139 ++#define TARGET_NR__llseek 140 ++#define TARGET_NR__newselect 142 ++#define TARGET_NR_setresuid 164 ++#define TARGET_NR_getresuid 165 ++#define TARGET_NR_setresgid 170 ++#define TARGET_NR_getresgid 171 ++#define TARGET_NR_chown 182 ++#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ ++#define TARGET_NR_mmap2 192 ++#define TARGET_NR_truncate64 193 ++#define TARGET_NR_ftruncate64 194 ++#define TARGET_NR_stat64 195 ++#define TARGET_NR_lstat64 196 ++#define TARGET_NR_fstat64 197 ++#define TARGET_NR_lchown32 198 ++#define TARGET_NR_getuid32 199 ++#define TARGET_NR_getgid32 200 ++#define TARGET_NR_geteuid32 201 ++#define TARGET_NR_getegid32 202 ++#define TARGET_NR_setreuid32 203 ++#define TARGET_NR_setregid32 204 ++#define TARGET_NR_getgroups32 205 ++#define TARGET_NR_setgroups32 206 ++#define TARGET_NR_fchown32 207 ++#define TARGET_NR_setresuid32 208 ++#define TARGET_NR_getresuid32 209 ++#define TARGET_NR_setresgid32 210 ++#define TARGET_NR_getresgid32 211 ++#define TARGET_NR_chown32 212 ++#define TARGET_NR_setuid32 213 ++#define TARGET_NR_setgid32 214 ++#define TARGET_NR_setfsuid32 215 ++#define TARGET_NR_setfsgid32 216 ++#define TARGET_NR_fcntl64 221 ++#define TARGET_NR_sendfile64 223 ++#define TARGET_NR_fadvise64_64 264 ++#define TARGET_NR_fstatat64 293 ++ ++#else ++ ++#define TARGET_NR_select 142 ++#define TARGET_NR_getrlimit 191 /* SuS compliant getrlimit */ ++#define TARGET_NR_lchown 198 ++#define TARGET_NR_getuid 199 ++#define TARGET_NR_getgid 200 ++#define TARGET_NR_geteuid 201 ++#define TARGET_NR_getegid 202 ++#define TARGET_NR_setreuid 203 ++#define TARGET_NR_setregid 204 ++#define TARGET_NR_getgroups 205 ++#define TARGET_NR_setgroups 206 ++#define TARGET_NR_fchown 207 ++#define TARGET_NR_setresuid 208 ++#define TARGET_NR_getresuid 209 ++#define TARGET_NR_setresgid 210 ++#define TARGET_NR_getresgid 211 ++#define TARGET_NR_chown 212 ++#define TARGET_NR_setuid 213 ++#define TARGET_NR_setgid 214 ++#define TARGET_NR_setfsuid 215 ++#define TARGET_NR_setfsgid 216 ++#define TARGET_NR_newfstatat 293 ++ ++#endif ++ +diff --git a/linux-user/s390x/target_signal.h b/linux-user/s390x/target_signal.h +new file mode 100644 +index 0000000..b4816b0 +--- /dev/null ++++ b/linux-user/s390x/target_signal.h +@@ -0,0 +1,26 @@ ++#ifndef TARGET_SIGNAL_H ++#define TARGET_SIGNAL_H ++ ++#include "cpu.h" ++ ++typedef struct target_sigaltstack { ++ abi_ulong ss_sp; ++ int ss_flags; ++ abi_ulong ss_size; ++} 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 abi_ulong get_sp_from_cpustate(CPUS390XState *state) ++{ ++ return state->regs[15]; ++} ++ ++#endif /* TARGET_SIGNAL_H */ +diff --git a/linux-user/s390x/termbits.h b/linux-user/s390x/termbits.h +new file mode 100644 +index 0000000..2a78a05 +--- /dev/null ++++ b/linux-user/s390x/termbits.h +@@ -0,0 +1,283 @@ ++/* ++ * include/asm-s390/termbits.h ++ * ++ * S390 version ++ * ++ * Derived from "include/asm-i386/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_line; /* line discipline */ ++ unsigned char c_cc[TARGET_NCCS]; /* control characters */ ++}; ++ ++struct target_termios2 { ++ 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_line; /* line discipline */ ++ unsigned char c_cc[TARGET_NCCS]; /* control characters */ ++ unsigned int c_ispeed; /* input speed */ ++ unsigned int c_ospeed; /* output speed */ ++}; ++ ++struct target_ktermios { ++ 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_line; /* line discipline */ ++ unsigned char c_cc[TARGET_NCCS]; /* control characters */ ++ unsigned int c_ispeed; /* input speed */ ++ unsigned int c_ospeed; /* output speed */ ++}; ++ ++/* 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_VTIME 5 ++#define TARGET_VMIN 6 ++#define TARGET_VSWTC 7 ++#define TARGET_VSTART 8 ++#define TARGET_VSTOP 9 ++#define TARGET_VSUSP 10 ++#define TARGET_VEOL 11 ++#define TARGET_VREPRINT 12 ++#define TARGET_VDISCARD 13 ++#define TARGET_VWERASE 14 ++#define TARGET_VLNEXT 15 ++#define TARGET_VEOL2 16 ++ ++/* 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 */ ++#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define TARGET_CRTSCTS 020000000000 /* flow control */ ++ ++#define TARGET_IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ ++ ++/* 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_TOSTOP 0000400 ++#define TARGET_ECHOCTL 0001000 ++#define TARGET_ECHOPRT 0002000 ++#define TARGET_ECHOKE 0004000 ++#define TARGET_FLUSHO 0010000 ++#define TARGET_PENDIN 0040000 ++#define TARGET_IEXTEN 0100000 ++ ++/* tcflow() and TCXONC use these */ ++#define TARGET_TCOOFF 0 ++#define TARGET_TCOON 1 ++#define TARGET_TCIOFF 2 ++#define TARGET_TCION 3 ++ ++/* tcflush() and TCFLSH use these */ ++#define TARGET_TCIFLUSH 0 ++#define TARGET_TCOFLUSH 1 ++#define TARGET_TCIOFLUSH 2 ++ ++/* tcsetattr uses these */ ++#define TARGET_TCSANOW 0 ++#define TARGET_TCSADRAIN 1 ++#define TARGET_TCSAFLUSH 2 ++ ++/* ++ * include/asm-s390/ioctls.h ++ * ++ * S390 version ++ * ++ * Derived from "include/asm-i386/ioctls.h" ++ */ ++ ++/* 0x54 is just a magic number to make these relatively unique ('T') */ ++ ++#define TARGET_TCGETS 0x5401 ++#define TARGET_TCSETS 0x5402 ++#define TARGET_TCSETSW 0x5403 ++#define TARGET_TCSETSF 0x5404 ++#define TARGET_TCGETA 0x5405 ++#define TARGET_TCSETA 0x5406 ++#define TARGET_TCSETAW 0x5407 ++#define TARGET_TCSETAF 0x5408 ++#define TARGET_TCSBRK 0x5409 ++#define TARGET_TCXONC 0x540A ++#define TARGET_TCFLSH 0x540B ++#define TARGET_TIOCEXCL 0x540C ++#define TARGET_TIOCNXCL 0x540D ++#define TARGET_TIOCSCTTY 0x540E ++#define TARGET_TIOCGPGRP 0x540F ++#define TARGET_TIOCSPGRP 0x5410 ++#define TARGET_TIOCOUTQ 0x5411 ++#define TARGET_TIOCSTI 0x5412 ++#define TARGET_TIOCGWINSZ 0x5413 ++#define TARGET_TIOCSWINSZ 0x5414 ++#define TARGET_TIOCMGET 0x5415 ++#define TARGET_TIOCMBIS 0x5416 ++#define TARGET_TIOCMBIC 0x5417 ++#define TARGET_TIOCMSET 0x5418 ++#define TARGET_TIOCGSOFTCAR 0x5419 ++#define TARGET_TIOCSSOFTCAR 0x541A ++#define TARGET_FIONREAD 0x541B ++#define TARGET_TIOCINQ FIONREAD ++#define TARGET_TIOCLINUX 0x541C ++#define TARGET_TIOCCONS 0x541D ++#define TARGET_TIOCGSERIAL 0x541E ++#define TARGET_TIOCSSERIAL 0x541F ++#define TARGET_TIOCPKT 0x5420 ++#define TARGET_FIONBIO 0x5421 ++#define TARGET_TIOCNOTTY 0x5422 ++#define TARGET_TIOCSETD 0x5423 ++#define TARGET_TIOCGETD 0x5424 ++#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TARGET_TCGETS2 _IOR('T',0x2A, struct termios2) ++#define TARGET_TCSETS2 _IOW('T',0x2B, struct termios2) ++#define TARGET_TCSETSW2 _IOW('T',0x2C, struct termios2) ++#define TARGET_TCSETSF2 _IOW('T',0x2D, struct termios2) ++#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++#define TARGET_TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ ++ ++#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ ++#define TARGET_FIOCLEX 0x5451 ++#define TARGET_FIOASYNC 0x5452 ++#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 for a change on serial input line(s) */ ++#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define TARGET_FIOQSIZE 0x545E ++ ++/* Used for packet mode */ ++#define TARGET_TIOCPKT_DATA 0 ++#define TARGET_TIOCPKT_FLUSHREAD 1 ++#define TARGET_TIOCPKT_FLUSHWRITE 2 ++#define TARGET_TIOCPKT_STOP 4 ++#define TARGET_TIOCPKT_START 8 ++#define TARGET_TIOCPKT_NOSTOP 16 ++#define TARGET_TIOCPKT_DOSTOP 32 ++ ++#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++ +diff --git a/linux-user/signal.c b/linux-user/signal.c +index 1aa9eab..d8ed2e8 100644 +--- a/linux-user/signal.c ++++ b/linux-user/signal.c +@@ -3432,6 +3432,320 @@ long do_rt_sigreturn(CPUState *env) + return -TARGET_ENOSYS; + } + ++#elif defined(TARGET_S390X) ++ ++#define __NUM_GPRS 16 ++#define __NUM_FPRS 16 ++#define __NUM_ACRS 16 ++ ++#define S390_SYSCALL_SIZE 2 ++#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ ++ ++#define _SIGCONTEXT_NSIG 64 ++#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ ++#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) ++#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) ++#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */ ++#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) ++ ++typedef struct ++{ ++ target_psw_t psw; ++ target_ulong gprs[__NUM_GPRS]; ++ unsigned int acrs[__NUM_ACRS]; ++} target_s390_regs_common; ++ ++typedef struct ++{ ++ unsigned int fpc; ++ double fprs[__NUM_FPRS]; ++} target_s390_fp_regs; ++ ++typedef struct ++{ ++ target_s390_regs_common regs; ++ target_s390_fp_regs fpregs; ++} target_sigregs; ++ ++struct target_sigcontext ++{ ++ target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; ++ target_sigregs *sregs; ++}; ++ ++typedef struct ++{ ++ uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; ++ struct target_sigcontext sc; ++ target_sigregs sregs; ++ int signo; ++ uint8_t retcode[S390_SYSCALL_SIZE]; ++} sigframe; ++ ++struct target_ucontext { ++ target_ulong uc_flags; ++ struct target_ucontext *uc_link; ++ target_stack_t uc_stack; ++ target_sigregs uc_mcontext; ++ target_sigset_t uc_sigmask; /* mask last for extensibility */ ++}; ++ ++typedef struct ++{ ++ uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; ++ uint8_t retcode[S390_SYSCALL_SIZE]; ++ struct target_siginfo info; ++ struct target_ucontext uc; ++} rt_sigframe; ++ ++static inline abi_ulong ++get_sigframe(struct target_sigaction *ka, CPUState *env, size_t frame_size) ++{ ++ abi_ulong sp; ++ ++ /* Default to using normal stack */ ++ sp = env->regs[15]; ++ ++ /* This is the X/Open sanctioned signal stack switching. */ ++ if (ka->sa_flags & TARGET_SA_ONSTACK) { ++ if (! sas_ss_flags(sp)) ++ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; ++ } ++ ++ /* This is the legacy signal stack switching. */ ++ else if (/* FIXME !user_mode(regs) */ 0 && ++ !(ka->sa_flags & TARGET_SA_RESTORER) && ++ ka->sa_restorer) { ++ sp = (abi_ulong) ka->sa_restorer; ++ } ++ ++ return (sp - frame_size) & -8ul; ++} ++ ++static void save_sigregs(CPUState *env, target_sigregs *sregs) ++{ ++ int i; ++ //save_access_regs(current->thread.acrs); FIXME ++ ++ /* Copy a 'clean' PSW mask to the user to avoid leaking ++ information about whether PER is currently on. */ ++ __put_user(env->psw.mask, &sregs->regs.psw.mask); ++ __put_user(env->psw.addr, &sregs->regs.psw.addr); ++ for (i = 0; i < 16; i++) ++ __put_user(env->regs[i], &sregs->regs.gprs[i]); ++ for (i = 0; i < 16; i++) ++ __put_user(env->aregs[i], &sregs->regs.acrs[i]); ++ /* ++ * We have to store the fp registers to current->thread.fp_regs ++ * to merge them with the emulated registers. ++ */ ++ //save_fp_regs(¤t->thread.fp_regs); FIXME ++ for (i = 0; i < 16; i++) ++ __put_user(env->fregs[i].i, &sregs->fpregs.fprs[i]); ++} ++ ++static void setup_frame(int sig, struct target_sigaction *ka, ++ target_sigset_t *set, CPUState *env) ++{ ++ sigframe *frame; ++ abi_ulong frame_addr; ++ ++ frame_addr = get_sigframe(ka, env, sizeof *frame); ++ qemu_log("%s: frame_addr 0x%lx\n", __FUNCTION__, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) ++ goto give_sigsegv; ++ ++ qemu_log("%s: 1\n", __FUNCTION__); ++ if (__put_user(set->sig[0], &frame->sc.oldmask[0])) ++ goto give_sigsegv; ++ ++ save_sigregs(env, &frame->sregs); ++ ++ __put_user((abi_ulong)&frame->sregs, (abi_ulong *)&frame->sc.sregs); ++ ++ /* Set up to return from userspace. If provided, use a stub ++ already in userspace. */ ++ if (ka->sa_flags & TARGET_SA_RESTORER) { ++ env->regs[14] = (unsigned long) ++ ka->sa_restorer | PSW_ADDR_AMODE; ++ } else { ++ env->regs[14] = (unsigned long) ++ frame->retcode | PSW_ADDR_AMODE; ++ if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, ++ (uint16_t *)(frame->retcode))) ++ goto give_sigsegv; ++ } ++ ++ /* Set up backchain. */ ++ if (__put_user(env->regs[15], (abi_ulong *) frame)) ++ goto give_sigsegv; ++ ++ /* Set up registers for signal handler */ ++ env->regs[15] = (target_ulong) frame; ++ env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; ++ ++ env->regs[2] = sig; //map_signal(sig); ++ env->regs[3] = (target_ulong) &frame->sc; ++ ++ /* We forgot to include these in the sigcontext. ++ To avoid breaking binary compatibility, they are passed as args. */ ++ env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no; ++ env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; ++ ++ /* Place signal number on stack to allow backtrace from handler. */ ++ if (__put_user(env->regs[2], (int *) &frame->signo)) ++ goto give_sigsegv; ++ unlock_user_struct(frame, frame_addr, 1); ++ return; ++ ++give_sigsegv: ++ qemu_log("%s: give_sigsegv\n", __FUNCTION__); ++ unlock_user_struct(frame, frame_addr, 1); ++ force_sig(TARGET_SIGSEGV); ++} ++ ++static void setup_rt_frame(int sig, struct target_sigaction *ka, ++ target_siginfo_t *info, ++ target_sigset_t *set, CPUState *env) ++{ ++ int i; ++ rt_sigframe *frame; ++ abi_ulong frame_addr; ++ ++ frame_addr = get_sigframe(ka, env, sizeof *frame); ++ qemu_log("%s: frame_addr 0x%lx\n", __FUNCTION__, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) ++ goto give_sigsegv; ++ ++ qemu_log("%s: 1\n", __FUNCTION__); ++ if (copy_siginfo_to_user(&frame->info, info)) ++ goto give_sigsegv; ++ ++ /* Create the ucontext. */ ++ __put_user(0, &frame->uc.uc_flags); ++ __put_user((abi_ulong)NULL, (abi_ulong*)&frame->uc.uc_link); ++ __put_user(target_sigaltstack_used.ss_sp, &frame->uc.uc_stack.ss_sp); ++ __put_user(sas_ss_flags(get_sp_from_cpustate(env)), ++ &frame->uc.uc_stack.ss_flags); ++ __put_user(target_sigaltstack_used.ss_size, &frame->uc.uc_stack.ss_size); ++ save_sigregs(env, &frame->uc.uc_mcontext); ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) { ++ __put_user((abi_ulong)set->sig[i], (abi_ulong*)&frame->uc.uc_sigmask.sig[i]); ++ } ++ ++ /* Set up to return from userspace. If provided, use a stub ++ already in userspace. */ ++ if (ka->sa_flags & TARGET_SA_RESTORER) { ++ env->regs[14] = (unsigned long) ++ ka->sa_restorer | PSW_ADDR_AMODE; ++ } else { ++ env->regs[14] = (unsigned long) ++ frame->retcode | PSW_ADDR_AMODE; ++ if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, ++ (uint16_t *)(frame->retcode))) ++ goto give_sigsegv; ++ } ++ ++ /* Set up backchain. */ ++ if (__put_user(env->regs[15], (abi_ulong *) frame)) ++ goto give_sigsegv; ++ ++ /* Set up registers for signal handler */ ++ env->regs[15] = (target_ulong) frame; ++ env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; ++ ++ env->regs[2] = sig; //map_signal(sig); ++ env->regs[3] = (target_ulong) &frame->info; ++ env->regs[4] = (target_ulong) &frame->uc; ++ return; ++ ++give_sigsegv: ++ qemu_log("%s: give_sigsegv\n", __FUNCTION__); ++ unlock_user_struct(frame, frame_addr, 1); ++ force_sig(TARGET_SIGSEGV); ++} ++ ++static int ++restore_sigregs(CPUState *env, target_sigregs *sc) ++{ ++ int err = 0; ++ int i; ++ ++ for (i = 0; i < 16; i++) { ++ err |= __get_user(env->regs[i], &sc->regs.gprs[i]); ++ } ++ ++ err |= __get_user(env->psw.mask, &sc->regs.psw.mask); ++ qemu_log("%s: sc->regs.psw.addr 0x%lx env->psw.addr 0x%lx\n", __FUNCTION__, sc->regs.psw.addr, env->psw.addr); ++ err |= __get_user(env->psw.addr, &sc->regs.psw.addr); ++ /* FIXME: 31-bit -> | PSW_ADDR_AMODE */ ++ ++ for (i = 0; i < 16; i++) { ++ err |= __get_user(env->aregs[i], &sc->regs.acrs[i]); ++ } ++ for (i = 0; i < 16; i++) { ++ err |= __get_user(env->fregs[i].i, &sc->fpregs.fprs[i]); ++ } ++ ++ return err; ++} ++ ++long do_sigreturn(CPUState *env) ++{ ++ sigframe *frame; ++ abi_ulong frame_addr = env->regs[15]; ++ qemu_log("%s: frame_addr 0x%lx\n", __FUNCTION__, frame_addr); ++ target_sigset_t target_set; ++ sigset_t set; ++ ++ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) ++ goto badframe; ++ if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) ++ goto badframe; ++ ++ target_to_host_sigset_internal(&set, &target_set); ++ sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */ ++ ++ if (restore_sigregs(env, &frame->sregs)) ++ goto badframe; ++ ++ unlock_user_struct(frame, frame_addr, 0); ++ return env->regs[2]; ++ ++badframe: ++ unlock_user_struct(frame, frame_addr, 0); ++ force_sig(TARGET_SIGSEGV); ++ return 0; ++} ++ ++long do_rt_sigreturn(CPUState *env) ++{ ++ rt_sigframe *frame; ++ abi_ulong frame_addr = env->regs[15]; ++ qemu_log("%s: frame_addr 0x%lx\n", __FUNCTION__, frame_addr); ++ sigset_t set; ++ ++ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) ++ goto badframe; ++ target_to_host_sigset(&set, &frame->uc.uc_sigmask); ++ ++ sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */ ++ ++ if (restore_sigregs(env, &frame->uc.uc_mcontext)) ++ goto badframe; ++ ++ if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.uc_stack), 0, ++ get_sp_from_cpustate(env)) == -EFAULT) ++ goto badframe; ++ unlock_user_struct(frame, frame_addr, 0); ++ return env->regs[2]; ++ ++badframe: ++ unlock_user_struct(frame, frame_addr, 0); ++ force_sig(TARGET_SIGSEGV); ++ return 0; ++} ++ + #elif defined(TARGET_PPC) && !defined(TARGET_PPC64) + + /* FIXME: Many of the structures are defined for both PPC and PPC64, but +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 548be54..e9b07df 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -5107,7 +5107,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + ret = get_errno(settimeofday(&tv, NULL)); + } + break; +-#ifdef TARGET_NR_select ++#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390) + case TARGET_NR_select: + { + struct target_sel_arg_struct *sel; +@@ -5214,7 +5214,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + #endif + #ifdef TARGET_NR_mmap + case TARGET_NR_mmap: +-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) ++#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \ ++ defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \ ++ || defined(TARGET_S390X) + { + abi_ulong *v; + abi_ulong v1, v2, v3, v4, v5, v6; +@@ -5698,6 +5700,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); + #elif defined(TARGET_CRIS) + ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5)); ++#elif defined(TARGET_S390X) ++ ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); + #else + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); + #endif +@@ -5904,8 +5908,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + break; + #endif /* TARGET_NR_getdents64 */ +-#ifdef TARGET_NR__newselect ++#if defined(TARGET_NR__newselect) || defined(TARGET_S390X) ++#ifdef TARGET_S390X ++ case TARGET_NR_select: ++#else + case TARGET_NR__newselect: ++#endif + ret = do_select(arg1, arg2, arg3, arg4, arg5); + break; + #endif +@@ -6129,7 +6137,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + goto unimplemented; + case TARGET_NR_sigaltstack: + #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ +- defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) ++ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_S390X) + ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); + break; + #else +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index 0cbe396..0f4fbd7 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -55,7 +55,7 @@ + #endif + + #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ +- || defined(TARGET_M68K) || defined(TARGET_CRIS) ++ || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_S390X) + + #define TARGET_IOC_SIZEBITS 14 + #define TARGET_IOC_DIRBITS 2 +@@ -315,7 +315,10 @@ struct target_sigaction; + int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact); + +-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) ++#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || \ ++ defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || \ ++ defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ ++ defined(TARGET_MICROBLAZE) || defined(TARGET_S390X) + + #if defined(TARGET_SPARC) + #define TARGET_SA_NOCLDSTOP 8u +@@ -1617,6 +1620,27 @@ struct target_stat { + + abi_long __unused[3]; + }; ++#elif defined(TARGET_S390X) ++struct target_stat { ++ abi_ulong st_dev; ++ abi_ulong st_ino; ++ abi_ulong st_nlink; ++ unsigned int st_mode; ++ unsigned int st_uid; ++ unsigned int st_gid; ++ unsigned int __pad1; ++ abi_ulong st_rdev; ++ abi_ulong st_size; ++ abi_ulong target_st_atime; ++ abi_ulong target_st_atime_nsec; ++ abi_ulong target_st_mtime; ++ abi_ulong target_st_mtime_nsec; ++ abi_ulong target_st_ctime; ++ abi_ulong target_st_ctime_nsec; ++ abi_ulong st_blksize; ++ abi_long st_blocks; ++ abi_ulong __unused[3]; ++}; + #else + #error unsupported CPU + #endif +@@ -1703,6 +1727,34 @@ struct target_statfs64 { + abi_long f_frsize; + abi_long f_spare[5]; + }; ++#elif defined(TARGET_S390X) ++struct target_statfs { ++ int32_t f_type; ++ int32_t f_bsize; ++ abi_long f_blocks; ++ abi_long f_bfree; ++ abi_long f_bavail; ++ abi_long f_files; ++ abi_long f_ffree; ++ kernel_fsid_t f_fsid; ++ int32_t f_namelen; ++ int32_t f_frsize; ++ int32_t f_spare[5]; ++}; ++ ++struct target_statfs64 { ++ int32_t f_type; ++ int32_t f_bsize; ++ abi_long f_blocks; ++ abi_long f_bfree; ++ abi_long f_bavail; ++ abi_long f_files; ++ abi_long f_ffree; ++ kernel_fsid_t f_fsid; ++ int32_t f_namelen; ++ int32_t f_frsize; ++ int32_t f_spare[5]; ++}; + #else + struct target_statfs { + uint32_t f_type; +diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh +index 67d6728..e676f57 100644 +--- a/qemu-binfmt-conf.sh ++++ b/qemu-binfmt-conf.sh +@@ -1,5 +1,5 @@ + #!/bin/sh +-# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC program execution by the kernel ++# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390 program execution by the kernel + + # load the binfmt_misc module + if [ ! -d /proc/sys/fs/binfmt_misc ]; then +@@ -60,3 +60,6 @@ if [ $cpu != "mips" ] ; then + echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register + fi ++if [ $cpu != "s390x" ] ; then ++ echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register ++fi +-- +1.6.2.1 + diff --git a/0025-linux-user-don-t-do-locking-in-single-threaded-proc.patch b/0025-linux-user-don-t-do-locking-in-single-threaded-proc.patch new file mode 100644 index 00000000..cf33fb2c --- /dev/null +++ b/0025-linux-user-don-t-do-locking-in-single-threaded-proc.patch @@ -0,0 +1,96 @@ +From f06038e90fe4eb5dd8c73735356125ab0d3e899b Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Wed, 22 Jul 2009 14:03:19 +0200 +Subject: [PATCH 25/33] linux-user: don't do locking in single-threaded processes + +Skips setting the tb_lock if a process doesn't have more than one thread, +which is usually the case. Results in about 20% performance gain (measured +with the s390x target, but the effect should be similar with other targets). + +Signed-off-by: Ulrich Hecht +--- + cpu-defs.h | 8 ++++++++ + cpu-exec.c | 14 ++++++++++++-- + linux-user/syscall.c | 1 + + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/cpu-defs.h b/cpu-defs.h +index d73ec0a..27e5bb2 100644 +--- a/cpu-defs.h ++++ b/cpu-defs.h +@@ -135,6 +135,13 @@ typedef struct CPUWatchpoint { + } CPUWatchpoint; + + #define CPU_TEMP_BUF_NLONGS 128 ++ ++#ifdef CONFIG_USER_ONLY ++#define MULTITHREAD uint32_t multithreaded; ++#else ++#define MULTITHREAD ++#endif ++ + #define CPU_COMMON \ + struct TranslationBlock *current_tb; /* currently executing TB */ \ + /* soft mmu support */ \ +@@ -149,6 +156,7 @@ typedef struct CPUWatchpoint { + uint32_t stop; /* Stop request */ \ + uint32_t stopped; /* Artificially stopped */ \ + uint32_t interrupt_request; \ ++ MULTITHREAD /* needs locking when accessing TBs */ \ + volatile sig_atomic_t exit_request; \ + /* The meaning of the MMU modes is defined in the target code. */ \ + CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ +diff --git a/cpu-exec.c b/cpu-exec.c +index 855ea3e..1371ce4 100644 +--- a/cpu-exec.c ++++ b/cpu-exec.c +@@ -219,6 +219,9 @@ int cpu_exec(CPUState *env1) + TranslationBlock *tb; + uint8_t *tc_ptr; + unsigned long next_tb; ++#ifdef CONFIG_USER_ONLY ++ uint32_t multithreaded; ++#endif + + if (cpu_halted(env1) == EXCP_HALTED) + return EXCP_HALTED; +@@ -604,7 +607,11 @@ int cpu_exec(CPUState *env1) + #endif + } + #endif +- spin_lock(&tb_lock); ++#ifdef CONFIG_USER_ONLY ++ multithreaded = env->multithreaded; ++ if (multithreaded) ++#endif ++ spin_lock(&tb_lock); + tb = tb_find_fast(); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ +@@ -632,7 +639,10 @@ int cpu_exec(CPUState *env1) + tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); + } + } +- spin_unlock(&tb_lock); ++#ifdef CONFIG_USER_ONLY ++ if (multithreaded) ++#endif ++ spin_unlock(&tb_lock); + env->current_tb = tb; + + /* cpu_interrupt might be called while translating the +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index e9b07df..f7a411d 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3560,6 +3560,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, + ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE); + init_task_state(ts); + new_stack = ts->stack; ++ env->multithreaded = 1; + /* we create a new CPU instance. */ + new_env = cpu_copy(env); + /* Init regs that differ from the parent. */ +-- +1.6.2.1 + diff --git a/0026-linux-user-dup3-fallocate-syscalls.patch b/0026-linux-user-dup3-fallocate-syscalls.patch new file mode 100644 index 00000000..3a960bfc --- /dev/null +++ b/0026-linux-user-dup3-fallocate-syscalls.patch @@ -0,0 +1,80 @@ +From 4af40cd06ca8bf1faa436a966833df346d7dba65 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 14:33:36 +0200 +Subject: [PATCH 26/33] linux-user: dup3, fallocate syscalls + +implementations of dup3 and fallocate that are good enough to fool LTP + +Signed-off-by: Ulrich Hecht +--- + configure | 18 ++++++++++++++++++ + linux-user/syscall.c | 10 ++++++++++ + 2 files changed, 28 insertions(+), 0 deletions(-) + +diff --git a/configure b/configure +index 68fa1c1..229f70b 100755 +--- a/configure ++++ b/configure +@@ -1355,6 +1355,21 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + splice=yes + fi + ++# check for fallocate ++fallocate=no ++cat > $TMPC << EOF ++#include ++ ++int main(void) ++{ ++ fallocate(0, 0, 0, 0); ++ return 0; ++} ++EOF ++if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then ++ fallocate=yes ++fi ++ + # Check if tools are available to build documentation. + if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then + build_docs="no" +@@ -1707,6 +1722,9 @@ fi + if test "$splice" = "yes" ; then + echo "#define CONFIG_SPLICE 1" >> $config_host_h + fi ++if test "$fallocate" = "yes" ; then ++ echo "#define CONFIG_FALLOCATE 1" >> $config_host_h ++fi + if test "$inotify" = "yes" ; then + echo "#define CONFIG_INOTIFY 1" >> $config_host_h + fi +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index f7a411d..4fb7998 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -4750,6 +4750,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + case TARGET_NR_dup2: + ret = get_errno(dup2(arg1, arg2)); + break; ++#ifdef TARGET_NR_dup3 ++ case TARGET_NR_dup3: ++ ret = get_errno(dup3(arg1, arg2, arg3)); ++ break; ++#endif + #ifdef TARGET_NR_getppid /* not on alpha */ + case TARGET_NR_getppid: + ret = get_errno(getppid()); +@@ -7016,6 +7021,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + #endif + ++#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate) ++ case TARGET_NR_fallocate: ++ ret = get_errno(fallocate(arg1, arg2, arg3, arg4)); ++ break; ++#endif + default: + unimplemented: + gemu_log("qemu: Unsupported syscall: %d\n", num); +-- +1.6.2.1 + diff --git a/0027-linux-user-fcntl-fixes-for-LTP.patch b/0027-linux-user-fcntl-fixes-for-LTP.patch new file mode 100644 index 00000000..ffdf3772 --- /dev/null +++ b/0027-linux-user-fcntl-fixes-for-LTP.patch @@ -0,0 +1,171 @@ +From b597826b87618cb1cb082e73b52354da2a62423f Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 15:10:30 +0200 +Subject: [PATCH 27/33] linux-user: fcntl fixes for LTP + +Fixes swaps on l_pid which were pretty much of random size. Implements +F_SETLEASE, F_GETLEASE. Now passes all LTP fcntl tests. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 34 ++++++++++++++++++++++------------ + linux-user/syscall_defs.h | 7 +++++++ + 2 files changed, 29 insertions(+), 12 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 4fb7998..86754f1 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3705,6 +3705,14 @@ static int target_to_host_fcntl_cmd(int cmd) + case TARGET_F_SETLKW64: + return F_SETLKW64; + #endif ++ case TARGET_F_SETLEASE: ++ return F_SETLEASE; ++ case TARGET_F_GETLEASE: ++ return F_GETLEASE; ++ case TARGET_F_DUPFD_CLOEXEC: ++ return F_DUPFD_CLOEXEC; ++ case TARGET_F_NOTIFY: ++ return F_NOTIFY; + default: + return -TARGET_EINVAL; + } +@@ -3731,7 +3739,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); +- fl.l_pid = tswapl(target_fl->l_pid); ++ fl.l_pid = tswap32(target_fl->l_pid); + unlock_user_struct(target_fl, arg, 0); + ret = get_errno(fcntl(fd, host_cmd, &fl)); + if (ret == 0) { +@@ -3741,7 +3749,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswapl(fl.l_start); + target_fl->l_len = tswapl(fl.l_len); +- target_fl->l_pid = tswapl(fl.l_pid); ++ target_fl->l_pid = tswap32(fl.l_pid); + unlock_user_struct(target_fl, arg, 1); + } + break; +@@ -3754,7 +3762,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); +- fl.l_pid = tswapl(target_fl->l_pid); ++ fl.l_pid = tswap32(target_fl->l_pid); + unlock_user_struct(target_fl, arg, 0); + ret = get_errno(fcntl(fd, host_cmd, &fl)); + break; +@@ -3766,7 +3774,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + fl64.l_whence = tswap16(target_fl64->l_whence); + fl64.l_start = tswapl(target_fl64->l_start); + fl64.l_len = tswapl(target_fl64->l_len); +- fl64.l_pid = tswap16(target_fl64->l_pid); ++ fl64.l_pid = tswap32(target_fl64->l_pid); + unlock_user_struct(target_fl64, arg, 0); + ret = get_errno(fcntl(fd, host_cmd, &fl64)); + if (ret == 0) { +@@ -3776,7 +3784,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + target_fl64->l_whence = tswap16(fl64.l_whence); + target_fl64->l_start = tswapl(fl64.l_start); + target_fl64->l_len = tswapl(fl64.l_len); +- target_fl64->l_pid = tswapl(fl64.l_pid); ++ target_fl64->l_pid = tswap32(fl64.l_pid); + unlock_user_struct(target_fl64, arg, 1); + } + break; +@@ -3788,7 +3796,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + fl64.l_whence = tswap16(target_fl64->l_whence); + fl64.l_start = tswapl(target_fl64->l_start); + fl64.l_len = tswapl(target_fl64->l_len); +- fl64.l_pid = tswap16(target_fl64->l_pid); ++ fl64.l_pid = tswap32(target_fl64->l_pid); + unlock_user_struct(target_fl64, arg, 0); + ret = get_errno(fcntl(fd, host_cmd, &fl64)); + break; +@@ -3808,6 +3816,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) + case TARGET_F_GETOWN: + case TARGET_F_SETSIG: + case TARGET_F_GETSIG: ++ case TARGET_F_SETLEASE: ++ case TARGET_F_GETLEASE: + ret = get_errno(fcntl(fd, host_cmd, arg)); + break; + +@@ -6630,7 +6640,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ fl.l_pid = tswap32(target_efl->l_pid); + unlock_user_struct(target_efl, arg3, 0); + } else + #endif +@@ -6641,7 +6651,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ fl.l_pid = tswap32(target_fl->l_pid); + unlock_user_struct(target_fl, arg3, 0); + } + ret = get_errno(fcntl(arg1, cmd, &fl)); +@@ -6654,7 +6664,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ target_efl->l_pid = tswap32(fl.l_pid); + unlock_user_struct(target_efl, arg3, 1); + } else + #endif +@@ -6665,7 +6675,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ target_fl->l_pid = tswap32(fl.l_pid); + unlock_user_struct(target_fl, arg3, 1); + } + } +@@ -6681,7 +6691,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ fl.l_pid = tswap32(target_efl->l_pid); + unlock_user_struct(target_efl, arg3, 0); + } else + #endif +@@ -6692,7 +6702,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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); ++ fl.l_pid = tswap32(target_fl->l_pid); + unlock_user_struct(target_fl, arg3, 0); + } + ret = get_errno(fcntl(arg1, cmd, &fl)); +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index 0f4fbd7..481ce59 100644 +--- a/linux-user/syscall_defs.h ++++ b/linux-user/syscall_defs.h +@@ -1824,6 +1824,13 @@ struct target_statfs64 { + #define TARGET_F_SETLK64 13 + #define TARGET_F_SETLKW64 14 + #endif ++ ++#define TARGET_F_LINUX_SPECIFIC_BASE 1024 ++#define TARGET_F_SETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 0) ++#define TARGET_F_GETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 1) ++#define TARGET_F_DUPFD_CLOEXEC (TARGET_F_LINUX_SPECIFIC_BASE + 6) ++#define TARGET_F_NOTIFY (TARGET_F_LINUX_SPECIFIC_BASE+2) ++ + #if defined (TARGET_ARM) + #define TARGET_O_ACCMODE 0003 + #define TARGET_O_RDONLY 00 +-- +1.6.2.1 + diff --git a/0028-linux-user-enable-getdents-for-32-bit-systems.patch b/0028-linux-user-enable-getdents-for-32-bit-systems.patch new file mode 100644 index 00000000..9416e147 --- /dev/null +++ b/0028-linux-user-enable-getdents-for-32-bit-systems.patch @@ -0,0 +1,41 @@ +From cd19670096c6f7affdba9792cb695b851390c184 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 17:17:32 +0200 +Subject: [PATCH 28/33] linux-user: enable getdents for > 32-bit systems + +works perfectly fine with the example from getdents(2) and passes the LTP +tests (tested with s390x on x86_64 emulation) + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 6 +----- + 1 files changed, 1 insertions(+), 5 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 86754f1..49dfb40 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -195,9 +195,7 @@ static int gettid(void) { + return -ENOSYS; + } + #endif +-#if TARGET_ABI_BITS == 32 + _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count); +-#endif + #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) + _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count); + #endif +@@ -5820,9 +5818,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + break; + #endif + case TARGET_NR_getdents: +-#if TARGET_ABI_BITS != 32 +- goto unimplemented; +-#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 ++#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 + { + struct target_dirent *target_dirp; + struct linux_dirent *dirp; +-- +1.6.2.1 + diff --git a/0029-linux-user-define-a-couple-of-syscalls-for-non-uid1.patch b/0029-linux-user-define-a-couple-of-syscalls-for-non-uid1.patch new file mode 100644 index 00000000..354299a2 --- /dev/null +++ b/0029-linux-user-define-a-couple-of-syscalls-for-non-uid1.patch @@ -0,0 +1,271 @@ +From 22a1d92ba7beebc34113d8a95badd56b2901c283 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 17:41:57 +0200 +Subject: [PATCH 29/33] linux-user: define a couple of syscalls for non-uid16 targets + +Quite a number of syscalls are only defined on systems with USE_UID16 +defined; this patch defines them on other systems as well. + +Fixes a large number of uid/gid-related testcases on the s390x target +(and most likely on other targets as well) + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 125 ++++++++++++++++++++++++++++++++++++++++++-------- + 1 files changed, 105 insertions(+), 20 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 49dfb40..b1ef3c9 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -309,7 +309,7 @@ static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode) + return (fchmodat(dirfd, pathname, mode, 0)); + } + #endif +-#if defined(TARGET_NR_fchownat) && defined(USE_UID16) ++#if defined(TARGET_NR_fchownat) + static int sys_fchownat(int dirfd, const char *pathname, uid_t owner, + gid_t group, int flags) + { +@@ -418,7 +418,7 @@ _syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode) + #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) + _syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode) + #endif +-#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16) ++#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) + _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, + uid_t,owner,gid_t,group,int,flags) + #endif +@@ -6382,18 +6382,35 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + case TARGET_NR_setfsgid: + ret = get_errno(setfsgid(arg1)); + break; ++#else /* USE_UID16 */ ++#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) ++ case TARGET_NR_fchownat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(sys_fchownat(arg1, p, arg3, arg4, arg5)); ++ unlock_user(p, arg2, 0); ++ break; ++#endif + #endif /* USE_UID16 */ + +-#ifdef TARGET_NR_lchown32 ++#if defined(TARGET_NR_lchown32) || !defined(USE_UID16) ++#if defined(TARGET_NR_lchown32) + case TARGET_NR_lchown32: ++#else ++ case TARGET_NR_lchown: ++#endif + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(lchown(p, arg2, arg3)); + unlock_user(p, arg1, 0); + break; + #endif +-#ifdef TARGET_NR_getuid32 ++#if defined(TARGET_NR_getuid32) || (defined(TARGET_NR_getuid) && !defined(USE_UID16)) ++#if defined(TARGET_NR_getuid32) + case TARGET_NR_getuid32: ++#else ++ case TARGET_NR_getuid: ++#endif + ret = get_errno(getuid()); + break; + #endif +@@ -6421,33 +6438,57 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + break; + #endif + +-#ifdef TARGET_NR_getgid32 ++#if defined(TARGET_NR_getgid32) || (defined(TARGET_NR_getgid) && !defined(USE_UID16)) ++#if defined(TARGET_NR_getgid32) + case TARGET_NR_getgid32: ++#else ++ case TARGET_NR_getgid: ++#endif + ret = get_errno(getgid()); + break; + #endif +-#ifdef TARGET_NR_geteuid32 ++#if defined(TARGET_NR_geteuid32) || (defined(TARGET_NR_geteuid) && !defined(USE_UID16)) ++#if defined(TARGET_NR_geteuid32) + case TARGET_NR_geteuid32: ++#else ++ case TARGET_NR_geteuid: ++#endif + ret = get_errno(geteuid()); + break; + #endif +-#ifdef TARGET_NR_getegid32 ++#if defined(TARGET_NR_getegid32) || (defined(TARGET_NR_getegid) && !defined(USE_UID16)) ++#if defined(TARGET_NR_getegid32) + case TARGET_NR_getegid32: ++#else ++ case TARGET_NR_getegid: ++#endif + ret = get_errno(getegid()); + break; + #endif +-#ifdef TARGET_NR_setreuid32 ++#if defined(TARGET_NR_setreuid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setreuid32) + case TARGET_NR_setreuid32: ++#else ++ case TARGET_NR_setreuid: ++#endif + ret = get_errno(setreuid(arg1, arg2)); + break; + #endif +-#ifdef TARGET_NR_setregid32 ++#if defined(TARGET_NR_setregid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setregid32) + case TARGET_NR_setregid32: ++#else ++ case TARGET_NR_setregid: ++#endif + ret = get_errno(setregid(arg1, arg2)); + break; + #endif +-#ifdef TARGET_NR_getgroups32 ++#if defined(TARGET_NR_getgroups32) || !defined(USE_UID16) ++#if defined(TARGET_NR_getgroups32) + case TARGET_NR_getgroups32: ++#else ++ case TARGET_NR_getgroups: ++#endif + { + int gidsetsize = arg1; + uint32_t *target_grouplist; +@@ -6471,8 +6512,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + break; + #endif +-#ifdef TARGET_NR_setgroups32 ++#if defined(TARGET_NR_setgroups32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setgroups32) + case TARGET_NR_setgroups32: ++#else ++ case TARGET_NR_setgroups: ++#endif + { + int gidsetsize = arg1; + uint32_t *target_grouplist; +@@ -6492,18 +6537,30 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + break; + #endif +-#ifdef TARGET_NR_fchown32 ++#if defined(TARGET_NR_fchown32) || !defined(USE_UID16) ++#if defined(TARGET_NR_fchown32) + case TARGET_NR_fchown32: ++#else ++ case TARGET_NR_fchown: ++#endif + ret = get_errno(fchown(arg1, arg2, arg3)); + break; + #endif +-#ifdef TARGET_NR_setresuid32 ++#if defined(TARGET_NR_setresuid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setresuid32) + case TARGET_NR_setresuid32: ++#else ++ case TARGET_NR_setresuid: ++#endif + ret = get_errno(setresuid(arg1, arg2, arg3)); + break; + #endif +-#ifdef TARGET_NR_getresuid32 ++#if defined(TARGET_NR_getresuid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_getresuid32) + case TARGET_NR_getresuid32: ++#else ++ case TARGET_NR_getresuid: ++#endif + { + uid_t ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); +@@ -6516,13 +6573,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + break; + #endif +-#ifdef TARGET_NR_setresgid32 ++#if defined(TARGET_NR_setresgid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setresgid32) + case TARGET_NR_setresgid32: ++#else ++ case TARGET_NR_setresgid: ++#endif + ret = get_errno(setresgid(arg1, arg2, arg3)); + break; + #endif ++#if defined(TARGET_NR_getresgid32) || !defined(USE_UID16) + #ifdef TARGET_NR_getresgid32 + case TARGET_NR_getresgid32: ++#else ++ case TARGET_NR_getresgid: ++#endif + { + gid_t rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); +@@ -6535,31 +6600,51 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + } + break; + #endif +-#ifdef TARGET_NR_chown32 ++#if defined(TARGET_NR_chown32) || !defined(USE_UID16) ++#if defined(TARGET_NR_chown32) + case TARGET_NR_chown32: ++#else ++ case TARGET_NR_chown: ++#endif + if (!(p = lock_user_string(arg1))) + goto efault; + ret = get_errno(chown(p, arg2, arg3)); + unlock_user(p, arg1, 0); + break; + #endif +-#ifdef TARGET_NR_setuid32 ++#if defined(TARGET_NR_setuid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setuid32) + case TARGET_NR_setuid32: ++#else ++ case TARGET_NR_setuid: ++#endif + ret = get_errno(setuid(arg1)); + break; + #endif +-#ifdef TARGET_NR_setgid32 ++#if defined(TARGET_NR_setgid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setgid32) + case TARGET_NR_setgid32: ++#else ++ case TARGET_NR_setgid: ++#endif + ret = get_errno(setgid(arg1)); + break; + #endif +-#ifdef TARGET_NR_setfsuid32 ++#if defined(TARGET_NR_setfsuid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setfsuid32) + case TARGET_NR_setfsuid32: ++#else ++ case TARGET_NR_setfsuid: ++#endif + ret = get_errno(setfsuid(arg1)); + break; + #endif +-#ifdef TARGET_NR_setfsgid32 ++#if defined(TARGET_NR_setfsgid32) || !defined(USE_UID16) ++#if defined(TARGET_NR_setfsgid32) + case TARGET_NR_setfsgid32: ++#else ++ case TARGET_NR_setfsgid: ++#endif + ret = get_errno(setfsgid(arg1)); + break; + #endif +-- +1.6.2.1 + diff --git a/0030-linux-user-getpriority-errno-fix.patch b/0030-linux-user-getpriority-errno-fix.patch new file mode 100644 index 00000000..1e03b3ed --- /dev/null +++ b/0030-linux-user-getpriority-errno-fix.patch @@ -0,0 +1,28 @@ +From fe268c13396fd05318a88ac7987198f34c3931e3 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 17:55:41 +0200 +Subject: [PATCH 30/33] linux-user: getpriority errno fix + +getpriority returned wrong errno; fixes LTP test getpriority02. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index b1ef3c9..30fb4ab 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -5327,7 +5327,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + /* libc does special remapping of the return value of + * sys_getpriority() so it's just easiest to call + * sys_getpriority() directly rather than through libc. */ +- ret = sys_getpriority(arg1, arg2); ++ ret = get_errno(sys_getpriority(arg1, arg2)); + break; + case TARGET_NR_setpriority: + ret = get_errno(setpriority(arg1, arg2, arg3)); +-- +1.6.2.1 + diff --git a/0031-linux-user-fadvise64-implementation.patch b/0031-linux-user-fadvise64-implementation.patch new file mode 100644 index 00000000..e263548c --- /dev/null +++ b/0031-linux-user-fadvise64-implementation.patch @@ -0,0 +1,46 @@ +From 5a8884c3742e2e0cb467efc23b3b8bedaa13f65d Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 23 Jul 2009 14:56:59 +0200 +Subject: [PATCH 31/33] linux-user: fadvise64 implementation + +good enough to pass all LTP fadvise64 tests + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 17 ++++++++++++++--- + 1 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 30fb4ab..c4b7001 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -6680,12 +6680,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + arg4 = temp; + } + #endif +-#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) ++#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64) + #ifdef TARGET_NR_fadvise64_64 + case TARGET_NR_fadvise64_64: + #endif +- /* This is a hint, so ignoring and returning success is ok. */ +- ret = get_errno(0); ++#ifdef TARGET_NR_fadvise64 ++ case TARGET_NR_fadvise64: ++#endif ++#ifdef TARGET_S390X ++ switch (arg4) { ++ case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */ ++ case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */ ++ case 6: arg4 = POSIX_FADV_DONTNEED; break; ++ case 7: arg4 = POSIX_FADV_NOREUSE; break; ++ default: break; ++ } ++#endif ++ ret = -posix_fadvise(arg1, arg2, arg3, arg4); + break; + #endif + #ifdef TARGET_NR_madvise +-- +1.6.2.1 + diff --git a/0032-linux-user-zero-fstat-buffer-to-initialize-nsec-fie.patch b/0032-linux-user-zero-fstat-buffer-to-initialize-nsec-fie.patch new file mode 100644 index 00000000..0285c3ca --- /dev/null +++ b/0032-linux-user-zero-fstat-buffer-to-initialize-nsec-fie.patch @@ -0,0 +1,31 @@ +From 6d0d8876abd8e714d86e071247f33f479ebbfa9e Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Fri, 10 Jul 2009 16:43:26 +0200 +Subject: [PATCH 32/33] linux-user: zero fstat buffer to initialize nsec fields + +The fstat implementation does not initialize the nanosecond fields in the +stat buffer; this caused funny values to turn up there, preventing, for +instance, cp -p from preserving timestamps because utimensat rejected +the out-of-bounds nanosecond values. Resetting the entire structure +to zero fixes that. + +Signed-off-by: Ulrich Hecht +--- + linux-user/syscall.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index c4b7001..ef76537 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -5552,6 +5552,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + + 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); +-- +1.6.2.1 + diff --git a/0033-dup3-check-fallocate-check-fixed.patch b/0033-dup3-check-fallocate-check-fixed.patch new file mode 100644 index 00000000..390269eb --- /dev/null +++ b/0033-dup3-check-fallocate-check-fixed.patch @@ -0,0 +1,76 @@ +From b54168c6f68c8db62e6c0718b23f637f9804abee Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Thu, 30 Jul 2009 16:02:52 +0200 +Subject: [PATCH 33/33] dup3 check, fallocate check fixed + +Signed-off-by: Ulrich Hecht +--- + configure | 20 +++++++++++++++++++- + linux-user/syscall.c | 4 +++- + 2 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/configure b/configure +index 229f70b..cb4914d 100755 +--- a/configure ++++ b/configure +@@ -1370,6 +1370,21 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + fallocate=yes + fi + ++# check for dup3 ++dup3=no ++cat > $TMPC << EOF ++#include ++ ++int main(void) ++{ ++ dup3(0, 0, 0); ++ return 0; ++} ++EOF ++if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then ++ dup3=yes ++fi ++ + # Check if tools are available to build documentation. + if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then + build_docs="no" +@@ -1723,7 +1738,10 @@ if test "$splice" = "yes" ; then + echo "#define CONFIG_SPLICE 1" >> $config_host_h + fi + if test "$fallocate" = "yes" ; then +- echo "#define CONFIG_FALLOCATE 1" >> $config_host_h ++ echo "CONFIG_FALLOCATE=y" >> $config_host_mak ++fi ++if test "$dup3" = "yes" ; then ++ echo "CONFIG_DUP3=y" >> $config_host_mak + fi + if test "$inotify" = "yes" ; then + echo "#define CONFIG_INOTIFY 1" >> $config_host_h +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index ef76537..6c109de 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3707,8 +3707,10 @@ static int target_to_host_fcntl_cmd(int cmd) + return F_SETLEASE; + case TARGET_F_GETLEASE: + return F_GETLEASE; ++#ifdef F_DUPFD_CLOEXEC + case TARGET_F_DUPFD_CLOEXEC: + return F_DUPFD_CLOEXEC; ++#endif + case TARGET_F_NOTIFY: + return F_NOTIFY; + default: +@@ -4758,7 +4760,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + case TARGET_NR_dup2: + ret = get_errno(dup2(arg1, arg2)); + break; +-#ifdef TARGET_NR_dup3 ++#if defined(TARGET_NR_dup3) && defined(CONFIG_DUP3) + case TARGET_NR_dup3: + ret = get_errno(dup3(arg1, arg2, arg3)); + break; +-- +1.6.2.1 + diff --git a/qemu-0.10.1.tar.bz2 b/qemu-0.10.1.tar.bz2 deleted file mode 100644 index 8d04fb3e..00000000 --- a/qemu-0.10.1.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c987d50d321cc856b0d98fd227bb26b0764e43f49abe24ae2312dd9eda204591 -size 3068967 diff --git a/qemu-0.11.0-rc1.tar.bz2 b/qemu-0.11.0-rc1.tar.bz2 new file mode 100644 index 00000000..fe58c392 --- /dev/null +++ b/qemu-0.11.0-rc1.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2470e1c4d6eb82eabc7fe44e1a9fc8968623e06dc7050234a184cbd4bc0a1d0 +size 3291544 diff --git a/qemu-0.9.0-migration.patch b/qemu-0.9.0-migration.patch deleted file mode 100644 index c3c6f247..00000000 --- a/qemu-0.9.0-migration.patch +++ /dev/null @@ -1,1754 +0,0 @@ -2007-03-13 Gwenole Beauchesne - - * Merge Anthony Liguori's QEMU Live Migration (combined) patch + - changes from the KVM tree. - -================================================================================ ---- qemu-0.9.0/Makefile.target -+++ qemu-0.9.0/Makefile.target -@@ -320,7 +320,7 @@ - - # must use static linking to avoid leaving stuff in virtual address space - VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o --VL_OBJS+=cutils.o -+VL_OBJS+=cutils.o migration.o - VL_OBJS+=block.o block-raw.o - VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o - ifdef CONFIG_WIN32 ---- qemu-0.9.0/audio/wavaudio.c -+++ qemu-0.9.0/audio/wavaudio.c -@@ -151,7 +151,7 @@ - le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); - le_store (hdr + 32, 1 << (bits16 + stereo), 2); - -- wav->f = qemu_fopen (conf.wav_path, "wb"); -+ wav->f = qemu_fopen_file (conf.wav_path, "wb"); - if (!wav->f) { - dolog ("Failed to open wave file `%s'\nReason: %s\n", - conf.wav_path, strerror (errno)); ---- qemu-0.9.0/audio/wavcapture.c -+++ qemu-0.9.0/audio/wavcapture.c -@@ -132,7 +132,7 @@ - le_store (hdr + 28, freq << shift, 4); - le_store (hdr + 32, 1 << shift, 2); - -- wav->f = qemu_fopen (path, "wb"); -+ wav->f = qemu_fopen_file (path, "wb"); - if (!wav->f) { - term_printf ("Failed to open wave file `%s'\nReason: %s\n", - path, strerror (errno)); ---- qemu-0.9.0/cpu-all.h -+++ qemu-0.9.0/cpu-all.h -@@ -892,6 +892,7 @@ - - #define VGA_DIRTY_FLAG 0x01 - #define CODE_DIRTY_FLAG 0x02 -+#define MIGRATION_DIRTY_FLAG 0x08 - - /* read dirty bit (return 0 or 1) */ - static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) -@@ -914,6 +915,10 @@ - int dirty_flags); - void cpu_tlb_update_dirty(CPUState *env); - -+int cpu_physical_memory_set_dirty_tracking(int enable); -+ -+int cpu_physical_memory_get_dirty_tracking(void); -+ - void dump_exec_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); - ---- qemu-0.9.0/cutils.c -+++ qemu-0.9.0/cutils.c -@@ -81,3 +81,43 @@ - *ptr = p; - return 1; - } -+ -+int hex2bin(char ch) -+{ -+ if (ch >= '0' && ch <= '9') -+ return ch - '0'; -+ else if (ch >= 'A' && ch <= 'Z') -+ return 10 + ch - 'A'; -+ else if (ch >= 'a' && ch <= 'z') -+ return 10 + ch - 'a'; -+ -+ return -1; -+} -+ -+char *urldecode(const char *ptr) -+{ -+ char *ret; -+ int i; -+ -+ ret = qemu_mallocz(strlen(ptr) + 1); -+ if (ret == NULL) -+ return NULL; -+ -+ for (i = 0; *ptr; ptr++, i++) { -+ switch (*ptr) { -+ case '%': -+ if (ptr[1] == 0 || ptr[2] == 0) -+ break; -+ ret[i] = hex2bin(ptr[1]) << 4 | hex2bin(ptr[2]); -+ ptr += 2; -+ break; -+ default: -+ ret[i] = *ptr; -+ break; -+ } -+ } -+ ret[i] = 0; -+ -+ return ret; -+} -+ ---- qemu-0.9.0/exec.c -+++ qemu-0.9.0/exec.c -@@ -82,6 +82,7 @@ - int phys_ram_fd; - uint8_t *phys_ram_base; - uint8_t *phys_ram_dirty; -+static int in_migration; - - CPUState *first_cpu; - /* current CPU in the current thread. It is only valid inside -@@ -1420,6 +1421,19 @@ - #endif - } - -+int cpu_physical_memory_set_dirty_tracking(int enable) -+{ -+ int r=0; -+ -+ in_migration = enable; -+ return r; -+} -+ -+int cpu_physical_memory_get_dirty_tracking(void) -+{ -+ return in_migration; -+} -+ - static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) - { - ram_addr_t ram_addr; -@@ -2287,6 +2301,14 @@ - return tswap16(val); - } - -+#ifdef __GNUC__ -+#define likely(x) __builtin_expect(!!(x), 1) -+#define unlikely(x) __builtin_expect(!!(x), 0) -+#else -+#define likely(x) x -+#define unlikely(x) x -+#endif -+ - /* warning: addr must be aligned. The ram page is not masked as dirty - and the code inside is not invalidated. It is useful if the dirty - bits are used to track modified PTEs */ -@@ -2308,9 +2330,21 @@ - io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); - io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); - } else { -- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + -- (addr & ~TARGET_PAGE_MASK); -+ unsigned long addr1; -+ addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); -+ -+ ptr = phys_ram_base + addr1; - stl_p(ptr, val); -+ -+ if (unlikely(in_migration)) { -+ if (!cpu_physical_memory_is_dirty(addr1)) { -+ /* invalidate code */ -+ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); -+ /* set dirty bit */ -+ phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= -+ (0xff & ~CODE_DIRTY_FLAG); -+ } -+ } - } - } - ---- qemu-0.9.0/hw/usb-uhci.c -+++ qemu-0.9.0/hw/usb-uhci.c -@@ -144,6 +144,58 @@ - } - } - -+static void uhci_save(QEMUFile *f, void *opaque) -+{ -+ UHCIState *s = opaque; -+ uint8_t num_ports = NB_PORTS; -+ int i; -+ -+ pci_device_save(&s->dev, f); -+ -+ qemu_put_8s(f, &num_ports); -+ for (i = 0; i < num_ports; ++i) -+ qemu_put_be16s(f, &s->ports[i].ctrl); -+ qemu_put_be16s(f, &s->cmd); -+ qemu_put_be16s(f, &s->status); -+ qemu_put_be16s(f, &s->intr); -+ qemu_put_be16s(f, &s->frnum); -+ qemu_put_be32s(f, &s->fl_base_addr); -+ qemu_put_8s(f, &s->sof_timing); -+ qemu_put_8s(f, &s->status2); -+ qemu_put_timer(f, s->frame_timer); -+} -+ -+static int uhci_load(QEMUFile* f,void* opaque,int version_id) -+{ -+ UHCIState *s = opaque; -+ uint8_t num_ports; -+ int i, ret; -+ -+ if (version_id > 1) -+ return -EINVAL; -+ -+ ret = pci_device_load(&s->dev, f); -+ if (ret < 0) -+ return ret; -+ -+ qemu_get_8s(f, &num_ports); -+ if (num_ports != NB_PORTS) -+ return -EINVAL; -+ -+ for (i = 0; i < num_ports; ++i) -+ qemu_get_be16s(f, &s->ports[i].ctrl); -+ qemu_get_be16s(f, &s->cmd); -+ qemu_get_be16s(f, &s->status); -+ qemu_get_be16s(f, &s->intr); -+ qemu_get_be16s(f, &s->frnum); -+ qemu_get_be32s(f, &s->fl_base_addr); -+ qemu_get_8s(f, &s->sof_timing); -+ qemu_get_8s(f, &s->status2); -+ qemu_get_timer(f, s->frame_timer); -+ -+ return 0; -+} -+ - static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) - { - UHCIState *s = opaque; -@@ -793,4 +845,6 @@ - to rely on this. */ - pci_register_io_region(&s->dev, 4, 0x20, - PCI_ADDRESS_SPACE_IO, uhci_map); -+ -+ register_savevm("uhci", 0, 1, uhci_save, uhci_load, s); - } ---- qemu-0.9.0/migration.c -+++ qemu-0.9.0/migration.c -@@ -0,0 +1,753 @@ -+/* -+ * QEMU migration support -+ * -+ * Copyright (C) 2007 Anthony Liguori -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "vl.h" -+#include "qemu_socket.h" -+ -+#include -+ -+#define MIN_FINALIZE_SIZE (200 << 10) -+ -+typedef struct MigrationState -+{ -+ int fd; -+ int throttle_count; -+ int bps; -+ int updated_pages; -+ int last_updated_pages; -+ int iteration; -+ int n_buffer; -+ int throttled; -+ int *has_error; -+ char buffer[TARGET_PAGE_SIZE + 4]; -+ target_ulong addr; -+ QEMUTimer *timer; -+ void *opaque; -+ int detach; -+ int (*release)(void *opaque); -+} MigrationState; -+ -+static uint32_t max_throttle = (32 << 20); -+static MigrationState *current_migration; -+ -+//#define MIGRATION_VERIFY -+#ifdef MIGRATION_VERIFY -+static int save_verify_memory(QEMUFile *f, void *opaque); -+static int load_verify_memory(QEMUFile *f, void *opaque, int version_id); -+#endif /* MIGRATION_VERIFY */ -+ -+/* QEMUFile migration implementation */ -+ -+static void migrate_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) -+{ -+ MigrationState *s = opaque; -+ int offset = 0; -+ -+ if (*s->has_error) -+ return; -+ -+ while (offset < size) { -+ ssize_t len; -+ -+ len = write(s->fd, buf + offset, size - offset); -+ if (len == -1) { -+ if (errno == EAGAIN || errno == EINTR) -+ continue; -+ term_printf("migration: write failed (%s)\n", strerror(errno)); -+ *s->has_error = 10; -+ break; -+ } else if (len == 0) { -+ term_printf("migration: other side closed connection\n"); -+ *s->has_error = 11; -+ break; -+ } -+ -+ offset += len; -+ } -+} -+ -+static void migrate_close(void *opaque) -+{ -+ MigrationState *s = opaque; -+ -+ if (s->release && s->release(s->opaque)) -+ *s->has_error = 12; -+ -+ qemu_free(s); -+ current_migration = NULL; -+} -+ -+/* Outgoing migration routines */ -+ -+static void migrate_finish(MigrationState *s) -+{ -+ QEMUFile *f; -+ int ret = 0; -+ int *has_error = s->has_error; -+ -+ fcntl(s->fd, F_SETFL, 0); -+ -+ if (! *has_error) { -+ f = qemu_fopen(s, migrate_put_buffer, NULL, migrate_close); -+ qemu_aio_flush(); -+ vm_stop(0); -+ qemu_put_be32(f, 1); -+ ret = qemu_live_savevm_state(f); -+#ifdef MIGRATION_VERIFY -+ save_verify_memory(f, NULL); -+#endif /* MIGRATION_VERIFY */ -+ qemu_fclose(f); -+ } -+ if (ret != 0 || *has_error) { -+ term_printf("Migration failed! ret=%d error=%d\n", ret, *has_error); -+ vm_start(); -+ } -+ if (!s->detach) -+ monitor_resume(); -+ qemu_free(has_error); -+ cpu_physical_memory_set_dirty_tracking(0); -+} -+ -+static int migrate_write_buffer(MigrationState *s) -+{ -+ if (*s->has_error) -+ return 0; -+ -+ if (s->n_buffer != sizeof(s->buffer)) { -+ ssize_t len; -+ again: -+ len = write(s->fd, s->buffer + s->n_buffer, sizeof(s->buffer) - s->n_buffer); -+ if (len == -1) { -+ if (errno == EINTR) -+ goto again; -+ if (errno == EAGAIN) -+ return 1; -+ *s->has_error = 13; -+ return 0; -+ } -+ if (len == 0) { -+ *s->has_error = 14; -+ return 0; -+ } -+ -+ s->throttle_count += len; -+ s->n_buffer += len; -+ if (s->n_buffer != sizeof(s->buffer)) -+ goto again; -+ } -+ -+ if (s->throttle_count > max_throttle) { -+ s->throttled = 1; -+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int migrate_check_convergence(MigrationState *s) -+{ -+ target_ulong addr; -+ int dirty_count = 0; -+ -+ for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { -+ if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) -+ dirty_count++; -+ } -+ -+ return ((dirty_count * TARGET_PAGE_SIZE) < MIN_FINALIZE_SIZE); -+} -+ -+static void migrate_write(void *opaque) -+{ -+ MigrationState *s = opaque; -+ -+ if (migrate_write_buffer(s)) -+ return; -+ -+ if (migrate_check_convergence(s) || *s->has_error) { -+ qemu_del_timer(s->timer); -+ qemu_free_timer(s->timer); -+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -+ migrate_finish(s); -+ return; -+ } -+ -+ while (s->addr < phys_ram_size) { -+ if (cpu_physical_memory_get_dirty(s->addr, MIGRATION_DIRTY_FLAG)) { -+ uint32_t value = cpu_to_be32(s->addr); -+ -+ memcpy(s->buffer, &value, 4); -+ memcpy(s->buffer + 4, phys_ram_base + s->addr, TARGET_PAGE_SIZE); -+ s->n_buffer = 0; -+ -+ cpu_physical_memory_reset_dirty(s->addr, s->addr + TARGET_PAGE_SIZE, MIGRATION_DIRTY_FLAG); -+ -+ s->addr += TARGET_PAGE_SIZE; -+ -+ s->updated_pages++; -+ -+ if (migrate_write_buffer(s)) -+ return; -+ } else -+ s->addr += TARGET_PAGE_SIZE; -+ } -+ -+ s->last_updated_pages = s->updated_pages; -+ s->updated_pages = 0; -+ s->addr = 0; -+ s->iteration++; -+} -+ -+static void migrate_reset_throttle(void *opaque) -+{ -+ MigrationState *s = opaque; -+ -+ s->bps = s->throttle_count; -+ -+ if (s->throttled) { -+ s->throttled = 0; -+ qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_write, s); -+ } -+ s->throttle_count = 0; -+ qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000); -+} -+ -+static int start_migration(MigrationState *s) -+{ -+ uint32_t value = cpu_to_be32(phys_ram_size); -+ target_phys_addr_t addr; -+ size_t offset = 0; -+ -+ while (offset != 4) { -+ ssize_t len = write(s->fd, ((char *)&value) + offset, 4 - offset); -+ if (len == -1 && errno == EINTR) -+ continue; -+ -+ if (len < 1) -+ return -EIO; -+ -+ offset += len; -+ } -+ -+ fcntl(s->fd, F_SETFL, O_NONBLOCK); -+ -+ for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { -+ if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) -+ cpu_physical_memory_set_dirty(addr); -+ } -+ -+ if (cpu_physical_memory_set_dirty_tracking(1)) { -+ *s->has_error = 16; -+ return -1; -+ } -+ -+ s->addr = 0; -+ s->iteration = 0; -+ s->updated_pages = 0; -+ s->last_updated_pages = 0; -+ s->n_buffer = sizeof(s->buffer); -+ s->timer = qemu_new_timer(rt_clock, migrate_reset_throttle, s); -+ -+ qemu_mod_timer(s->timer, qemu_get_clock(rt_clock)); -+ qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_write, s); -+ return 0; -+} -+ -+static MigrationState *migration_init_fd(int detach, int fd) -+{ -+ MigrationState *s; -+ -+ s = qemu_mallocz(sizeof(MigrationState)); -+ if (s == NULL) { -+ term_printf("Allocation error\n"); -+ return NULL; -+ } -+ -+ s->fd = fd; -+ s->has_error = qemu_mallocz(sizeof(int)); -+ if (s->has_error == NULL) { -+ term_printf("malloc failed (for has_error)\n"); -+ return NULL; -+ } -+ s->detach = detach; -+ -+ current_migration = s; -+ -+ if (start_migration(s) == -1) { -+ term_printf("Could not start migration\n"); -+ return NULL; -+ } -+ -+ if (!detach) -+ monitor_suspend(); -+ -+ return s; -+} -+ -+typedef struct MigrationCmdState -+{ -+ int fd; -+ pid_t pid; -+} MigrationCmdState; -+ -+static int cmd_release(void *opaque) -+{ -+ MigrationCmdState *c = opaque; -+ int status, ret; -+ -+ close(c->fd); -+ -+again: -+ ret = waitpid(c->pid, &status, 0); -+ if (ret == -1 && errno == EINTR) -+ goto again; -+ -+ if (ret == -1) { -+ term_printf("migration: waitpid failed (%s)\n", strerror(errno)); -+ return -1; -+ } -+ /* FIXME: check and uncomment -+ * if (WIFEXITED(status)) -+ * status = WEXITSTATUS(status); -+ */ -+ return status; -+} -+ -+static MigrationState *migration_init_cmd(int detach, const char *command, char **argv) -+{ -+ int fds[2]; -+ pid_t pid; -+ int i; -+ MigrationState *s; -+ -+ if (pipe(fds) == -1) { -+ term_printf("pipe() (%s)\n", strerror(errno)); -+ return NULL; -+ } -+ -+ pid = fork(); -+ if (pid == -1) { -+ close(fds[0]); -+ close(fds[1]); -+ term_printf("fork error (%s)\n", strerror(errno)); -+ return NULL; -+ } -+ if (pid == 0) { -+ close(fds[1]); -+ dup2(fds[0], STDIN_FILENO); -+ execvp(command, argv); -+ exit(1); -+ } else -+ close(fds[0]); -+ -+ for (i = 0; argv[i]; i++) -+ qemu_free(argv[i]); -+ qemu_free(argv); -+ -+ s = migration_init_fd(detach, fds[1]); -+ if (s) { -+ MigrationCmdState *c = qemu_mallocz(sizeof(*c)); -+ c->pid = pid; -+ c->fd = fds[1]; -+ s->release = cmd_release; -+ s->opaque = c; -+ } -+ -+ return s; -+} -+ -+static MigrationState *migration_init_exec(int detach, const char *command) -+{ -+ char **argv = NULL; -+ -+ argv = qemu_mallocz(sizeof(char *) * 4); -+ argv[0] = strdup("sh"); -+ argv[1] = strdup("-c"); -+ argv[2] = strdup(command); -+ argv[3] = NULL; -+ -+ return migration_init_cmd(detach, "/bin/sh", argv); -+} -+ -+static MigrationState *migration_init_ssh(int detach, const char *host) -+{ -+ int qemu_argc, daemonize = 0, argc, i; -+ char **qemu_argv, **argv; -+ const char *incoming = NULL; -+ -+ qemu_get_launch_info(&qemu_argc, &qemu_argv, &daemonize, &incoming); -+ -+ argc = 3 + qemu_argc; -+ if (!daemonize) -+ argc++; -+ if (!incoming) -+ argc+=2; -+ -+ argv = qemu_mallocz(sizeof(char *) * (argc + 1)); -+ argv[0] = strdup("ssh"); -+ argv[1] = strdup("-XC"); -+ argv[2] = strdup(host); -+ -+ for (i = 0; i < qemu_argc; i++) -+ argv[3 + i] = strdup(qemu_argv[i]); -+ -+ if (!daemonize) -+ argv[3 + i++] = strdup("-daemonize"); -+ if (!incoming) { -+ argv[3 + i++] = strdup("-incoming"); -+ argv[3 + i++] = strdup("stdio"); -+ } -+ -+ argv[3 + i] = NULL; -+ -+ return migration_init_cmd(detach, "ssh", argv); -+} -+ -+static int tcp_release(void *opaque) -+{ -+ MigrationState *s = opaque; -+ uint8_t status = 0; -+ ssize_t len; -+ -+again: -+ len = read(s->fd, &status, 1); -+ if (len == -1 && errno == EINTR) -+ goto again; -+ -+ close(s->fd); -+ -+ return (len != 1 || status != 0); -+} -+ -+static MigrationState *migration_init_tcp(int detach, const char *host) -+{ -+ int fd; -+ struct sockaddr_in addr; -+ MigrationState *s; -+ -+ fd = socket(PF_INET, SOCK_STREAM, 0); -+ if (fd == -1) { -+ term_printf("socket() failed %s\n", strerror(errno)); -+ return NULL; -+ } -+ -+ addr.sin_family = AF_INET; -+ if (parse_host_port(&addr, host) == -1) { -+ term_printf("parse_host_port() FAILED for %s\n", host); -+ close(fd); -+ return NULL; -+ } -+ -+again: -+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { -+ if (errno == EINTR) -+ goto again; -+ term_printf("connect() failed %s\n", strerror(errno)); -+ close(fd); -+ return NULL; -+ } -+ -+ s = migration_init_fd(detach, fd); -+ if (s) { -+ s->opaque = s; -+ s->release = tcp_release; -+ } -+ return s; -+} -+ -+/* Incoming migration */ -+ -+static int migrate_incoming_fd(int fd) -+{ -+ int ret; -+ QEMUFile *f = qemu_fopen_fd(fd); -+ uint32_t addr; -+ extern void qemu_announce_self(void); -+ -+ if (qemu_get_be32(f) != phys_ram_size) -+ return 101; -+ -+ do { -+ int l; -+ addr = qemu_get_be32(f); -+ if (addr == 1) -+ break; -+ l = qemu_get_buffer(f, phys_ram_base + addr, TARGET_PAGE_SIZE); -+ if (l != TARGET_PAGE_SIZE) -+ return 102; -+ } while (1); -+ -+ -+ qemu_aio_flush(); -+ vm_stop(0); -+ ret = qemu_live_loadvm_state(f); -+#ifdef MIGRATION_VERIFY -+ if (ret==0) ret=load_verify_memory(f, NULL, 1); -+#endif /* MIGRATION_VERIFY */ -+ qemu_fclose(f); -+ -+ return ret; -+} -+ -+static int migrate_incoming_tcp(const char *host) -+{ -+ struct sockaddr_in addr; -+ socklen_t addrlen = sizeof(addr); -+ int fd, sfd; -+ ssize_t len; -+ uint8_t status = 0; -+ int reuse = 1; -+ int rc; -+ -+ addr.sin_family = AF_INET; -+ if (parse_host_port(&addr, host) == -1) { -+ fprintf(stderr, "parse_host_port() failed for %s\n", host); -+ rc = 201; -+ goto error; -+ } -+ -+ fd = socket(PF_INET, SOCK_STREAM, 0); -+ if (fd == -1) { -+ perror("socket failed"); -+ rc = 202; -+ goto error; -+ } -+ -+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { -+ perror("setsockopt() failed"); -+ rc = 203; -+ goto error_socket; -+ } -+ -+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { -+ perror("bind() failed"); -+ rc = 204; -+ goto error_socket; -+ } -+ -+ if (listen(fd, 1) == -1) { -+ perror("listen() failed"); -+ rc = 205; -+ goto error_socket; -+ } -+ -+again: -+ sfd = accept(fd, (struct sockaddr *)&addr, &addrlen); -+ if (sfd == -1) { -+ if (errno == EINTR) -+ goto again; -+ perror("accept() failed"); -+ rc = 206; -+ goto error_socket; -+ } -+ -+ rc = migrate_incoming_fd(sfd); -+ if (rc != 0) { -+ rc = 207; -+ fprintf(stderr, "migrate_incoming_fd failed (rc=%d)\n", rc); -+ goto error_accept; -+ } -+ -+again1: -+ len = write(sfd, &status, 1); -+ if (len == -1 && errno == EAGAIN) -+ goto again1; -+ if (len != 1) { -+ rc = 208; -+ goto error_accept; -+ -+ } -+ -+error_accept: -+ close(sfd); -+error_socket: -+ close(fd); -+error: -+ return rc; -+} -+ -+int migrate_incoming(const char *device) -+{ -+ const char *ptr; -+ int ret = 0; -+ -+ if (strcmp(device, "stdio") == 0) -+ ret = migrate_incoming_fd(STDIN_FILENO); -+ else if (strstart(device, "tcp://", &ptr)) { -+ char *host, *end; -+ host = strdup(ptr); -+ end = strchr(host, '/'); -+ if (end) *end = 0; -+ ret = migrate_incoming_tcp(host); -+ qemu_free(host); -+ } else { -+ errno = EINVAL; -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+/* Migration monitor command */ -+ -+/* TODO: -+ 1) audit all error paths -+*/ -+ -+void do_migrate(int detach, const char *uri) -+{ -+ const char *ptr; -+ -+ if (strstart(uri, "exec:", &ptr)) { -+ char *command = urldecode(ptr); -+ migration_init_exec(detach, command); -+ free(command); -+ } else if (strstart(uri, "ssh://", &ptr)) { -+ char *host, *end; -+ -+ host = strdup(ptr); -+ end = strchr(host, '/'); -+ if (end) *end = 0; -+ migration_init_ssh(detach, host); -+ qemu_free(host); -+ } else if (strstart(uri, "tcp://", &ptr)) { -+ char *host, *end; -+ -+ host = strdup(ptr); -+ end = strchr(host, '/'); -+ if (end) *end = 0; -+ -+ if (migration_init_tcp(detach, host) == NULL) -+ term_printf("migration failed (migration_init_tcp for %s failed)\n", host); -+ free(host); -+ } else { -+ term_printf("Unknown migration protocol '%s'\n", uri); -+ return; -+ } -+} -+ -+void do_migrate_set_speed(const char *value) -+{ -+ double d; -+ char *ptr; -+ -+ d = strtod(value, &ptr); -+ switch (*ptr) { -+ case 'G': case 'g': -+ d *= 1024; -+ case 'M': case 'm': -+ d *= 1024; -+ case 'K': case 'k': -+ d *= 1024; -+ default: -+ break; -+ } -+ -+ max_throttle = (uint32_t)d; -+} -+ -+void do_info_migration(void) -+{ -+ MigrationState *s = current_migration; -+ -+ if (s) { -+ term_printf("Migration active\n"); -+ if (s->bps < (1 << 20)) -+ term_printf("Transfer rate %3.1f kb/s\n", -+ (double)s->bps / 1024); -+ else -+ term_printf("Transfer rate %3.1f mb/s\n", -+ (double)s->bps / (1024 * 1024)); -+ term_printf("Iteration %d\n", s->iteration); -+ term_printf("Transferred %d/%d pages\n", s->updated_pages, phys_ram_size >> TARGET_PAGE_BITS); -+ if (s->iteration) -+ term_printf("Last iteration found %d dirty pages\n", s->last_updated_pages); -+ } else -+ term_printf("Migration inactive\n"); -+ -+ term_printf("Maximum migration speed is "); -+ if (max_throttle < (1 << 20)) -+ term_printf("%3.1f kb/s\n", (double)max_throttle / 1024); -+ else -+ term_printf("%3.1f mb/s\n", (double)max_throttle / (1024 * 1024)); -+} -+ -+void do_migrate_cancel(void) -+{ -+ MigrationState *s = current_migration; -+ -+ if (s) -+ *s->has_error = 20; -+} -+ -+ -+ -+#ifdef MIGRATION_VERIFY -+unsigned int calc_page_checksum(target_ulong addr) -+{ -+ unsigned int sum=0; -+ unsigned int *p = (unsigned int *)(phys_ram_base + addr); -+ unsigned int *q = p + (TARGET_PAGE_SIZE / sizeof(unsigned int)); -+ -+ for ( /*initialized already */ ; pfirst_client; vc != NULL; vc = vc->next) { -+ for (j=0; j < SELF_ANNOUNCE_ROUNDS; j++) -+ vc->fd_read(vc->opaque, buf, len); -+ } -+ } -+} -+ - /***********************************************************/ - /* savevm/loadvm support */ - - #define IO_BUF_SIZE 32768 - - struct QEMUFile { -- FILE *outfile; -- BlockDriverState *bs; -- int is_file; -- int is_writable; -- int64_t base_offset; -+ QEMUFilePutBufferFunc *put_buffer; -+ QEMUFileGetBufferFunc *get_buffer; -+ QEMUFileCloseFunc *close; -+ void *opaque; -+ - int64_t buf_offset; /* start of buffer when writing, end of buffer - when reading */ - int buf_index; -@@ -4299,58 +4337,143 @@ - uint8_t buf[IO_BUF_SIZE]; - }; - --QEMUFile *qemu_fopen(const char *filename, const char *mode) -+typedef struct QEMUFileFD - { -- QEMUFile *f; -+ int fd; -+} QEMUFileFD; - -- f = qemu_mallocz(sizeof(QEMUFile)); -- if (!f) -- return NULL; -- if (!strcmp(mode, "wb")) { -- f->is_writable = 1; -- } else if (!strcmp(mode, "rb")) { -- f->is_writable = 0; -- } else { -- goto fail; -+static int fd_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) -+{ -+ QEMUFileFD *s = opaque; -+ int offset = 0; -+ ssize_t len; -+ -+again: -+ len = read(s->fd, buf + offset, size - offset); -+ if (len == -1) { -+ if (errno == EINTR || errno == EAGAIN) -+ goto again; - } -- f->outfile = fopen(filename, mode); -- if (!f->outfile) -+ -+ return len; -+} -+ -+QEMUFile *qemu_fopen_fd(int fd) -+{ -+ QEMUFileFD *s = qemu_mallocz(sizeof(QEMUFileFD)); -+ s->fd = fd; -+ return qemu_fopen(s, NULL, fd_get_buffer, qemu_free); -+} -+ -+typedef struct QEMUFileUnix -+{ -+ FILE *outfile; -+} QEMUFileUnix; -+ -+static void file_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) -+{ -+ QEMUFileUnix *s = opaque; -+ fseek(s->outfile, pos, SEEK_SET); -+ fwrite(buf, 1, size, s->outfile); -+} -+ -+static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) -+{ -+ QEMUFileUnix *s = opaque; -+ fseek(s->outfile, pos, SEEK_SET); -+ return fread(buf, 1, size, s->outfile); -+} -+ -+static void file_close(void *opaque) -+{ -+ QEMUFileUnix *s = opaque; -+ fclose(s->outfile); -+ qemu_free(s); -+} -+ -+QEMUFile *qemu_fopen_file(const char *filename, const char *mode) -+{ -+ QEMUFileUnix *s; -+ -+ s = qemu_mallocz(sizeof(QEMUFileUnix)); -+ if (!s) -+ return NULL; -+ -+ s->outfile = fopen(filename, mode); -+ if (!s->outfile) - goto fail; -- f->is_file = 1; -- return f; -- fail: -- if (f->outfile) -- fclose(f->outfile); -- qemu_free(f); -+ -+ if (!strcmp(mode, "wb")) -+ return qemu_fopen(s, file_put_buffer, NULL, file_close); -+ else if (!strcmp(mode, "rb")) -+ return qemu_fopen(s, NULL, file_get_buffer, file_close); -+ -+fail: -+ if (s->outfile) -+ fclose(s->outfile); -+ qemu_free(s); - return NULL; - } - -+typedef struct QEMUFileBdrv -+{ -+ BlockDriverState *bs; -+ int64_t base_offset; -+} QEMUFileBdrv; -+ -+static void bdrv_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) -+{ -+ QEMUFileBdrv *s = opaque; -+ bdrv_pwrite(s->bs, s->base_offset + pos, buf, size); -+} -+ -+static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) -+{ -+ QEMUFileBdrv *s = opaque; -+ return bdrv_pread(s->bs, s->base_offset + pos, buf, size); -+} -+ - QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) - { -+ QEMUFileBdrv *s; -+ -+ s = qemu_mallocz(sizeof(QEMUFileBdrv)); -+ if (!s) -+ return NULL; -+ -+ s->bs = bs; -+ s->base_offset = offset; -+ -+ if (is_writable) -+ return qemu_fopen(s, bdrv_put_buffer, NULL, qemu_free); -+ -+ return qemu_fopen(s, NULL, bdrv_get_buffer, qemu_free); -+} -+ -+QEMUFile *qemu_fopen(void *opaque, QEMUFilePutBufferFunc *put_buffer, -+ QEMUFileGetBufferFunc *get_buffer, QEMUFileCloseFunc *close) -+{ - QEMUFile *f; - - f = qemu_mallocz(sizeof(QEMUFile)); - if (!f) -- return NULL; -- f->is_file = 0; -- f->bs = bs; -- f->is_writable = is_writable; -- f->base_offset = offset; -+ return NULL; -+ -+ f->opaque = opaque; -+ f->put_buffer = put_buffer; -+ f->get_buffer = get_buffer; -+ f->close = close; -+ - return f; - } - - void qemu_fflush(QEMUFile *f) - { -- if (!f->is_writable) -+ if (!f->put_buffer) - return; -+ - if (f->buf_index > 0) { -- if (f->is_file) { -- fseek(f->outfile, f->buf_offset, SEEK_SET); -- fwrite(f->buf, 1, f->buf_index, f->outfile); -- } else { -- bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, -- f->buf, f->buf_index); -- } -+ f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); - f->buf_offset += f->buf_index; - f->buf_index = 0; - } -@@ -4360,19 +4483,13 @@ - { - int len; - -- if (f->is_writable) -+ if (!f->get_buffer) - return; -- if (f->is_file) { -- fseek(f->outfile, f->buf_offset, SEEK_SET); -- len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile); -- if (len < 0) -- len = 0; -- } else { -- len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, -- f->buf, IO_BUF_SIZE); -- if (len < 0) -- len = 0; -- } -+ -+ len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); -+ if (len < 0) -+ len = 0; -+ - f->buf_index = 0; - f->buf_size = len; - f->buf_offset += len; -@@ -4380,11 +4497,9 @@ - - void qemu_fclose(QEMUFile *f) - { -- if (f->is_writable) -- qemu_fflush(f); -- if (f->is_file) { -- fclose(f->outfile); -- } -+ qemu_fflush(f); -+ if (f->close) -+ f->close(f->opaque); - qemu_free(f); - } - -@@ -4459,7 +4574,7 @@ - /* SEEK_END not supported */ - return -1; - } -- if (f->is_writable) { -+ if (f->put_buffer) { - qemu_fflush(f); - f->buf_offset = pos; - } else { -@@ -4659,8 +4774,78 @@ - } - /* always seek to exact end of record */ - qemu_fseek(f, cur_pos + record_len, SEEK_SET); -+ } -+ ret = 0; -+ the_end: -+ return ret; -+} -+ -+int qemu_live_savevm_state(QEMUFile *f) -+{ -+ SaveStateEntry *se; -+ int len, ret; -+ -+ qemu_put_be32(f, QEMU_VM_FILE_MAGIC); -+ qemu_put_be32(f, QEMU_VM_FILE_VERSION); -+ -+ for(se = first_se; se != NULL; se = se->next) { -+ len = strlen(se->idstr); -+ -+ qemu_put_byte(f, len); -+ qemu_put_buffer(f, se->idstr, len); -+ qemu_put_be32(f, se->instance_id); -+ qemu_put_be32(f, se->version_id); -+ -+ se->save_state(f, se->opaque); -+ } -+ -+ qemu_put_byte(f, 0); -+ -+ ret = 0; -+ return ret; -+} -+ -+int qemu_live_loadvm_state(QEMUFile *f) -+{ -+ SaveStateEntry *se; -+ int len, ret, instance_id, version_id; -+ unsigned int v; -+ char idstr[256]; -+ -+ v = qemu_get_be32(f); -+ if (v != QEMU_VM_FILE_MAGIC) -+ goto fail; -+ v = qemu_get_be32(f); -+ if (v != QEMU_VM_FILE_VERSION) { -+ fail: -+ ret = -1; -+ goto the_end; -+ } -+ -+ for(;;) { -+ len = qemu_get_byte(f); -+ if (len == 0) -+ break; -+ qemu_get_buffer(f, idstr, len); -+ idstr[len] = '\0'; -+ instance_id = qemu_get_be32(f); -+ version_id = qemu_get_be32(f); -+ se = find_se(idstr, instance_id); -+ if (!se) { -+ fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", -+ instance_id, idstr); -+ } else { -+ ret = se->load_state(f, se->opaque, version_id); -+ if (ret < 0) { -+ fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", -+ instance_id, idstr); -+ } -+ } - } - ret = 0; -+ -+ qemu_announce_self(); -+ - the_end: - return ret; - } -@@ -4980,7 +5165,12 @@ - uint16_t fptag, fpus, fpuc, fpregs_format; - uint32_t hflags; - int i; -- -+ -+#ifdef USE_KVM -+ if (kvm_allowed) -+ kvm_save_registers(env); -+#endif -+ - for(i = 0; i < CPU_NB_REGS; i++) - qemu_put_betls(f, &env->regs[i]); - qemu_put_betls(f, &env->eip); -@@ -5065,6 +5255,16 @@ - qemu_put_be64s(f, &env->kernelgsbase); - #endif - qemu_put_be32s(f, &env->smbase); -+ -+#ifdef USE_KVM -+ if (kvm_allowed) { -+ for (i = 0; i < NR_IRQ_WORDS ; i++) { -+ qemu_put_betls(f, &env->kvm_interrupt_bitmap[i]); -+ } -+ qemu_put_be64s(f, &env->tsc); -+ } -+#endif -+ - } - - #ifdef USE_X86LDOUBLE -@@ -5484,7 +5684,20 @@ - inflateEnd(&s->zstream); - } - --static void ram_save(QEMUFile *f, void *opaque) -+static void ram_save_live(QEMUFile *f, void *opaque) -+{ -+ target_ulong addr; -+ -+ for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { -+ if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) { -+ qemu_put_be32(f, addr); -+ qemu_put_buffer(f, phys_ram_base + addr, TARGET_PAGE_SIZE); -+ } -+ } -+ qemu_put_be32(f, 1); -+} -+ -+static void ram_save_static(QEMUFile *f, void *opaque) - { - int i; - RamCompressState s1, *s = &s1; -@@ -5528,16 +5741,39 @@ - ram_compress_close(s); - } - --static int ram_load(QEMUFile *f, void *opaque, int version_id) -+static void ram_save(QEMUFile *f, void *opaque) -+{ -+ int in_migration = cpu_physical_memory_get_dirty_tracking(); -+ -+ qemu_put_byte(f, in_migration); -+ -+ if (in_migration) -+ ram_save_live(f, opaque); -+ else -+ ram_save_static(f, opaque); -+} -+ -+static int ram_load_live(QEMUFile *f, void *opaque) -+{ -+ target_ulong addr; -+ -+ do { -+ addr = qemu_get_be32(f); -+ if (addr == 1) -+ break; -+ -+ qemu_get_buffer(f, phys_ram_base + addr, TARGET_PAGE_SIZE); -+ } while (1); -+ -+ return 0; -+} -+ -+static int ram_load_static(QEMUFile *f, void *opaque) - { - RamDecompressState s1, *s = &s1; - uint8_t buf[10]; - int i; - -- if (version_id == 1) -- return ram_load_v1(f, opaque); -- if (version_id != 2) -- return -EINVAL; - if (qemu_get_be32(f) != phys_ram_size) - return -EINVAL; - if (ram_decompress_open(s, f) < 0) -@@ -5583,6 +5819,30 @@ - return 0; - } - -+static int ram_load(QEMUFile *f, void *opaque, int version_id) -+{ -+ int ret; -+ -+ switch (version_id) { -+ case 1: -+ ret = ram_load_v1(f, opaque); -+ break; -+ case 3: -+ if (qemu_get_byte(f)) { -+ ret = ram_load_live(f, opaque); -+ break; -+ } -+ case 2: -+ ret = ram_load_static(f, opaque); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ - /***********************************************************/ - /* bottom halves (can be seen as timers which expire ASAP) */ - -@@ -6205,7 +6465,8 @@ - QEMU_OPTION_no_reboot, - QEMU_OPTION_daemonize, - QEMU_OPTION_option_rom, -- QEMU_OPTION_semihosting -+ QEMU_OPTION_semihosting, -+ QEMU_OPTION_incoming, - }; - - typedef struct QEMUOption { -@@ -6272,6 +6533,7 @@ - { "serial", 1, QEMU_OPTION_serial }, - { "parallel", 1, QEMU_OPTION_parallel }, - { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, -+ { "incoming", 1, QEMU_OPTION_incoming }, - { "full-screen", 0, QEMU_OPTION_full_screen }, - #ifdef CONFIG_SDL - { "no-quit", 0, QEMU_OPTION_no_quit }, -@@ -6496,6 +6758,17 @@ - - #define MAX_NET_CLIENTS 32 - -+static int saved_argc; -+static char **saved_argv; -+ -+void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const char **opt_incoming) -+{ -+ *argc = saved_argc; -+ *argv = saved_argv; -+ *opt_daemonize = daemonize; -+ *opt_incoming = incoming; -+} -+ - int main(int argc, char **argv) - { - #ifdef CONFIG_GDBSTUB -@@ -6524,6 +6797,9 @@ - int usb_devices_index; - int fds[2]; - -+ saved_argc = argc; -+ saved_argv = argv; -+ - LIST_INIT (&vm_change_state_head); - #ifndef _WIN32 - { -@@ -6890,6 +7166,9 @@ - case QEMU_OPTION_loadvm: - loadvm = optarg; - break; -+ case QEMU_OPTION_incoming: -+ incoming = optarg; -+ break; - case QEMU_OPTION_full_screen: - full_screen = 1; - break; -@@ -6963,11 +7242,6 @@ - } - - #ifndef _WIN32 -- if (daemonize && !nographic && vnc_display == NULL) { -- fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n"); -- daemonize = 0; -- } -- - if (daemonize) { - pid_t pid; - -@@ -7002,7 +7276,6 @@ - exit(1); - - umask(027); -- chdir("/"); - - signal(SIGTSTP, SIG_IGN); - signal(SIGTTOU, SIG_IGN); -@@ -7146,7 +7419,7 @@ - } - - register_savevm("timer", 0, 2, timer_save, timer_load, NULL); -- register_savevm("ram", 0, 2, ram_save, ram_load, NULL); -+ register_savevm("ram", 0, 3, ram_save, ram_load, NULL); - - init_ioports(); - -@@ -7228,8 +7501,19 @@ - } - } else - #endif -- if (loadvm) -- do_loadvm(loadvm); -+ if (loadvm) { -+ do_loadvm(loadvm); -+ } -+ -+ if (incoming) { -+ int rc; -+ -+ rc = migrate_incoming(incoming); -+ if (rc != 0) { -+ fprintf(stderr, "Migration failed rc=%d\n", rc); -+ exit(rc); -+ } -+ } - - { - /* XXX: simplify init */ -@@ -7252,6 +7536,7 @@ - if (len != 1) - exit(1); - -+ chdir("/"); - fd = open("/dev/null", O_RDWR); - if (fd == -1) - exit(1); ---- qemu-0.9.0/vl.h -+++ qemu-0.9.0/vl.h -@@ -105,8 +105,12 @@ - char *pstrcat(char *buf, int buf_size, const char *s); - int strstart(const char *str, const char *val, const char **ptr); - int stristart(const char *str, const char *val, const char **ptr); -+int hex2bin(char ch); -+char *urldecode(const char *ptr); - - /* vl.c */ -+void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const char **opt_incoming); -+ - uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); - - void hw_error(const char *fmt, ...); -@@ -434,7 +438,14 @@ - - typedef struct QEMUFile QEMUFile; - --QEMUFile *qemu_fopen(const char *filename, const char *mode); -+typedef void (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, int64_t pos, int size); -+typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, int64_t pos, int size); -+typedef void (QEMUFileCloseFunc)(void *opaque); -+ -+QEMUFile *qemu_fopen(void *opaque, QEMUFilePutBufferFunc *put_buffer, -+ QEMUFileGetBufferFunc *get_buffer, QEMUFileCloseFunc *close); -+QEMUFile *qemu_fopen_file(const char *filename, const char *mode); -+QEMUFile *qemu_fopen_fd(int fd); - void qemu_fflush(QEMUFile *f); - void qemu_fclose(QEMUFile *f); - void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); -@@ -523,6 +534,9 @@ - void do_delvm(const char *name); - void do_info_snapshots(void); - -+int qemu_live_savevm_state(QEMUFile *f); -+int qemu_live_loadvm_state(QEMUFile *f); -+ - /* bottom halves */ - typedef void QEMUBHFunc(void *opaque); - -@@ -1373,6 +1387,13 @@ - - #endif /* defined(QEMU_TOOL) */ - -+/* migration.c */ -+void do_info_migration(void); -+void do_migrate(int detach, const char *uri); -+void do_migrate_cancel(void); -+void do_migrate_set_speed(const char *value); -+int migrate_incoming(const char *device); -+ - /* monitor.c */ - void monitor_init(CharDriverState *hd, int show_banner); - void term_puts(const char *str); -@@ -1383,6 +1404,8 @@ - void term_print_help(void); - void monitor_readline(const char *prompt, int is_password, - char *buf, int buf_size); -+void monitor_suspend(void); -+void monitor_resume(void); - - /* readline.c */ - typedef void ReadLineFunc(void *opaque, const char *str); diff --git a/qemu-cvs-flash.patch b/qemu-cvs-flash.patch deleted file mode 100644 index d468ab88..00000000 --- a/qemu-cvs-flash.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu/linux-user/syscall.c -+++ qemu/linux-user/syscall.c -@@ -1867,6 +1867,8 @@ - - switch (call) { - case IPCOP_semop: -+ ret = -EINVAL; -+ break; - { - struct sembuf *target_sops; - int i; diff --git a/qemu-cvs-gettimeofday.patch b/qemu-cvs-gettimeofday.patch deleted file mode 100644 index df6db7c5..00000000 --- a/qemu-cvs-gettimeofday.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu/linux-user/syscall.c -+++ qemu/linux-user/syscall.c -@@ -3895,6 +3895,8 @@ - case TARGET_NR_gettimeofday: - { - struct timeval tv; -+ if(copy_from_user_timeval(&tv, arg1)) -+ goto efault; - ret = get_errno(gettimeofday(&tv, NULL)); - if (!is_error(ret)) { - host_to_target_timeval(arg1, &tv); diff --git a/qemu-cvs-ioctl_debug.patch b/qemu-cvs-ioctl_debug.patch deleted file mode 100644 index cbb5a5dc..00000000 --- a/qemu-cvs-ioctl_debug.patch +++ /dev/null @@ -1,18 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu/linux-user/syscall.c -+++ qemu/linux-user/syscall.c -@@ -2087,7 +2087,12 @@ - ie = ioctl_entries; - for(;;) { - if (ie->target_cmd == 0) { -- gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); -+ int i; -+ gemu_log("Unsupported ioctl: cmd=0x%04lx (%x)\n", cmd, (cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); -+ for(i=0;ioctl_entries[i].target_cmd;i++) { -+ if((ioctl_entries[i].target_cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) == (cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT))) -+ gemu_log("%p\t->\t%s (%x)\n", ioctl_entries[i].host_cmd, ioctl_entries[i].name, (ioctl_entries[i].target_cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT); -+ } - return -TARGET_ENOSYS; - } - if (ie->target_cmd == cmd) diff --git a/qemu-cvs-ioctl_nodirection.patch b/qemu-cvs-ioctl_nodirection.patch deleted file mode 100644 index cd523000..00000000 --- a/qemu-cvs-ioctl_nodirection.patch +++ /dev/null @@ -1,24 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu/linux-user/syscall.c -+++ qemu/linux-user/syscall.c -@@ -2117,6 +2117,11 @@ - arg_type++; - target_size = thunk_type_size(arg_type, 0); - switch(ie->access) { -+ /* FIXME: actually the direction given in the ioctl should be -+ * correct so we can assume the communication is uni-directional. -+ * The alsa developers did not like this concept though and -+ * declared ioctls IOC_R and IOC_W even though they were IOC_RW.*/ -+/* - case IOC_R: - ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); - if (!is_error(ret)) { -@@ -2131,6 +2136,7 @@ - unlock_user(argptr, arg, 0); - ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); - break; -+*/ - default: - case IOC_RW: - argptr = lock_user(arg, target_size, 1); diff --git a/qemu-cvs-ipc.patch b/qemu-cvs-ipc.patch deleted file mode 100644 index 300ef215..00000000 --- a/qemu-cvs-ipc.patch +++ /dev/null @@ -1,364 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu-0.10.1/linux-user/syscall.c -+++ qemu-0.10.1/linux-user/syscall.c -@@ -29,7 +29,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -46,6 +46,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include - #include -@@ -158,6 +161,7 @@ - - #define __NR_sys_exit __NR_exit - #define __NR_sys_sched_getaffinity __NR_sched_getaffinity -+#define __NR_sys_ipc __NR_ipc - #define __NR_sys_uname __NR_uname - #define __NR_sys_faccessat __NR_faccessat - #define __NR_sys_fchmodat __NR_fchmodat -@@ -266,6 +270,10 @@ - #if defined(TARGET_NR_tkill) && defined(__NR_tkill) - _syscall2(int,sys_tkill,int,tid,int,sig) - #endif -+#ifdef __NR_ipc -+_syscall6(int,sys_ipc, long, call, long, first, long, second, long, third, void *, ptr, long, fifth) -+#define semctl(a,b,c,d) sys_ipc(IPCOP_semctl,a,b,c,&d,0l) -+#endif - #ifdef __NR_sys_sched_getaffinity - _syscall3(int,sys_sched_getaffinity,pid_t,pid,unsigned int,cpusetsize,void*,mask) - #endif -@@ -1687,6 +1695,18 @@ - abi_ulong __unused4; - }; - -+struct target_semid64_ds -+{ -+ struct target_ipc64_perm sem_perm; -+ target_ulong sem_otime; -+ target_ulong __unused1; -+ target_ulong sem_ctime; -+ target_ulong __unused2; -+ target_ulong sem_nsems; -+ target_ulong __unused3; -+ target_ulong __unused4; -+}; -+ - static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, - abi_ulong target_addr) - { -@@ -1725,6 +1745,43 @@ - return 0; - } - -+static inline abi_long target_to_host_ipc64_perm( struct ipc64_perm *host_ip, target_ulong target_addr ) -+{ -+ struct target_ipc64_perm *target_ip; -+ struct target_semid64_ds *target_sd; -+ -+ lock_user_struct(VERIFY_READ, target_sd, target_addr, 1); -+ target_ip=&(target_sd->sem_perm); -+ host_ip->key = tswapl(target_ip->key); -+ host_ip->uid = tswapl(target_ip->uid); -+ host_ip->gid = tswapl(target_ip->gid); -+ host_ip->cuid = tswapl(target_ip->cuid); -+ host_ip->cgid = tswapl(target_ip->cgid); -+ host_ip->mode = tswap16(target_ip->mode); -+ host_ip->seq = tswap16(target_ip->seq); -+ unlock_user_struct(target_sd, target_addr, 1); -+ return 0; -+} -+ -+static inline abi_long host_to_target_ipc64_perm(target_ulong target_addr, -+ struct ipc64_perm *host_ip) -+{ -+ struct target_ipc64_perm *target_ip; -+ struct target_semid64_ds *target_sd; -+ -+ lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0); -+ target_ip = &(target_sd->sem_perm); -+ target_ip->key = tswapl(host_ip->key); -+ target_ip->uid = tswapl(host_ip->uid); -+ target_ip->gid = tswapl(host_ip->gid); -+ target_ip->cuid = tswapl(host_ip->cuid); -+ target_ip->cgid = tswapl(host_ip->cgid); -+ target_ip->mode = tswap16(host_ip->mode); -+ target_ip->seq = tswap16(host_ip->seq); -+ unlock_user_struct(target_sd, target_addr, 1); -+ return 0; -+} -+ - static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, - abi_ulong target_addr) - { -@@ -1755,6 +1812,32 @@ - return 0; - } - -+static inline void target_to_host_semid64_ds(struct semid64_ds *host_sd, -+ target_ulong target_addr) -+{ -+ struct target_semid64_ds *target_sd; -+ -+ lock_user_struct(VERIFY_READ, target_sd, target_addr, 1); -+ target_to_host_ipc64_perm(&(host_sd->sem_perm),target_addr); -+ host_sd->sem_nsems = tswapl(target_sd->sem_nsems); -+ host_sd->sem_otime = tswapl(target_sd->sem_otime); -+ host_sd->sem_ctime = tswapl(target_sd->sem_ctime); -+ unlock_user_struct(target_sd, target_addr, 0); -+} -+ -+static inline void host_to_target_semid64_ds(target_ulong target_addr, -+ struct semid64_ds *host_sd) -+{ -+ struct target_semid64_ds *target_sd; -+ -+ lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0); -+ host_to_target_ipc64_perm(target_addr,&(host_sd->sem_perm)); -+ target_sd->sem_nsems = tswapl(host_sd->sem_nsems); -+ target_sd->sem_otime = tswapl(host_sd->sem_otime); -+ target_sd->sem_ctime = tswapl(host_sd->sem_ctime); -+ unlock_user_struct(target_sd, target_addr, 1); -+} -+ - union semun { - int val; - struct semid_ds *buf; -@@ -1767,6 +1850,10 @@ - unsigned short int *array; - }; - -+#ifndef IPC_64 -+#define IPC_64 0x100 -+#endif -+ - static inline abi_long target_to_host_semun(int cmd, - union semun *host_su, - abi_ulong target_addr, -@@ -1779,7 +1866,15 @@ - case IPC_SET: - if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) - return -TARGET_EFAULT; -- target_to_host_semid_ds(ds,target_su->buf); -+ target_to_host_semid_ds(ds,tswapl(target_su->buf)); -+ host_su->buf = ds; -+ unlock_user_struct(target_su, target_addr, 0); -+ break; -+ case IPC_STAT + IPC_64: -+ case IPC_SET + IPC_64: -+ if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) -+ return -TARGET_EFAULT; -+ target_to_host_semid64_ds((struct semid64_ds*)ds,tswapl(target_su->buf)); - host_su->buf = ds; - unlock_user_struct(target_su, target_addr, 0); - break; -@@ -1815,7 +1910,14 @@ - case IPC_SET: - if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) - return -TARGET_EFAULT; -- host_to_target_semid_ds(target_su->buf,ds); -+ host_to_target_semid_ds(tswapl(target_su->buf),ds); -+ unlock_user_struct(target_su, target_addr, 1); -+ break; -+ case IPC_STAT + IPC_64: -+ case IPC_SET + IPC_64: -+ if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) -+ return -TARGET_EFAULT; -+ host_to_target_semid64_ds(tswapl(target_su->buf),(struct semid64_ds*)ds); - unlock_user_struct(target_su, target_addr, 1); - break; - case GETVAL: -@@ -1843,7 +1945,8 @@ - { - union semun arg; - struct semid_ds dsarg; -- int cmd = third&0xff; -+ struct semid64_ds dsarg64; -+ int cmd = third; // &0xff; - abi_long ret = 0; - - switch( cmd ) { -@@ -1872,13 +1975,23 @@ - ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); - break; -+ case IPC_STAT + IPC_64: -+ target_to_host_semun(cmd,&arg,ptr,(struct semid_ds *)&dsarg64); -+ ret = get_errno(semctl(first, second, cmd, arg)); -+ host_to_target_semun(cmd,ptr,&arg,(struct semid_ds *)&dsarg64); -+ break; - case IPC_SET: - target_to_host_semun(cmd,&arg,ptr,&dsarg); - ret = get_errno(semctl(first, second, cmd, arg)); - host_to_target_semun(cmd,ptr,&arg,&dsarg); - break; -- default: -+ case IPC_SET + IPC_64: -+ target_to_host_semun(cmd,&arg,ptr,(struct semid_ds *)&dsarg64); - ret = get_errno(semctl(first, second, cmd, arg)); -+ host_to_target_semun(cmd,ptr,&arg,(struct semid_ds *)&dsarg64); -+ break; -+ default: -+ ret = get_errno(semctl(first, second, cmd & 0xff, arg)); - } - - return ret; -@@ -1908,6 +2021,41 @@ - abi_ulong __unused5; - }; - -+struct target_shmid64_ds { -+ struct target_ipc64_perm shm_perm; /* operation perms */ -+ target_ulong shm_segsz; /* size of segment (bytes) */ -+ target_ulong shm_atime; /* last attach time */ -+ target_ulong __unused1; -+ target_ulong shm_dtime; /* last detach time */ -+ target_ulong __unused2; -+ target_ulong shm_ctime; /* last change time */ -+ target_ulong __unused3; -+ int32_t shm_cpid; /* pid of creator */ -+ int32_t shm_lpid; /* pid of last operator */ -+ target_ulong shm_nattch; /* no. of current attaches */ -+ target_ulong __unused4; -+ target_ulong __unused5; -+}; -+ -+/* Data structure describing a set of semaphores. */ -+struct target_shmid_ds -+ { -+ struct target_ipc_perm shm_perm; /* operation permission struct */ -+ unsigned int __unused1; -+ target_ulong shm_atime; /* time of last shmat() */ -+ unsigned int __unused2; -+ target_ulong shm_dtime; /* time of last shmdt() */ -+ unsigned int __unused3; -+ target_ulong shm_ctime; /* time of last change by shmctl() */ -+ unsigned int __unused4; -+ target_ulong shm_segsz; /* size of segment in bytes */ -+ unsigned int shm_cpid; /* pid of creator */ -+ unsigned int shm_lpid; /* pid of last shmop */ -+ target_ulong shm_nattch; /* number of current attaches */ -+ unsigned long __unused5; -+ unsigned long __unused6; -+ }; -+ - static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, - abi_ulong target_addr) - { -@@ -2193,11 +2341,59 @@ - case IPCOP_shmctl: - switch(second) { - case IPC_RMID: -+ case IPC_RMID + IPC_64: - case SHM_LOCK: -+ case SHM_LOCK + IPC_64: - case SHM_UNLOCK: -+ case SHM_UNLOCK + IPC_64: - ret = get_errno(shmctl(first, second, NULL)); - break; -+ case IPC_STAT + IPC_64: -+ { -+ struct shmid64_ds buf; -+ struct target_shmid64_ds *target_buf; -+#ifdef DEBUG -+ gemu_log("qemu: doing IPC_STAT\n"); -+#endif -+ lock_user_struct(VERIFY_WRITE, target_buf, ptr, 1); -+ ret = get_errno(shmctl(first, second, (struct shmid_ds*)&buf)); -+ -+ host_to_target_ipc64_perm(ptr, &buf.shm_perm); -+ target_buf->shm_atime = tswapl(buf.shm_atime); -+ target_buf->shm_dtime = tswapl(buf.shm_dtime); -+ target_buf->shm_ctime = tswapl(buf.shm_ctime); -+ target_buf->shm_segsz = tswapl(buf.shm_segsz); -+ target_buf->shm_cpid = tswap32(buf.shm_cpid); -+ target_buf->shm_lpid = tswap32(buf.shm_lpid); -+ target_buf->shm_nattch = tswapl(buf.shm_nattch); -+ unlock_user_struct(target_buf, ptr, 0); -+ break; -+ } -+ case IPC_SET + IPC_64: -+ { -+ struct shmid64_ds buf; -+ struct target_shmid64_ds *target_buf; -+#ifdef DEBUG -+ gemu_log("qemu: doing IPC_SET\n"); -+#endif -+ lock_user_struct(VERIFY_READ, target_buf, ptr, 1); -+ -+ target_to_host_ipc64_perm(&buf.shm_perm, ptr); -+ buf.shm_atime = tswapl(target_buf->shm_atime); -+ buf.shm_dtime = tswapl(target_buf->shm_dtime); -+ buf.shm_ctime = tswapl(target_buf->shm_ctime); -+ buf.shm_segsz = tswapl(target_buf->shm_segsz); -+ buf.shm_cpid = tswap32(target_buf->shm_cpid); -+ buf.shm_lpid = tswap32(target_buf->shm_lpid); -+ buf.shm_nattch = tswapl(target_buf->shm_nattch); -+ -+ ret = get_errno(shmctl(first, second, (struct shmid_ds*)&buf)); -+ -+ unlock_user_struct(target_buf, ptr, 0); -+ break; -+ } - default: -+ gemu_log("Unsopported shmctl(%ld,%#lx)\n", second, second); - goto unimplemented; - } - break; ---- qemu-0.10.1/linux-user/syscall_defs.h -+++ qemu-0.10.1/linux-user/syscall_defs.h -@@ -2001,3 +2001,18 @@ - #include "socket.h" - - #include "errno_defs.h" -+ -+struct target_ipc64_perm -+{ -+ int key; -+ uint32_t uid; -+ uint32_t gid; -+ uint32_t cuid; -+ uint32_t cgid; -+ unsigned short mode; -+ unsigned short __pad1; -+ unsigned short seq; -+ unsigned short __pad2; -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; ---- qemu-0.10.1/linux-user/x86_64/syscall.h -+++ qemu-0.10.1/linux-user/x86_64/syscall.h -@@ -61,21 +61,6 @@ - }; - #endif - --struct target_ipc64_perm --{ -- int key; -- uint32_t uid; -- uint32_t gid; -- uint32_t cuid; -- uint32_t cgid; -- unsigned short mode; -- unsigned short __pad1; -- unsigned short seq; -- unsigned short __pad2; -- abi_ulong __unused1; -- abi_ulong __unused2; --}; -- - struct target_msqid64_ds { - struct target_ipc64_perm msg_perm; - unsigned int msg_stime; /* last msgsnd time */ diff --git a/qemu-cvs-ipc_semop.patch b/qemu-cvs-ipc_semop.patch deleted file mode 100644 index 62c507f0..00000000 --- a/qemu-cvs-ipc_semop.patch +++ /dev/null @@ -1,26 +0,0 @@ -Index: qemu/linux-user/syscall.c -================================================================================ ---- qemu/linux-user/syscall.c -+++ qemu/linux-user/syscall.c -@@ -1983,9 +1983,19 @@ - - switch (call) { - case IPCOP_semop: -- ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); -+ { -+ struct sembuf *target_sops; -+ int i; -+ lock_user_struct(VERIFY_READ, target_sops, ptr, 0); -+ for(i=0; istatus; - } -+ return 0; - } - - static void mpcore_timer_write(mpcore_timer_state *s, int offset, ---- target-m68k/translate.c -+++ target-m68k/translate.c -@@ -452,6 +452,7 @@ - default: - qemu_assert(0, "bad operand size"); - } -+ return 0; - } - - /* Assign value to a register. If the width is less than the register width diff --git a/qemu-svn-i386-nptl.patch b/qemu-svn-i386-nptl.patch deleted file mode 100644 index f403c76b..00000000 --- a/qemu-svn-i386-nptl.patch +++ /dev/null @@ -1,46 +0,0 @@ -Index: linux-user/syscall.c -================================================================================ ---- configure -+++ configure -@@ -1610,6 +1610,7 @@ - echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak - echo "#define CONFIG_KVM 1" >> $config_h - fi -+ target_nptl="yes" - ;; - x86_64) - echo "TARGET_ARCH=x86_64" >> $config_mak ---- linux-user/syscall.c -+++ linux-user/syscall.c -@@ -3175,8 +3175,14 @@ - flags &= ~CLONE_NPTL_FLAGS2; - - /* TODO: Implement CLONE_CHILD_CLEARTID. */ -- if (nptl_flags & CLONE_SETTLS) -+ if (nptl_flags & CLONE_SETTLS) { -+#if defined(TARGET_I386) && defined(TARGET_ABI32) -+ do_set_thread_area(new_env, newtls); -+ cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector); -+#else - cpu_set_tls (new_env, newtls); -+#endif -+ } - - /* Grab a mutex so that thread setup appears atomic. */ - pthread_mutex_lock(&clone_lock); -@@ -3247,8 +3253,14 @@ - if (flags & CLONE_PARENT_SETTID) - put_user_u32(gettid(), parent_tidptr); - ts = (TaskState *)env->opaque; -- if (flags & CLONE_SETTLS) -+ if (flags & CLONE_SETTLS) { -+#if defined(TARGET_I386) && defined(TARGET_ABI32) -+ do_set_thread_area(env, newtls); -+ cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector); -+#else - cpu_set_tls (env, newtls); -+#endif -+ } - /* TODO: Implement CLONE_CHILD_CLEARTID. */ - #endif - } else { diff --git a/qemu-svn-ncurses.patch b/qemu-svn-ncurses.patch deleted file mode 100644 index 8ee00bfc..00000000 --- a/qemu-svn-ncurses.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- configure -+++ configure -@@ -949,7 +949,7 @@ - #include - int main(void) { return curses_version(); } - EOF -- if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lcurses > /dev/null 2> /dev/null ; then -+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lncurses > /dev/null 2> /dev/null ; then - curses=yes - fi - fi # test "$curses" -@@ -1427,7 +1427,7 @@ - if test "$curses" = "yes" ; then - echo "#define CONFIG_CURSES 1" >> $config_h - echo "CONFIG_CURSES=yes" >> $config_mak -- echo "CURSES_LIBS=-lcurses" >> $config_mak -+ echo "CURSES_LIBS=-lncurses" >> $config_mak - fi - if test "$brlapi" = "yes" ; then - echo "CONFIG_BRLAPI=yes" >> $config_mak diff --git a/qemu.changes b/qemu.changes index 6ee26fe5..46e7c54d 100644 --- a/qemu.changes +++ b/qemu.changes @@ -1,3 +1,44 @@ +------------------------------------------------------------------- +Mon Aug 11 14:44:48 CEST 2009 - uli@suse.de + +- update -> 0.11.0 RC1 + - add machine aliasing support (Mark McLoughlin) + - add getfd/closefd monitor commands (Mark McLoughlin) + - fix live migration (various) + - HPET fixes (various) + - slirp: fix guestfwd for incoming data (Jan Kiszka) + - fix qemu-img convert to copy unallocated parts of the image + (Akkarit Sangpetch) + - vmdk: fix backing file handling (Kevin Wolf) + - scsi: add save/restore support (Nolan Leake) + - e1000: ignore reset command (Kevin Wolf) + - allow monitor interaction when using -incoming exec: (Chris Lalancette) + - fix -net socket,listen (Jan Kiszka) + - serial: fix lost characters after sysrq (Jason Wessel) + - lsi53c895a: Implement additional registers (Sebastian Herbszt) + - i386: fix cpu reset (Nitin Kamble) + - Prevent CD-ROM eject while device is locked (Mark McLoughlin) + - Fix memory leaks (various) + - Reset PS2 keyboard/mouse on reset (Dinesh Subraveti) + - Fix -initrd with > 4GB guests (Glauber Costa) + - qcow2 fixes (various) + - Enable power button event generation (Gleb Natapov) + - fix serial option in -drive + - Fix non-ACPI timer interrupt routing (Beth Kon) + - Fix keyboard mapping on newer Xords with non-default keymaps (balrog) + - Make PCI config status register read-only (Anthony Liguori) + - Fix crash on resolution change -> screen dump -> vga redraw (Avi Kivity) + - fix savevm/loadvm (various) + - virtio: fix guest oops with 2.6.25 kernels (Rusty Russell) + - SH4: add support for -kernel (Takashi Yoshii, Aurelien Jarno) + - hotplug: fix closing of char devices (Jan Kiszka) + - hotplug: remove incorrect check for device name (Eduardo Habkost) + - fix VGA regression (malc) +- added S/390 host and target +- maintaining patches in git +- several linux-user improvements for compatibility and speed +- enabled curl block driver, VNC TLS and SASL, AIO, and Bluetooth + ------------------------------------------------------------------- Thu Apr 16 01:53:59 CEST 2009 - ro@suse.de diff --git a/qemu.spec b/qemu.spec index 7ad789d9..a41141ba 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,5 +1,5 @@ # -# spec file for package qemu (Version 0.10.1) +# spec file for package qemu (Version 0.11.0) # # Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. # @@ -19,39 +19,47 @@ Name: qemu -BuildRequires: SDL-devel bison e2fsprogs-devel libgnutls-devel libpcap-devel ncurses-devel zlib-devel-static +BuildRequires: SDL-devel bison bluez-devel curl-devel cyrus-sasl-devel e2fsprogs-devel libaio-devel libgnutls-devel libpcap-devel ncurses-devel zlib-devel-static Url: http://fabrice.bellard.free.fr/qemu/ -License: BSD 3-Clause; GPL v2 or later; LGPL v2.1 or later; X11/MIT +License: BSD 3-clause (or similar) ; GPL v2 or later ; LGPL v2.1 or later ; MIT License (or similar) Group: System/Emulators/PC Summary: Universal CPU emulator -Version: 0.10.1 -Release: 2 -Source: %name-%version.tar.bz2 -Patch1: qemu-0.9.0.cvs-binfmt.patch -Patch6: qemu-0.7.0-amd64.patch -Patch8: qemu-cvs-pthread.patch -#Patch19: qemu-0.9.0-nousbdevfs.patch -Patch34: qemu-0.9.0-migration.patch -Patch50: qemu-cvs-newpath.patch -Patch53: qemu-cvs-sched_getaffinity.patch -Patch56: qemu-cvs-ipc.patch -Patch57: qemu-cvs-ipc_semop.patch -Patch58: qemu-cvs-ioctl_debug.patch -Patch59: qemu-cvs-alsa_bitfield.patch -Patch60: qemu-cvs-alsa_ioctl.patch -Patch61: qemu-cvs-ioctl_nodirection.patch -Patch62: qemu-cvs-alsa_mmap.patch -Patch63: qemu-cvs-gettimeofday.patch -Patch64: qemu-cvs-nofadvise64.patch -Patch65: qemu-cvs-flash.patch -Patch66: qemu-cvs-mmap-amd64.patch -Patch85: qemu-img-vmdk-scsi.patch -Patch86: qemu-svn-ncurses.patch -Patch88: qemu-svn-pcap.patch -Patch90: qemu-nonvoid_return.patch -#Patch91: qemu-svn-dirent.patch -Patch92: qemu-svn-s390.patch -Patch93: qemu-svn-i386-nptl.patch +Version: 0.11.0 +Release: 1 +Source: %name-0.11.0-rc1.tar.bz2 +Patch1: 0001-qemu-0.7.0-amd64.patch +Patch2: 0002-qemu-0.9.0.cvs-binfmt.patch +Patch3: 0003-qemu-cvs-alsa_bitfield.patch +Patch4: 0004-qemu-cvs-alsa_ioctl.patch +Patch5: 0005-qemu-cvs-alsa_mmap.patch +Patch6: 0006-qemu-cvs-gettimeofday.patch +Patch7: 0007-qemu-cvs-ioctl_debug.patch +Patch8: 0008-qemu-cvs-ioctl_nodirection.patch +Patch9: 0009-qemu-cvs-newpath.patch +Patch10: 0010-qemu-cvs-sched_getaffinity.patch +Patch11: 0011-qemu-cvs-mmap-amd64.patch +Patch12: 0012-qemu-cvs-pthread.patch +Patch13: 0013-qemu-img-vmdk-scsi.patch +Patch14: 0014-qemu-nonvoid_return.patch +Patch15: 0015-pcap-network-emulation.patch +Patch16: 0016-i386-linux-user-NPTL-support.patch +Patch17: 0017-qemu-0.11-git-ioctl_mount.patch +Patch18: 0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch +Patch19: 0019-Rewrite-mmap_find_vma-to-work-fine-on-64-bit-hosts.patch +Patch20: 0020-TCG-sync-op-32-bit-targets-fixed.patch +Patch21: 0021-S-390-CPU-emulation.patch +Patch22: 0022-S-390-host-target-build-system-support.patch +Patch23: 0023-S-390-host-support-for-TCG.patch +Patch24: 0024-linux-user-S-390-64-bit-s390x-support.patch +Patch25: 0025-linux-user-don-t-do-locking-in-single-threaded-proc.patch +Patch26: 0026-linux-user-dup3-fallocate-syscalls.patch +Patch27: 0027-linux-user-fcntl-fixes-for-LTP.patch +Patch28: 0028-linux-user-enable-getdents-for-32-bit-systems.patch +Patch29: 0029-linux-user-define-a-couple-of-syscalls-for-non-uid1.patch +Patch30: 0030-linux-user-getpriority-errno-fix.patch +Patch31: 0031-linux-user-fadvise64-implementation.patch +Patch32: 0032-linux-user-zero-fstat-buffer-to-initialize-nsec-fie.patch +Patch33: 0033-dup3-check-fallocate-check-fixed.patch # this is to make lint happy Source300: rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -71,42 +79,54 @@ Authors: Fabrice Bellard %prep -%setup -q -ln -s fpu/*.h . +%setup -q -n qemu-0.11.0-rc1 %patch1 -p1 -%patch6 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 %patch8 -p1 -#%patch19 -%patch50 -p1 -%patch53 -p1 -%patch56 -p1 -%patch57 -p1 -%patch58 -p1 -%patch59 -p1 -%patch60 -p1 -%patch61 -p1 -%patch62 -p1 -%patch63 -p1 -%patch64 -p1 -%patch65 -p1 -%patch66 -p1 -%patch85 -p1 -%patch86 -%patch88 -%patch90 -#%patch91 -%patch92 -%patch93 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 %build # build QEMU mkdir -p dynamic -# build qemu-system without kqemu support +# build qemu-system ./configure --prefix=/usr \ --interp-prefix=/usr/share/qemu/qemu-i386 \ - --audio-card-list="ac97 adlib cs4231a gus" \ + --audio-card-list="ac97 es1370 sb16 cs4231a adlib gus" \ --audio-drv-list="alsa sdl" --enable-mixemu \ --extra-cflags="$QEMU_OPT_FLAGS" --enable-system --disable-linux-user +# curl test fails for no reason in build system +echo "CONFIG_CURL=y" >> config-host.mak +echo "CURL_LIBS=-lcurl" >> config-host.mak +echo "#define CONFIG_CURL 1" >> config-host.h make %{?jobs:-j%{jobs}} V=1 make qemu-img V=1 mv */qemu */qemu-* qemu-img dynamic || true @@ -121,21 +141,13 @@ make clean make %{?jobs:-j%{jobs}} V=1 %install -install -d -m 755 $RPM_BUILD_ROOT/usr/bin -%ifnarch alpha +make install DESTDIR=$RPM_BUILD_ROOT +rm -fr $RPM_BUILD_ROOT/usr/share/doc install -m 755 */qemu $RPM_BUILD_ROOT/usr/bin ln -sf qemu $RPM_BUILD_ROOT/usr/bin/qemu-system-i386 -%endif install -m 755 */qemu-*[^.]? $RPM_BUILD_ROOT/usr/bin -install -d -m 755 $RPM_BUILD_ROOT/%{_mandir}/man1 -install -m 644 qemu.1 $RPM_BUILD_ROOT/%{_mandir}/man1 -install -d -m 755 $RPM_BUILD_ROOT/usr/share/qemu -install -m 644 pc-bios/*.bin pc-bios/video.x pc-bios/openbios-sparc* $RPM_BUILD_ROOT/usr/share/qemu install -d -m 755 $RPM_BUILD_ROOT/usr/sbin install -m 755 qemu-binfmt-conf.sh $RPM_BUILD_ROOT/usr/sbin -install -m 755 dynamic/qemu-img $RPM_BUILD_ROOT/usr/bin -install -d -m 755 $RPM_BUILD_ROOT/usr/share/qemu/keymaps -install -m 644 keymaps/[a-z]* $RPM_BUILD_ROOT/usr/share/qemu/keymaps %ifnarch %ix86 x86_64 ln -sf ../../../emul/ia32-linux $RPM_BUILD_ROOT/usr/share/qemu/qemu-i386 %endif @@ -148,335 +160,14 @@ rm -rf ${RPM_BUILD_ROOT} %files %defattr(-, root, root) -%doc COPYING COPYING.LIB Changelog README TODO VERSION qemu-doc.html -%ifnarch alpha +%doc COPYING COPYING.LIB Changelog README TODO VERSION qemu-doc.html qemu-tech.html /usr/bin/qemu -%endif /usr/bin/qemu-* /usr/sbin/qemu* -%{_mandir}/man1/qemu*.1.gz +%doc %{_mandir}/man[18]/qemu*.[18].gz /usr/share/qemu %ifnarch %ix86 x86_64 ia64 %dir /emul/ia32-linux %endif %changelog -* Thu Apr 16 2009 ro@suse.de -- buildfix: refresh patches -* Fri Mar 27 2009 crrodriguez@suse.de -- BuildRequire zlib-devel-static -* Tue Mar 24 2009 uli@suse.de -- update -> release (0.10.1) - - fixes bnc #435135 (CVE-2008-4539, SWAMP #22179), #362956 - (CVE-2008-1945, CVE-2008-0928), #461565 (CVE-2008-2382) - - Kernel Virtual Machine acceleration support - - GDB XML register description support - - Intel e1000 emulation - - HPET emulation - - VirtIO paravirtual device support - - Marvell 88w8618 / MusicPal emulation - - Nokia N-series tablet emulation / OMAP2 processor emulation - - PCI hotplug support - - Curses display support - - qemu-nbd utility to mount supported block formats - - Altivec support in PPC emulation and new firmware (OpenBIOS) - - Multiple VNC clients are now supported - - TLS encryption is now supported in VNC - - MIPS Magnum R4000 machine (Hervé Poussineau) - - Braille support (Samuel Thibault) - - Freecom MusicPal system emulation (Jan Kiszka) - - OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski) - - EsounD audio driver (Frederick Reeve) - - Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz) - - Many, many, bug fixes and new features - - virtio-net: allow masking of notifications on empty queue (Alex - Williamson) - - e1000: fix rx descriptor low threshold logic (Alex Willaimson) - - x86 tcg: add NULL checks to lsl instruction (Jan Kiszka) - - kvm vga: fix screen corruption with -std-vga and Windows (Avi Kivity) - - kvm vga: fix screen corruption with Ubuntu installations (Glauber Costa) - - virtio-net: check right return size on sg list (Alex Williamson) - - Make qemu_announce_self handle holes (live migration after hotplug) - (Marcelo Tosatti) - - Revert r6804-r6808 (qcow2 allocation info). This series of changes - added a high cost to startup for large qcow2 images (Anthony Liguori) - - qemu-img: fix help message (Aurelien Jarno) - - Fix build for non-default installs of SDL (Anthony Liguori) - - Fix race condition in env->interrupt_request. When using TCG and a - dynticks host timer, this condition could cause TCG to get stuck in an - infinite loop (Aurelien Jarno) - - Fix reading encrypted hard disk passwords during early startup (Jan - Kiszka) - - Fix encrypted disk reporting in 'info block' (Jan Kiszka) - - Fix console size with tiny displays (MusicPal) (Jan Kiszka) - - Improve error handling in bdrv_open2 (Jan Kiszka) - - Avoid leaking data in mux'ed character devices (Jan Kiszka) - - Fix initial character device reset (no banner in monitor) (Jan Kiszka) - - Fix cpuid KVM crash on i386 host (Lubomir Rintel) - - Fix SLES10sp2 installation by adding ISTAT1 register to LSI SCSI - emulation (Ryan Harper) -- s390x TCG backend -- i386-linux-user NPTL support -* Wed Oct 08 2008 uli@suse.de -- update -> current SVN - - fixes PPC hosts - - fixes SH4 targets (reenabled), adds NPTL support - - SSSE3, SSE4.* instructions, "unreal" mode fixed - - Alpha target converted to TCG - - live migration - - Bluetooth emulation - - SCSI tape support - - OpenBIOS binary updated - - UHCI emulation rewritten - - lots of bugfixes -* Mon Aug 04 2008 ro@suse.de -- fix build by adding return statements for two nonvoid functions - (qemu-nonvoid_return.patch), actually unreached code -* Thu Jul 24 2008 uli@suse.de -- update -> current SVN - - MIPS Magnum R4000 machine (Hervé Poussineau) - - Braille support (Samuel Thibault) - - Freecom MusicPal system emulation (Jan Kiszka) - - OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski) - - EsounD audio driver (Frederick Reeve) - - Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz) -- added pcap networking -- ditched GCC3 thanks to TCG. Hooray! - (downside: no PPC and SH4 emulation, no S/390 host) -* Thu May 15 2008 cthiel@suse.de -- use lsilogic instead of buslogic for SCSI VMDK images -* Thu May 08 2008 uli@suse.de -- add format option to disable autodetection of disk image format - (bnc#380828) -* Fri Apr 25 2008 uli@suse.de -- revert secfix (causes data corruption, no known good patch - available yet) -- support creation of SCSI VMDK images -* Tue Mar 11 2008 uli@suse.de -- secfix (unchecked block read/write vulnerability, bug #362956) -* Thu Jan 17 2008 uli@suse.de -- update -> 0.9.1 - - TFTP booting from host directory (Anthony Liguori, Erwan Velu) - - Tap device emulation for Solaris (Sittichai Palanisong) - - Monitor multiplexing to several I/O channels (Jason Wessel) - - ds1225y nvram support (Herve Poussineau) - - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif) - - MIPS 64-bit FPU support (Thiemo Seufer) - - Xscale PDA emulation (Andrzej Zaborowski) - - ColdFire system emulation (Paul Brook) - - Improved SH4 support (Magnus Damm) - - MIPS64 support (Aurelien Jarno, Thiemo Seufer) - - Preliminary Alpha guest support (J. Mayer) - - Gumstix boards: connex and verdex emulation (Thorsten Zitterell) - - Intel mainstone II board emulation (Armin Kuster) - - VMware SVGA II graphics card support (Andrzej Zaborowski) -- revert s390-dis.c to last GPLv2 version -- reenabled qemu-system-ppcemb -* Mon Dec 10 2007 uli@suse.de -- fixed open() usage with O_CREAT -* Tue Nov 13 2007 uli@suse.de -- update -> current CVS: - - Read-only support for Parallels disk images (Alex Beregszaszi) - - CRIS emulation (Edgar E. Iglesias) - - SPARC32PLUS execution support (Blue Swirl) - - MIPS mipssim pseudo machine (Thiemo Seufer) - - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) - - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski) - - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery) -* Fri Oct 12 2007 ro@suse.de -- hack to fix build: undef DEBUG_BLOCK for now -* Fri Sep 28 2007 agraf@suse.de -- fix SVM support (Alexander Graf) -* Thu Sep 13 2007 agraf@suse.de -- add SVM emulation support (Alexander Graf) -- fix a misassumption in the s390 fix (uli) -- allow more IDE power management (Ben Guthro) -- log any I/O error and perform automatic read retry for CDrom (Ben Guthro) -- fix Coherent guest support (Jan Jezabek) -- fix several Darwin guest issues (Filip Navara) -* Mon Aug 20 2007 agraf@suse.de -- fix ATAPI bug when using libata (Brandon Philips) (#291775) -* Sat Aug 11 2007 olh@suse.de -- disable only SNDRV_SB_CSP_IOCTL_LOAD_CODE for _IOC_SIZEBITS < 14 -* Thu Aug 09 2007 olh@suse.de -- disable some alsa SB ioctl declarations -* Mon Aug 06 2007 olh@suse.de -- remove inclusion of linux/compiler.h -* Mon Jul 30 2007 uli@suse.de -- fixed for S/390 -* Tue Jul 10 2007 schwab@suse.de -- Add (incomplete) m68k emulation. -* Mon Jul 09 2007 agraf@suse.de -- included alsa support in qemu-user -- update to current cvs - - TFTP booting from host directory (Anthony Liguori, Erwan Velu) - - Tap device emulation for Solaris (Sittichai Palanisong) - - Monitor multiplexing to several I/O channels (Jason Wessel) - - ds1225y nvram support (Herve Poussineau) - - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - - Several Sparc fixes (Aurelien Jarno, Blue Swirl) - - MIPS 64-bit FPU support (Thiemo Seufer) - - Xscale PDA emulation (Andrzei Zaborowski) - - ColdFire system emulation (Paul Brook) - - Improved SH4 support (Magnus Damm) - - MIPS64 support (Aurelien Jarno, Thiemo Seufer) - - Preliminary Alpha guest support (J. Mayer) - - IPC fixes -* Wed Jun 20 2007 agraf@suse.de -- applied proper fix for x86_64 and the MAP_32BIT flag -* Wed Jun 20 2007 uli@suse.de -- added secfixes (bug #252519) -* Thu Jun 14 2007 agraf@suse.de -- made wine work (set FS register to 0 on init) -- suppressed robust_list warnings -* Wed Jun 13 2007 agraf@suse.de -- made flash player 9 work on ppc -- fixed FUTEX_WAKE_OP on machines where endianness differs -- made mmap on x86_64 use the MAP_32BIT flag -- removed a useless spin_lock -- removed an annoying debug message for forking -- implemented sched_getaffinity syscall -- fixed configure call so it takes gcc3 again -* Wed Jun 13 2007 uli@suse.de -- support "vga=" parameter (Pascal Terjan) -- direct jump support for x86-64 (Gwenole Beauchesne) -- fix chaining of CPU instances (Gwenole Beauchesne) -- live migration support (Anthony Liguori) -- fix fprem/fprem1 insns (Julian Seward) -- KVM support -- Z80/ZX Spectrum emulation (Stuart Brady) -- GCC4 support postponed (breaks x86-64 on i386) -* Mon Jun 11 2007 agraf@suse.de -- implemented TLS support on i386 so qemu-user can be used to run - with current libc versions (partly done by David Woodhouse, - fixed by Alexander Graf) -- added a dirty hack for an mmap page table bug on qemu-user x86 - emulation -- disable AF_NETLINK in qemu-user (endianness problems) -- applied fast path mangling patch from Kirill A. Shutemov -- applied strace patch for debugging (by Stuart R. Anderson) -* Wed Apr 04 2007 agraf@suse.de -- fixed initrd loading on x86 -* Thu Mar 29 2007 ro@suse.de -- added bison to BuildRequires -* Tue Feb 20 2007 uli@suse.de -- added better fix by Robert Schiele (bug #241950) -- update -> 0.9.0 - - Support for relative paths in backing files for disk images - - Async file I/O API - - New qcow2 disk image format - - Support of multiple VM snapshots - - Linux: specific host CDROM and floppy support - - SMM support - - Moved PCI init, MP table init and ACPI table init to Bochs BIOS - - Support for MIPS32 Release 2 instruction set (Thiemo Seufer) - - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil) - - Darwin userspace emulation (Pierre d'Herbemont) - - m68k user support (Paul Brook) - - several x86 and x86_64 emulation fixes - - Mouse relative offset VNC extension (Anthony Liguori) - - PXE boot support (Anthony Liguori) - - '-daemonize' option (Anthony Liguori) -* Tue Feb 06 2007 uli@suse.de -- added fix by Robert Schiele to work without usbdevfs - (bug #241950) -* Fri Feb 02 2007 ro@suse.de -- remove -fstack-protector from CFLAGS -* Fri Oct 27 2006 schwab@suse.de -- Fix char signedness. -* Mon Sep 11 2006 uli@suse.de -- re-added ARM FPE patch -- fixed SPARC on PPC -- install missing openbios-sparc32 -* Sat Sep 09 2006 dmueller@suse.de -- update to 0.8.2: - - ACPI support - - PC VGA BIOS fixes - - MIPS FPU support (Marius Groeger) - - PPC breakpoints and single stepping (Jason Wessel) - - USB updates (Paul Brook) - - UDP/TCP/telnet character devices (Jason Wessel) - - Windows sparse file support (Frediano Ziglio) - - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko) - - PCNET NIC support (Antony T Curtis) - - Support for variable frequency host CPUs - - Workaround for win32 SMP hosts - - Support for AMD Flash memories (Jocelyn Mayer) - - Audio capture to WAV files support (malc) -* Tue May 30 2006 uli@suse.de -- fixed to build on PPC with new glibc -* Mon May 29 2006 uli@suse.de -- fixed to build with new kernel headers -* Wed Mar 08 2006 uli@suse.de -- split giant patch -- added NWFPE glue code fix -* Tue Mar 07 2006 schwab@suse.de -- More fixes for ia64 port. -* Tue Mar 07 2006 schwab@suse.de -- Remove obsolete hunk from ia64 patch. -* Wed Jan 25 2006 mls@suse.de -- converted neededforbuild to BuildRequires -* Tue Dec 20 2005 uli@suse.de -- update -> 0.8.0 -* Thu Dec 08 2005 uli@suse.de -- update to current CVS (MIPS userspace, ARM system, SMP, USB, - NX, VLAN, serial, parallel, ES1370, ALSA backend) -- build i386 and AMD64 emus with kqemu support if possible -- install missing PPC video driver, SPARC boot ROM -- install missing keymaps -* Mon Nov 07 2005 uli@suse.de -- updated linker scripts for new binutils release -* Sat Sep 17 2005 dmueller@suse.de -- update to 0.7.2 -* Mon Aug 15 2005 schwab@suse.de -- Don't package /emul/ia32-linux on ia64. -* Mon Aug 15 2005 schwab@suse.de -- Fix compilation on ia64. -* Mon Aug 01 2005 uli@suse.de -- update -> 0.7.1 -- enabled x86_64-system -* Mon Jul 11 2005 uli@suse.de -- update -> CVS (MIPS emulation) -- build with throwaway GCC3 (still no GCC4-compatible QEMU in - sight) -- enabled armeb-user -- link *-user statically (necessary for chrooting into non-native - systems) -- disabled s390, alpha, armv4l build (broken and unmaintained) -- disabled qemu-fast (broken and deprecated) -- disabled i386-user on x86_64 (useless) -- build with %%jobs -* Wed Jun 01 2005 ro@suse.de -- update to 0.7.0, still no success with gcc-4 -* Thu Jan 27 2005 uli@suse.de -- baselibs-x86 link is unnecessary on x86/AMD64 -- two ARM emulation fixes (RRX operand fix by Paul Brook, shifter - carry fix by me) -- SDL 1.2.8 can be linked statically -> enabled qemu-fast -* Mon Nov 29 2004 uli@suse.de -- update -> 0.6.1 -- build softmmu binaries on s390 (still doesn't work though) -- pack /emul/ia32-linux directory and symlink from /usr/share/qemu - so it's possible to use the IA64 baselibs-x86 packages -* Wed Sep 15 2004 uli@suse.de -- removed unnecessary dependency on private glibc symbol - (bug #44864) -* Fri Aug 06 2004 uli@suse.de -- update -> 0.6.0 (fixes for several OSs, improvements in emulated - hardware (IDE, PCI, network, VGA, APM, PowerMac), minor fixes, - tool for conversion of VMware images) -* Tue May 11 2004 uli@suse.de -- update -> 0.5.5 (contains ARM, utime() fixes and several others) -- make uname() return target machine name (fixes config.guess, - rpm etc.) -- fake sigaltstack() (fixes m4) -- enabled x86-64 -* Wed May 05 2004 uli@suse.de -- fixed ARM emulation bug -* Wed Apr 28 2004 uli@suse.de -- build with -fno-unit-at-a-time (fixes PPC system emulator) -* Wed Apr 28 2004 uli@suse.de -- update -> 0.5.4 (runs Linux/PPC, several fixes) -* Mon Apr 19 2004 uli@suse.de -- initial package