diff --git a/0001-qemu-0.7.0-amd64.patch b/0001-qemu-0.7.0-amd64.patch index a4b348a1..75157c6b 100644 --- a/0001-qemu-0.7.0-amd64.patch +++ b/0001-qemu-0.7.0-amd64.patch @@ -1,7 +1,7 @@ -From 827af866df5674253ef563bd244277d31a93ba32 Mon Sep 17 00:00:00 2001 +From 8c7a6ec1220237db1e270244b1f1d90dd3d54204 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 +Subject: [PATCH 01/16] qemu-0.7.0-amd64 No clue why this is necessary or useful, nothing found in any changelogs. --- @@ -9,10 +9,10 @@ No clue why this is necessary or useful, nothing found in any changelogs. 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x86_64.ld b/x86_64.ld -index 878dafb..142e641 100644 +index 24ea77d..52a696e 100644 --- a/x86_64.ld +++ b/x86_64.ld -@@ -59,8 +59,6 @@ SECTIONS +@@ -58,8 +58,6 @@ SECTIONS .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } @@ -21,7 +21,7 @@ index 878dafb..142e641 100644 /* 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 @@ SECTIONS +@@ -85,8 +83,8 @@ SECTIONS .data1 : { *(.data1) } .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } @@ -33,5 +33,5 @@ index 878dafb..142e641 100644 .ctors : { -- -1.6.2.1 +1.6.4.2 diff --git a/0002-qemu-0.9.0.cvs-binfmt.patch b/0002-qemu-0.9.0.cvs-binfmt.patch index ec88e3d2..45fb14a3 100644 --- a/0002-qemu-0.9.0.cvs-binfmt.patch +++ b/0002-qemu-0.9.0.cvs-binfmt.patch @@ -1,7 +1,7 @@ -From 496da9d6ffd6f42570cbed52adba37fea769d2ab Mon Sep 17 00:00:00 2001 +From af10e52cdaf296681cf093f9269acf3080a01f5c 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 +Subject: [PATCH 02/16] qemu-0.9.0.cvs-binfmt Fixes binfmt_misc setup script: - x86_64 is i386-compatible @@ -81,5 +81,5 @@ index 941f0cf..67d6728 100644 + 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 +1.6.4.2 diff --git a/0003-qemu-cvs-alsa_bitfield.patch b/0003-qemu-cvs-alsa_bitfield.patch index a4ecc7b2..617c0193 100644 --- a/0003-qemu-cvs-alsa_bitfield.patch +++ b/0003-qemu-cvs-alsa_bitfield.patch @@ -1,7 +1,7 @@ -From 4675ae349f0d4e489f1298f1cbf246dfa7124d79 Mon Sep 17 00:00:00 2001 +From d4ec93547c43a157b88b923b612653c9527ec2a6 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 +Subject: [PATCH 03/16] qemu-cvs-alsa_bitfield Implements TYPE_INTBITFIELD partially. (required for ALSA support) @@ -79,5 +79,5 @@ index 109c541..55890f3 100644 case TYPE_LONGLONG: case TYPE_ULONGLONG: -- -1.6.2.1 +1.6.4.2 diff --git a/0004-qemu-cvs-alsa_ioctl.patch b/0004-qemu-cvs-alsa_ioctl.patch index 805ee83e..34d0a479 100644 --- a/0004-qemu-cvs-alsa_ioctl.patch +++ b/0004-qemu-cvs-alsa_ioctl.patch @@ -1,7 +1,7 @@ -From ab27a247cbab3c5f780e14a3ad822a5e12955d8f Mon Sep 17 00:00:00 2001 +From 91d6aa16e2794b006ac997ccebd2c7c7da671f32 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 +Subject: [PATCH 04/16] qemu-cvs-alsa_ioctl Implements ALSA ioctls on PPC hosts. @@ -19,10 +19,10 @@ Signed-off-by: Ulrich Hecht 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 +index 769e1bc..fca824c 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h -@@ -301,6 +301,11 @@ +@@ -304,6 +304,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))) @@ -2254,16 +2254,16 @@ index 0000000..3de8614 + unsigned char *code; +}; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h -index ac5dbc5..78c6488 100644 +index 2d45753..77ae416 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h -@@ -2138,3 +2138,4 @@ struct target_mq_attr { +@@ -2161,3 +2161,4 @@ struct target_mq_attr { #define FUTEX_CLOCK_REALTIME 256 #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) +#include "ioctls_alsa_structs.h" diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h -index d3f3df9..1fa48d0 100644 +index 340dbd3..1b92423 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -80,6 +80,11 @@ STRUCT(count_info, @@ -3622,5 +3622,5 @@ index 0000000..6dbc964 +) + -- -1.6.2.1 +1.6.4.2 diff --git a/0005-qemu-cvs-alsa_mmap.patch b/0005-qemu-cvs-alsa_mmap.patch index aa4080af..5c5a4689 100644 --- a/0005-qemu-cvs-alsa_mmap.patch +++ b/0005-qemu-cvs-alsa_mmap.patch @@ -1,7 +1,7 @@ -From ed5099e1cc655c77344863855abe5c20c1b6eb0b Mon Sep 17 00:00:00 2001 +From 8dc126f05ef5f8d0105d5d1b77493a27df8b4e30 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 +Subject: [PATCH 05/16] qemu-cvs-alsa_mmap Hack to prevent ALSA from using mmap() interface to simplify emulation. @@ -11,11 +11,11 @@ Signed-off-by: Ulrich Hecht 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c -index e05caa0..c33e5fe 100644 +index 144fb7c..1ea202b 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; +@@ -328,6 +328,9 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) + return h2g(ptr); } +#define SNDRV_PCM_MMAP_OFFSET_STATUS 0x80000000 @@ -24,7 +24,7 @@ index e05caa0..c33e5fe 100644 /* 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) -@@ -356,6 +359,17 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, +@@ -363,6 +366,17 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } #endif @@ -43,5 +43,5 @@ index e05caa0..c33e5fe 100644 errno = EINVAL; goto fail; -- -1.6.2.1 +1.6.4.2 diff --git a/0006-qemu-cvs-gettimeofday.patch b/0006-qemu-cvs-gettimeofday.patch index c4dcf38b..815f1594 100644 --- a/0006-qemu-cvs-gettimeofday.patch +++ b/0006-qemu-cvs-gettimeofday.patch @@ -1,7 +1,7 @@ -From 69aca2fcdf61fbd4a5c0123a7e64cf99862076ff Mon Sep 17 00:00:00 2001 +From fdeb1b8a61335d7c8537725cd1d7997053ce1d27 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 +Subject: [PATCH 06/16] qemu-cvs-gettimeofday No clue what this is for. --- @@ -9,10 +9,10 @@ No clue what this is for. 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index 7b57323..70d3b2d 100644 +index e38552c..63eef34 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, +@@ -5101,6 +5101,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_gettimeofday: { struct timeval tv; @@ -22,5 +22,5 @@ index 7b57323..70d3b2d 100644 if (!is_error(ret)) { if (copy_to_user_timeval(arg1, &tv)) -- -1.6.2.1 +1.6.4.2 diff --git a/0007-qemu-cvs-ioctl_debug.patch b/0007-qemu-cvs-ioctl_debug.patch index d4aaecae..ab948ef2 100644 --- a/0007-qemu-cvs-ioctl_debug.patch +++ b/0007-qemu-cvs-ioctl_debug.patch @@ -1,7 +1,7 @@ -From 4ec256fd6d555ec61f0a1bd530ff66860937b232 Mon Sep 17 00:00:00 2001 +From 6d88562dea1c1e0ae1367b89353a546c0e725513 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 +Subject: [PATCH 07/16] qemu-cvs-ioctl_debug Extends unsupported ioctl debug output. @@ -11,10 +11,10 @@ Signed-off-by: Ulrich Hecht 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index 70d3b2d..ce5283c 100644 +index 63eef34..1540e77 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) +@@ -2896,7 +2896,12 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) ie = ioctl_entries; for(;;) { if (ie->target_cmd == 0) { @@ -29,5 +29,5 @@ index 70d3b2d..ce5283c 100644 } if (ie->target_cmd == cmd) -- -1.6.2.1 +1.6.4.2 diff --git a/0008-qemu-cvs-ioctl_nodirection.patch b/0008-qemu-cvs-ioctl_nodirection.patch index 3cdacf68..f809bcb1 100644 --- a/0008-qemu-cvs-ioctl_nodirection.patch +++ b/0008-qemu-cvs-ioctl_nodirection.patch @@ -1,7 +1,7 @@ -From 5a0ba0e95920618c8ae38f4842d9dd56943f4343 Mon Sep 17 00:00:00 2001 +From 8fdbbf0d63c4de94c308c165283d7ea57f1cbf60 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 +Subject: [PATCH 08/16] 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 @@ -14,10 +14,10 @@ Signed-off-by: Ulrich Hecht 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index ce5283c..b7230c7 100644 +index 1540e77..3f810c3 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) +@@ -2926,6 +2926,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) { @@ -29,7 +29,7 @@ index ce5283c..b7230c7 100644 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) +@@ -2944,6 +2949,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; @@ -38,5 +38,5 @@ index ce5283c..b7230c7 100644 case IOC_RW: argptr = lock_user(VERIFY_READ, arg, target_size, 1); -- -1.6.2.1 +1.6.4.2 diff --git a/0009-qemu-cvs-newpath.patch b/0009-qemu-cvs-newpath.patch deleted file mode 100644 index 5fc1023a..00000000 --- a/0009-qemu-cvs-newpath.patch +++ /dev/null @@ -1,235 +0,0 @@ -From bc376b5848fef44ed9a56ec2e0e9bfd22aa1b24d 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"); -- -- The assumption is that this area does not change. - */ - #include --#include -+#include - #include --#include - #include --#include - #include - #include "qemu.h" - --struct pathelem --{ -- /* Name of this, eg. lib */ -- char *name; -- /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ -- char *pathname; -- struct pathelem *parent; -- /* Children */ -- unsigned int num_entries; -- struct pathelem *entries[0]; -+struct path_list_head { -+ struct path_list_head *next; -+ char* path; - }; - --static struct pathelem *base; -- --/* First N chars of S1 match S2, and S2 is N chars long. */ --static int strneq(const char *s1, unsigned int n, const char *s2) --{ -- unsigned int i; -- -- for (i = 0; i < n; i++) -- if (s1[i] != s2[i]) -- return 0; -- return s2[i] == 0; --} -- --static struct pathelem *add_entry(struct pathelem *root, const char *name); -- --static struct pathelem *new_entry(const char *root, -- struct pathelem *parent, -- const char *name) --{ -- struct pathelem *new = malloc(sizeof(*new)); -- new->name = strdup(name); -- asprintf(&new->pathname, "%s/%s", root, name); -- new->num_entries = 0; -- return new; --} -- --#define streq(a,b) (strcmp((a), (b)) == 0) -- --static struct pathelem *add_dir_maybe(struct pathelem *path) --{ -- DIR *dir; -- -- if ((dir = opendir(path->pathname)) != NULL) { -- struct dirent *dirent; -- -- while ((dirent = readdir(dir)) != NULL) { -- if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ -- path = add_entry(path, dirent->d_name); -- } -- } -- closedir(dir); -- } -- return path; --} -- --static struct pathelem *add_entry(struct pathelem *root, const char *name) --{ -- root->num_entries++; -- -- root = realloc(root, sizeof(*root) -- + sizeof(root->entries[0])*root->num_entries); -- -- root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); -- root->entries[root->num_entries-1] -- = add_dir_maybe(root->entries[root->num_entries-1]); -- return root; --} -- --/* This needs to be done after tree is stabilized (ie. no more reallocs!). */ --static void set_parents(struct pathelem *child, struct pathelem *parent) --{ -- unsigned int i; -- -- child->parent = parent; -- for (i = 0; i < child->num_entries; i++) -- set_parents(child->entries[i], child); --} -- --/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ --static const char * --follow_path(const struct pathelem *cursor, const char *name) --{ -- unsigned int i, namelen; -- -- name += strspn(name, "/"); -- namelen = strcspn(name, "/"); -- -- if (namelen == 0) -- return cursor->pathname; -- -- if (strneq(name, namelen, "..")) -- return follow_path(cursor->parent, name + namelen); -- -- if (strneq(name, namelen, ".")) -- return follow_path(cursor, name + namelen); -- -- for (i = 0; i < cursor->num_entries; i++) -- if (strneq(name, namelen, cursor->entries[i]->name)) -- return follow_path(cursor->entries[i], name + namelen); -- -- /* Not found */ -- return NULL; --} -+static struct path_list_head* list_head; - - void init_paths(const char *prefix) - { -- char pref_buf[PATH_MAX]; -- -- if (prefix[0] == '\0' || -- !strcmp(prefix, "/")) -+ if (prefix[0] != '/' || -+ prefix[0] == '\0' || -+ !strcmp(prefix, "/")) - return; - -- if (prefix[0] != '/') { -- char *cwd = get_current_dir_name(); -- if (!cwd) -- abort(); -- strcpy(pref_buf, cwd); -- strcat(pref_buf, "/"); -- strcat(pref_buf, prefix); -- 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) { -- free (base); -- base = NULL; -- } else { -- set_parents(base, base); -- } -+ /* first element of list is prefix */ -+ list_head->path = strdup(prefix); -+ list_head->next = NULL; - } - - /* Look for path in emulation dir, otherwise return name. */ - const char *path(const char *name) - { -+ struct path_list_head *list = list_head; -+ int path_length = strlen(list_head->path) + strlen(name) + 1; -+ char *newname = malloc(path_length); -+ struct stat buf; -+ const char * result = name; -+ - /* Only do absolute paths: quick and dirty, but should mostly be OK. - 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); -+ -+ /* look for place where path should be present */ -+ while ( list->next && (strcmp(list->next->path, newname) < 0) ) -+ list = list->next; -+ -+ /* if there is no path in list */ -+ if ( !list->next || strcmp(list->next->path, newname) ) { -+ /* add element to list if path exist in emulation dir */ -+ if ( !stat(newname, &buf) ) -+ { -+ struct path_list_head *new; -+ -+ new = malloc(sizeof(struct path_list_head)); -+ new->path = strdup(newname); -+ new->next = list->next; -+ list->next = new; -+ result = new->path; -+ } -+ -+ } else if ( stat(list->next->path, &buf) ) { -+ /* remove element from list if path doesn't exist in emulation dir */ -+ struct path_list_head* tmp; -+ -+ tmp = list->next; -+ list->next = tmp->next; -+ free(tmp->path); -+ free(tmp); -+ } else -+ result = list->next->path; -+ -+exit: -+ free(newname); -+ return result; - } --- -1.6.2.1 - diff --git a/0010-qemu-cvs-sched_getaffinity.patch b/0009-qemu-cvs-sched_getaffinity.patch similarity index 79% rename from 0010-qemu-cvs-sched_getaffinity.patch rename to 0009-qemu-cvs-sched_getaffinity.patch index ac86e0f3..25bf9da5 100644 --- a/0010-qemu-cvs-sched_getaffinity.patch +++ b/0009-qemu-cvs-sched_getaffinity.patch @@ -1,7 +1,7 @@ -From 72e306e63740a51a1c82f39cabb65df65ce2c215 Mon Sep 17 00:00:00 2001 +From a6f58c0e024cda6f06d788f6d03b699c8c736fdf 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 +Subject: [PATCH 09/16] qemu-cvs-sched_getaffinity Implements sched_getaffinity syscall. @@ -11,10 +11,10 @@ Signed-off-by: Ulrich Hecht 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index b7230c7..faf41b1 100644 +index 3f810c3..a74869e 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, \ +@@ -156,6 +156,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ } @@ -22,7 +22,7 @@ index b7230c7..faf41b1 100644 #define __NR_sys_uname __NR_uname #define __NR_sys_faccessat __NR_faccessat #define __NR_sys_fchmodat __NR_fchmodat -@@ -213,6 +214,9 @@ _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) +@@ -215,6 +216,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 @@ -32,10 +32,10 @@ index b7230c7..faf41b1 100644 #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif -@@ -6979,6 +6983,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, +@@ -7045,6 +7049,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + ret = get_errno(fallocate(arg1, arg2, arg3, arg4)); break; #endif - #endif /* CONFIG_SPLICE */ + +#ifdef TARGET_NR_sched_getaffinity + case TARGET_NR_sched_getaffinity: @@ -52,5 +52,5 @@ index b7230c7..faf41b1 100644 unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -- -1.6.2.1 +1.6.4.2 diff --git a/0011-qemu-cvs-mmap-amd64.patch b/0010-qemu-cvs-mmap-amd64.patch similarity index 85% rename from 0011-qemu-cvs-mmap-amd64.patch rename to 0010-qemu-cvs-mmap-amd64.patch index 2579fc44..6d322e88 100644 --- a/0011-qemu-cvs-mmap-amd64.patch +++ b/0010-qemu-cvs-mmap-amd64.patch @@ -1,7 +1,7 @@ -From 5c8849d886cafd1626c1d36c572c3ccee5c88d5d Mon Sep 17 00:00:00 2001 +From b22d5f62f9765ec734d7b14886d7aed5b61acf8b 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 +Subject: [PATCH 10/16] 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 @@ -13,7 +13,7 @@ Signed-off-by: Ulrich Hecht 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c -index c33e5fe..9ca8f6f 100644 +index 1ea202b..74b0d4b 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -31,6 +31,10 @@ @@ -26,7 +26,7 @@ index c33e5fe..9ca8f6f 100644 + //#define DEBUG_MMAP - #if defined(USE_NPTL) + #if defined(CONFIG_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 */ @@ -37,5 +37,5 @@ index c33e5fe..9ca8f6f 100644 return -1; prot1 = prot; -- -1.6.2.1 +1.6.4.2 diff --git a/0013-qemu-img-vmdk-scsi.patch b/0011-qemu-img-vmdk-scsi.patch similarity index 71% rename from 0013-qemu-img-vmdk-scsi.patch rename to 0011-qemu-img-vmdk-scsi.patch index f97f045a..6818aae5 100644 --- a/0013-qemu-img-vmdk-scsi.patch +++ b/0011-qemu-img-vmdk-scsi.patch @@ -1,7 +1,7 @@ -From 75e8da1c5ca1b61a9a97fcc385eb5c6b9f83130f Mon Sep 17 00:00:00 2001 +From afdac5e4c878653b9f4a038bebdcf98a01397a39 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 +Subject: [PATCH 11/16] qemu-img-vmdk-scsi Support creation of SCSI VMDK images in qemu-img. @@ -37,7 +37,7 @@ index 4e48622..b7a15c7 100644 /* 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 +index 9a3b2e0..85e8a72 100644 --- a/block_int.h +++ b/block_int.h @@ -30,6 +30,7 @@ @@ -49,18 +49,18 @@ index 8898d91..d482050 100644 #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 +index 641bd87..949ae97 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]") +- "create [-f fmt] [-o options] filename [size]") ++ "create [-s] [-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}] +-@item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ++@item create [-s] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ETEXI DEF("commit", img_commit, @@ -68,19 +68,19 @@ index ddb86f0..be94d22 100644 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") +- "convert [-c] [-f fmt] [-O output_fmt] [-o options] filename [filename2 [...]] output_filename") ++ "convert [-c] [-s] [-f fmt] [-O output_fmt] [-o options] 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} +-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename} ++@item convert [-c] [-s] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @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 +index 2824178..4b6663f 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -259,7 +259,7 @@ static int img_create(int argc, char **argv) +@@ -253,7 +253,7 @@ static int img_create(int argc, char **argv) flags = 0; for(;;) { @@ -89,7 +89,7 @@ index 070fe2e..2adeb56 100644 if (c == -1) break; switch(c) { -@@ -278,6 +278,9 @@ static int img_create(int argc, char **argv) +@@ -272,6 +272,9 @@ static int img_create(int argc, char **argv) case 'e': flags |= BLOCK_FLAG_ENCRYPT; break; @@ -99,7 +99,7 @@ index 070fe2e..2adeb56 100644 case '6': flags |= BLOCK_FLAG_COMPAT6; break; -@@ -357,6 +360,8 @@ static int img_create(int argc, char **argv) +@@ -354,6 +357,8 @@ static int img_create(int argc, char **argv) printf("Formatting '%s', fmt=%s ", filename, fmt); print_option_parameters(param); @@ -108,7 +108,7 @@ index 070fe2e..2adeb56 100644 puts(""); ret = bdrv_create(drv, filename, param); -@@ -551,7 +556,7 @@ static int img_convert(int argc, char **argv) +@@ -548,7 +553,7 @@ static int img_convert(int argc, char **argv) out_baseimg = NULL; flags = 0; for(;;) { @@ -117,7 +117,7 @@ index 070fe2e..2adeb56 100644 if (c == -1) break; switch(c) { -@@ -573,6 +578,9 @@ static int img_convert(int argc, char **argv) +@@ -570,6 +575,9 @@ static int img_convert(int argc, char **argv) case 'e': flags |= BLOCK_FLAG_ENCRYPT; break; @@ -127,7 +127,7 @@ index 070fe2e..2adeb56 100644 case '6': flags |= BLOCK_FLAG_COMPAT6; break; -@@ -639,6 +647,9 @@ static int img_convert(int argc, char **argv) +@@ -637,6 +645,9 @@ static int img_convert(int argc, char **argv) } } @@ -138,5 +138,5 @@ index 070fe2e..2adeb56 100644 ret = bdrv_create(drv, out_filename, param); free_option_parameters(param); -- -1.6.2.1 +1.6.4.2 diff --git a/0012-qemu-cvs-pthread.patch b/0012-qemu-cvs-pthread.patch deleted file mode 100644 index 4f43936b..00000000 --- a/0012-qemu-cvs-pthread.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 9e89bde7061d46a60dfe895450053360427a32f0 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 e4f9498..be55d3d 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/0014-qemu-nonvoid_return.patch b/0012-qemu-nonvoid_return.patch similarity index 78% rename from 0014-qemu-nonvoid_return.patch rename to 0012-qemu-nonvoid_return.patch index a5a1da92..9527e9cd 100644 --- a/0014-qemu-nonvoid_return.patch +++ b/0012-qemu-nonvoid_return.patch @@ -1,7 +1,7 @@ -From 29b517b3811d8745eb73e95fe18552eb1f0153af Mon Sep 17 00:00:00 2001 +From 44ce0d8cef307cd7b6e82242f896559916886f30 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 +Subject: [PATCH 12/16] qemu-nonvoid_return Squelches GCC warnings about undefined return values. @@ -12,10 +12,10 @@ Signed-off-by: Ulrich Hecht 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/hw/mpcore.c b/hw/mpcore.c -index 907bd99..a682695 100644 +index b4db191..ef0c705 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) +@@ -104,6 +104,7 @@ static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset) default: return 0; } @@ -24,7 +24,7 @@ index 907bd99..a682695 100644 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 +index 99cf6dd..18875d9 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -440,6 +440,7 @@ static inline int opsize_bytes(int opsize) @@ -36,5 +36,5 @@ index b37578b..feaa155 100644 /* Assign value to a register. If the width is less than the register width -- -1.6.2.1 +1.6.4.2 diff --git a/0016-i386-linux-user-NPTL-support.patch b/0013-i386-linux-user-NPTL-support.patch similarity index 83% rename from 0016-i386-linux-user-NPTL-support.patch rename to 0013-i386-linux-user-NPTL-support.patch index 39c6e78f..cafac289 100644 --- a/0016-i386-linux-user-NPTL-support.patch +++ b/0013-i386-linux-user-NPTL-support.patch @@ -1,7 +1,7 @@ -From e770ff83915791d048ca88da6c3877cb54bf063e Mon Sep 17 00:00:00 2001 +From b7c83887c1c86140ffaab86d4d1fca5a81e86c2d 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 +Subject: [PATCH 13/16] i386-linux-user NPTL support Makes NPTL binaries run by implementing TLS. @@ -12,10 +12,10 @@ Signed-off-by: Ulrich Hecht 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/configure b/configure -index 4ce7bc1..4f79498 100755 +index 5f463b0..0ec7ff0 100755 --- a/configure +++ b/configure -@@ -1904,6 +1904,7 @@ TARGET_ABI_DIR="" +@@ -2283,6 +2283,7 @@ TARGET_ABI_DIR="" case "$target_arch2" in i386) target_phys_bits=32 @@ -24,10 +24,10 @@ index 4ce7bc1..4f79498 100755 x86_64) TARGET_BASE_ARCH=i386 diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index faf41b1..87ceac7 100644 +index a74869e..ec67a14 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, +@@ -3584,8 +3584,14 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, ts->child_tidptr = child_tidptr; } @@ -43,7 +43,7 @@ index faf41b1..87ceac7 100644 /* 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, +@@ -3657,8 +3663,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; @@ -60,5 +60,5 @@ index faf41b1..87ceac7 100644 ts->child_tidptr = child_tidptr; #endif -- -1.6.2.1 +1.6.4.2 diff --git a/0017-qemu-0.11-git-ioctl_mount.patch b/0014-qemu-0.11-git-ioctl_mount.patch similarity index 80% rename from 0017-qemu-0.11-git-ioctl_mount.patch rename to 0014-qemu-0.11-git-ioctl_mount.patch index 3d0b1798..754fbe0b 100644 --- a/0017-qemu-0.11-git-ioctl_mount.patch +++ b/0014-qemu-0.11-git-ioctl_mount.patch @@ -1,17 +1,17 @@ -From df6df89350799107b3395665943c4df7eeba87e0 Mon Sep 17 00:00:00 2001 +From 7c670471903f85dfbcbfce2a7b7829bd08559c3c 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 +Subject: [PATCH 14/16] 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 +index fca824c..2cec892 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h -@@ -310,7 +310,7 @@ +@@ -313,7 +313,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))) @@ -21,5 +21,5 @@ index aee5a88..a0fb052 100644 IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) #endif -- -1.6.2.1 +1.6.4.2 diff --git a/0015-pcap-network-emulation.patch b/0015-pcap-network-emulation.patch deleted file mode 100644 index a8eeb9f8..00000000 --- a/0015-pcap-network-emulation.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 99759e033ea960b86828657682f8382538c4ccb7 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 -+ifdef CONFIG_PCAP -+LIBS+=-lpcap -+endif - - # specific flags are needed for non soft mmu emulator - ifdef CONFIG_STATIC -diff --git a/configure b/configure -index cac4198..4ce7bc1 100755 ---- a/configure -+++ b/configure -@@ -169,6 +169,7 @@ mingw32="no" - EXESUF="" - slirp="yes" - vde="yes" -+pcap="yes" - fmod_lib="" - fmod_inc="" - oss_lib="" -@@ -432,6 +433,8 @@ for opt do - ;; - --disable-vde) vde="no" - ;; -+ --disable-pcap) pcap="no" -+ ;; - --disable-kqemu) kqemu="no" - ;; - --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_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=y" >> $config_host_mak -diff --git a/net.c b/net.c -index 3d3829d..595f7bc 100644 ---- a/net.c -+++ b/net.c -@@ -1264,6 +1264,105 @@ void do_info_usernet(Monitor *mon) - - #endif /* CONFIG_SLIRP */ - -+#if defined(CONFIG_PCAP) -+#include -+typedef struct PCAPState { -+ VLANClientState *vc; -+ pcap_t *handle; -+} PCAPState; -+ -+static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -+{ -+ 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) -+{ -+ VLANClientState *vc = (VLANClientState *)user; -+ -+ qemu_send_packet(vc, pdata, phdr->len); -+} -+ -+static void pcap_send(void *opaque) -+{ -+ PCAPState *s = (PCAPState *)opaque; -+ -+ pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char *)s->vc); -+} -+ -+static int net_pcap_init(VLANState *vlan, const char *model, const char *name, char *ifname) -+{ -+ PCAPState *s; -+ char errbuf[PCAP_ERRBUF_SIZE]; -+ int fd; -+ -+ s = qemu_mallocz(sizeof(PCAPState)); -+ if (!s) -+ return -1; -+ -+ if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) { -+ fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf); -+ goto fail; -+ } -+ -+ /* Attempt to connect device. */ -+ s->handle = (void*)pcap_open_live(ifname, 65535, 1, 0, errbuf); -+ if (!s->handle) { -+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf); -+ goto fail; -+ } -+ -+ /* Check non-blocking mode. */ -+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { -+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); -+ goto fail; -+ } -+ -+#if defined(BIOCSHDRCMPLT) -+ /* -+ * Tell the kernel that the header is fully-formed when it gets it. -+ * This is required in order to fake the src address. -+ */ -+ { -+ unsigned int one = 1; -+ ioctl(pcap_fileno(s->handle), BIOCSHDRCMPLT, &one); -+ } -+#endif /* BIOCSHDRCMPLT */ -+ -+#if defined(BIOCIMMEDIATE) -+ /* -+ * Tell the kernel that the packet has to be processed immediately. -+ */ -+ { -+ unsigned int one = 1; -+ ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one); -+ } -+#endif /* BIOCIMMEDIATE */ -+ -+ 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"); -+ goto fail; -+ } -+ qemu_set_fd_handler(fd, pcap_send, NULL, s); -+ -+ return 0; -+ -+fail: -+ if (s) { -+ if (s->handle) -+ pcap_close(s->handle); -+ qemu_free(s); -+ } -+ -+ return -1; -+} -+#endif /* CONFIG_PCAP */ -+ - #if !defined(_WIN32) - - typedef struct TAPState { -@@ -2631,6 +2730,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]; -+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) -+ ret = net_pcap_init(vlan, device, name, NULL); -+ else -+ ret = net_pcap_init(vlan, device, name, ifname); -+ } else -+#endif - #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" -+#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" --- -1.6.2.1 - diff --git a/0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch b/0015-qemu-0.11-git-user-linux-ppc-uid16_fix.patch similarity index 96% rename from 0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch rename to 0015-qemu-0.11-git-user-linux-ppc-uid16_fix.patch index c0be7ea9..cccf4470 100644 --- a/0018-qemu-0.11-git-user-linux-ppc-uid16_fix.patch +++ b/0015-qemu-0.11-git-user-linux-ppc-uid16_fix.patch @@ -1,7 +1,7 @@ -From 015bd9be8314b3ce6d97d1bc9614874aee9b0e52 Mon Sep 17 00:00:00 2001 +From 7871becde1196cc4d89b1e27de4e03858ef8f265 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 +Subject: [PATCH 15/16] qemu-0.11-git-user-linux-ppc-uid16_fix --- linux-user/ppc/syscall_nr.h | 30 +++++++++++++++--------------- @@ -99,7 +99,7 @@ index f54276b..cc84a4c 100644 #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 +index 77ae416..e734fec 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -49,7 +49,7 @@ @@ -112,5 +112,5 @@ index 78c6488..0cbe396 100644 #define USE_UID16 #endif -- -1.6.2.1 +1.6.4.2 diff --git a/0016-S-390-support.patch b/0016-S-390-support.patch new file mode 100644 index 00000000..feb48909 --- /dev/null +++ b/0016-S-390-support.patch @@ -0,0 +1,7699 @@ +From 92f6fc08eaf4f9b0873c5442b0536df36323b868 Mon Sep 17 00:00:00 2001 +From: Ulrich Hecht +Date: Tue, 25 May 2010 16:38:22 +0200 +Subject: [PATCH 16/16] S/390 support + +--- + configure | 2 + + cpu-all.h | 2 +- + cpu-defs.h | 8 + + cpu-exec.c | 14 +- + default-configs/s390x-linux-user.mak | 1 + + disas.c | 3 + + exec.c | 2 + + linux-user/elfload.c | 18 + + linux-user/main.c | 89 ++ + 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 | 144 ++- + linux-user/syscall_defs.h | 56 +- + qemu-binfmt-conf.sh | 5 +- + s390-dis.c | 4 +- + target-s390x/cpu.h | 31 +- + target-s390x/exec.h | 2 +- + target-s390x/helper.c | 24 + + target-s390x/helpers.h | 128 ++ + target-s390x/op_helper.c | 1620 ++++++++++++++++++++ + target-s390x/translate.c | 2760 ++++++++++++++++++++++++++++++++++ + tcg/s390/tcg-target.c | 1070 +++++++++++++- + tcg/s390/tcg-target.h | 9 + + tcg/tcg-op.h | 12 + + tcg/tcg-opc.h | 2 + + tcg/tcg.c | 6 + + 29 files changed, 6947 insertions(+), 61 deletions(-) + create mode 100644 default-configs/s390x-linux-user.mak + 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 + create mode 100644 target-s390x/helpers.h + +diff --git a/configure b/configure +index 0ec7ff0..bf2aae0 100755 +--- a/configure ++++ b/configure +@@ -830,6 +830,7 @@ sh4eb-linux-user \ + sparc-linux-user \ + sparc64-linux-user \ + sparc32plus-linux-user \ ++s390x-linux-user \ + " + fi + # the following are Darwin specific +@@ -2379,6 +2380,7 @@ case "$target_arch2" in + target_phys_bits=64 + ;; + s390x) ++ target_nptl="yes" + target_phys_bits=64 + ;; + *) +diff --git a/cpu-all.h b/cpu-all.h +index 57b69f8..c500cb8 100644 +--- a/cpu-all.h ++++ b/cpu-all.h +@@ -138,7 +138,7 @@ typedef union { + uint64_t ll; + } CPU_DoubleU; + +-#ifdef TARGET_SPARC ++#if defined(TARGET_SPARC) || defined(TARGET_S390X) + typedef union { + float128 q; + #if defined(HOST_WORDS_BIGENDIAN) \ +diff --git a/cpu-defs.h b/cpu-defs.h +index 95068b5..c50c59e 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 3246c9e..b5b5a1f 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; +@@ -578,7 +581,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 */ +@@ -602,7 +609,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/default-configs/s390x-linux-user.mak b/default-configs/s390x-linux-user.mak +new file mode 100644 +index 0000000..a243c99 +--- /dev/null ++++ b/default-configs/s390x-linux-user.mak +@@ -0,0 +1 @@ ++# Default configuration for s390x-linux-user +diff --git a/disas.c b/disas.c +index f7bcce7..4267e67 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/exec.c b/exec.c +index 5969eb2..d51c8ce 100644 +--- a/exec.c ++++ b/exec.c +@@ -74,6 +74,8 @@ + #define TARGET_PHYS_ADDR_SPACE_BITS 42 + #elif defined(TARGET_I386) + #define TARGET_PHYS_ADDR_SPACE_BITS 36 ++#elif defined(TARGET_S390X) ++#define TARGET_PHYS_ADDR_SPACE_BITS 42 + #else + #define TARGET_PHYS_ADDR_SPACE_BITS 32 + #endif +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 682a813..899fe59 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -686,6 +686,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 802bd88..be9d8a2 100644 +--- a/linux-user/main.c ++++ b/linux-user/main.c +@@ -2433,6 +2433,86 @@ 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; ++ case EXCP_SPEC: ++ { ++ fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); ++ info.si_signo = SIGILL; ++ info.si_errno = 0; ++ info.si_code = TARGET_ILL_ILLOPC; ++ info._sifields._sigfault._addr = env->__excp_addr; ++ queue_signal(env, info.si_signo, &info); ++ } ++ break; ++ default: ++ printf ("Unhandled trap: 0x%x\n", trapnr); ++ 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" +@@ -3073,6 +3153,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 df189c3..c66cf85 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].ll, &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].ll, &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 ec67a14..1995ebb 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -186,7 +186,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 + +@@ -313,7 +313,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) + { +@@ -422,7 +422,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 +@@ -3566,6 +3566,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); + #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) +@@ -5145,7 +5146,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; +@@ -5252,7 +5253,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; +@@ -5737,6 +5740,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 +@@ -5941,8 +5946,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 +@@ -6167,7 +6176,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + 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_M68K) ++ defined(TARGET_M68K) || defined(TARGET_S390X) + ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); + break; + #else +@@ -6400,18 +6409,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 +@@ -6439,33 +6465,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; +@@ -6489,8 +6539,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; +@@ -6510,18 +6564,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)); +@@ -6534,13 +6600,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)); +@@ -6553,31 +6627,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 +diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h +index e734fec..a703f8e 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 +@@ -1633,6 +1636,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 +@@ -1719,6 +1743,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/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register ++fi +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 +index 0e75e1c..f2578af 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -32,19 +32,9 @@ + + #define NB_MMU_MODES 2 + +-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; ++#define TARGET_PAGE_BITS 12 ++ ++#include "cpu-all.h" + + typedef struct CPUS390XState { + uint64_t regs[16]; /* GP registers */ +@@ -52,7 +42,7 @@ typedef struct CPUS390XState { + uint32_t aregs[16]; /* access registers */ + + uint32_t fpc; /* floating-point control register */ +- FPReg fregs[16]; /* FP registers */ ++ CPU_DoubleU fregs[16]; /* FP registers */ + float_status fpu_status; /* passed to softfloat lib */ + + struct { +@@ -88,6 +78,8 @@ static inline int cpu_mmu_index (CPUState *env) + CPUS390XState *cpu_s390x_init(const char *cpu_model); + int cpu_s390x_exec(CPUS390XState *s); + void cpu_s390x_close(CPUS390XState *s); ++void s390x_translate_init(void); ++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 +@@ -106,17 +98,26 @@ extern void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token + extern CPUState *s390_cpu_addr2state(uint16_t cpu_addr); + #endif + ++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 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 + +-#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_SPEC 6 /* specification exception */ + #define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ + + static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) +diff --git a/target-s390x/exec.h b/target-s390x/exec.h +index 13dc7dd..e80c69e 100644 +--- a/target-s390x/exec.h ++++ b/target-s390x/exec.h +@@ -32,7 +32,7 @@ register struct CPUS390XState *env asm(AREG0); + + static inline int cpu_has_work(CPUState *env) + { +- return env->interrupt_request & CPU_INTERRUPT_HARD; // guess ++ return env->interrupt_request & CPU_INTERRUPT_HARD; /* guess */ + } + + static inline void regs_to_env(void) +diff --git a/target-s390x/helper.c b/target-s390x/helper.c +index 4c2dc82..ec096c4 100644 +--- a/target-s390x/helper.c ++++ b/target-s390x/helper.c +@@ -39,6 +39,7 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model) + cpu_exec_init(env); + if (!inited) { + inited = 1; ++ s390x_translate_init(); + } + + env->cpu_model_str = cpu_model; +@@ -64,8 +65,31 @@ void cpu_reset(CPUS390XState *env) + tlb_flush(env, 1); + } + ++#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; ++} ++ ++#endif /* CONFIG_USER_ONLY */ ++ + #ifndef CONFIG_USER_ONLY + ++target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ++{ ++ return 0; ++} ++ + int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) + { +diff --git a/target-s390x/helpers.h b/target-s390x/helpers.h +new file mode 100644 +index 0000000..0d16760 +--- /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, i32) ++DEF_HELPER_2(aeb, i32, i32, i32) ++DEF_HELPER_2(deb, void, i32, i32) ++DEF_HELPER_2(meeb, void, i32, i32) ++DEF_HELPER_2(cdb, i32, i32, i64) ++DEF_HELPER_2(adb, i32, i32, i64) ++DEF_HELPER_2(seb, i32, i32, i32) ++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 +index e623de9..d523c34 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -1,6 +1,7 @@ + /* + * S/390 helper routines + * ++ * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * This library is free software; you can redistribute it and/or +@@ -72,3 +73,1622 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) + } + + #endif ++ ++#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) ++{ ++#if TARGET_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ ++ __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; ++#else ++ mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); ++#endif ++} ++ ++/* 128 -> 64/64 unsigned division */ ++void HELPER(dlg)(uint32_t r1, uint64_t v2) ++{ ++#if TARGET_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ ++ __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); ++#else ++ cpu_abort(env, "128 -> 64/64 division not implemented on this system\n"); ++#endif ++} ++ ++/* 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_code(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: goto abort; 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 { ++abort: ++ cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", insn); ++ } ++ 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; ++ } ++} ++ ++/* 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) ++{ ++ CPU_QuadU v1; ++ v1.q = int32_to_float128(v2, &env->fpu_status); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++} ++ ++/* 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].l.upper = 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) ++{ ++ CPU_QuadU x1; ++ x1.q = int64_to_float128(v2, &env->fpu_status); ++ HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, x1.ll.upper, x1.l); ++ env->fregs[f1].ll = x1.ll.upper; ++ env->fregs[f1 + 2].ll = x1.ll.lower; ++} ++ ++/* convert 32-bit int to 32-bit float */ ++void HELPER(cefbr)(uint32_t f1, int32_t v2) ++{ ++ env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); ++ HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, env->fregs[f1].l.upper, f1); ++} ++ ++/* 32-bit FP addition RR */ ++uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 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].l.upper = float32_sub(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 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].l.upper = float32_div(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &env->fpu_status); ++} ++ ++/* 128-bit FP division RR */ ++void HELPER(dxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ CPU_QuadU res; ++ res.q = float128_div(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* 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) ++{ ++ CPU_QuadU v1; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ CPU_QuadU res; ++ res.q = float128_mul(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* 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].l.upper, &env->fpu_status); ++} ++ ++/* convert 128-bit float to 64-bit float */ ++void HELPER(ldxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x2; ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].d = float128_to_float64(x2.q, &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) ++{ ++ CPU_QuadU res; ++ res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* 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].l.upper = float64_to_float32(d2, &env->fpu_status); ++} ++ ++/* convert 128-bit float to 32-bit float */ ++void HELPER(lexbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x2; ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); ++ HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper); ++} ++ ++/* absolute value of 32-bit float */ ++uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1; ++ float32 v2 = env->fregs[f2].d; ++ v1 = float32_abs(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; ++ v1 = float64_abs(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) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ v1.q = float128_abs(v2.q); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++ return set_cc_nz_f128(v1.q); ++} ++ ++/* 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].l.upper = env->fregs[f2].l.upper; ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* load and test 128-bit float */ ++uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x; ++ x.ll.upper = env->fregs[f2].ll; ++ x.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].ll = x.ll.upper; ++ env->fregs[f1 + 2].ll = x.ll.lower; ++ return set_cc_nz_f128(x.q); ++} ++ ++/* negative absolute of 32-bit float */ ++uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_sub(float32_zero, env->fregs[f2].l.upper, &env->fpu_status); ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 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) ++{ ++ CPU_QuadU x1, x2; ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ x1.q = float128_sub(float64_to_float128(float64_zero, &env->fpu_status), x2.q, &env->fpu_status); ++ env->fregs[f1].ll = x1.ll.upper; ++ env->fregs[f1 + 2].ll = x1.ll.lower; ++ return set_cc_nz_f128(x1.q); ++} ++ ++/* 32-bit FP compare RM */ ++uint32_t HELPER(ceb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ v2.l = val; ++ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.f); ++ return set_cc_f32(v1, v2.f); ++} ++ ++/* 32-bit FP addition RM */ ++uint32_t HELPER(aeb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ v2.l = val; ++ HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 32-bit FP division RM */ ++void HELPER(deb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ v2.l = val; ++ HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); ++} ++ ++/* 32-bit FP multiplication RM */ ++void HELPER(meeb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ v2.l = val; ++ HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); ++} ++ ++/* 32-bit FP compare RR */ ++uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ float32 v2 = env->fregs[f2].l.upper;; ++ 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) ++{ ++ CPU_QuadU v1; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ if (float128_is_nan(v1.q) || float128_is_nan(v2.q)) return 3; ++ else if (float128_eq(v1.q, v2.q, &env->fpu_status)) return 0; ++ else if (float128_lt(v1.q, v2.q, &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; ++ CPU_DoubleU v2; ++ v2.ll = 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; ++ CPU_DoubleU v2; ++ v2.ll = 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, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ v2.l = val; ++ env->fregs[f1].l.upper = v1 = float32_sub(v1, v2.f, &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; ++ CPU_DoubleU v2; ++ v2.ll = 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; ++ CPU_DoubleU v2; ++ v2.ll = 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; ++ CPU_DoubleU v2; ++ v2.ll = 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].l.upper; ++ 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) ++{ ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ set_round_mode(m3); ++ env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); ++ if (float128_is_nan(v2.q)) return 3; ++ else if (float128_is_zero(v2.q)) return 0; ++ else if (float128_is_neg(v2.q)) 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].l.upper; ++ 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) ++{ ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float128_to_int32(v2.q, &env->fpu_status); ++ return set_cc_nz_f128(v2.q); ++} ++ ++/* load 32-bit FP zero */ ++void HELPER(lzer)(uint32_t f1) ++{ ++ env->fregs[f1].l.upper = 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) ++{ ++ CPU_QuadU x; ++ x.q = float64_to_float128(float64_zero, &env->fpu_status); ++ env->fregs[f1].ll = x.ll.upper; ++ env->fregs[f1 + 1].ll = x.ll.lower; ++} ++ ++/* 128-bit FP subtraction RR */ ++uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ CPU_QuadU res; ++ res.q = float128_sub(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++ return set_cc_nz_f128(res.q); ++} ++ ++/* 128-bit FP addition RR */ ++uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ CPU_QuadU v2; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ CPU_QuadU res; ++ res.q = float128_add(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++ return set_cc_nz_f128(res.q); ++} ++ ++/* 32-bit FP multiplication RR */ ++void HELPER(meebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, env->fregs[f2].l.upper, &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); ++ CPU_DoubleU v2; ++ v2.ll = 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].l.upper = float32_add(env->fregs[f1].l.upper, float32_mul(env->fregs[f2].l.upper, env->fregs[f3].l.upper, &env->fpu_status), &env->fpu_status); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++void HELPER(lxdb)(uint32_t f1, uint64_t a2) ++{ ++ CPU_DoubleU v2; ++ v2.ll = ldq(a2); ++ CPU_QuadU v1; ++ v1.q = float64_to_float128(v2.d, &env->fpu_status); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++} ++ ++/* test data class 32-bit */ ++uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ 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) ++{ ++ CPU_QuadU v1; ++ uint32_t cc = 0; ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ ++ int neg = float128_is_neg(v1.q); ++ if (float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) cc = 1; ++ else if (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) cc = 1; ++ else if (float128_is_nan(v1.q) && (m2 & (1 << (3-neg)))) cc = 1; ++ else if (float128_is_signaling_nan(v1.q) && (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 +index cde19df..aa50b7d 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -18,12 +18,43 @@ + * 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) +@@ -48,12 +79,2741 @@ void cpu_dump_state(CPUState *env, FILE *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_i64 tcgregs[16]; ++static TCGv_i32 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 HOST_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_i32 load_freg32(int reg) ++{ ++ TCGv_i32 r = tcg_temp_new_i32(); ++ tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].l.upper)); ++ return r; ++} ++ ++static void load_reg32_var(TCGv_i32 r, int reg) ++{ ++#ifdef TCGREGS ++ sync_reg64(reg); ++ tcg_gen_mov_i32(r, tcgregs32[reg]); ++#else ++#ifdef HOST_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_i32 load_reg32(int reg) ++{ ++ TCGv_i32 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_i32 v) ++{ ++#ifdef TCGREGS ++ sync_reg64(reg); ++ tcg_gen_mov_i32(tcgregs32[reg], v); ++#else ++#ifdef HOST_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_i32 v) ++{ ++#ifdef TCGREGS ++ TCGv_i32 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 HOST_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].l.upper)); ++} ++ ++static void gen_illegal_opcode(DisasContext *s) ++{ ++ TCGv tmp = tcg_const_i64(EXCP_SPEC); ++ gen_helper_exception(tmp); ++ tcg_temp_free(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; ++ 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) ++{ ++ TCGv_i32 tmp = tcg_const_i32(v2); ++ gen_helper_cmp_s32(cc, v1, tmp); ++ tcg_temp_free(tmp); ++} ++static inline void cmp_u32c(TCGv v1, uint32_t v2) ++{ ++ TCGv_i32 tmp = tcg_const_i32(v2); ++ gen_helper_cmp_u32(cc, v1, tmp); ++ tcg_temp_free(tmp); ++} ++ ++ ++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) ++{ ++ TCGv_i32 tmp = tcg_const_i64(v2); ++ gen_helper_cmp_s64(cc, v1, tmp); ++ tcg_temp_free(tmp); ++} ++static inline void cmp_u64c(TCGv v1, uint64_t v2) ++{ ++ TCGv_i32 tmp = tcg_const_i64(v2); ++ gen_helper_cmp_u64(cc, v1, tmp); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_bcr(uint32_t mask, int tr, uint64_t offset) ++{ ++ TCGv target, o; ++ TCGv_i32 m; ++ if (mask == 0xf) { /* unconditional */ ++ target = load_reg(tr); ++ tcg_gen_mov_i64(psw_addr, target); ++ } ++ else { ++ m = tcg_const_i32(mask); ++ o = tcg_const_i64(offset); ++ gen_helper_bcr(cc, m, (target = load_reg(tr)), o); ++ tcg_temp_free(m); ++ tcg_temp_free(o); ++ } ++ tcg_temp_free(target); ++} ++ ++static void gen_brc(uint32_t mask, uint64_t pc, int32_t offset) ++{ ++ TCGv p; ++ TCGv_i32 m, o; ++ ++ if (mask == 0xf) { /* unconditional */ ++ tcg_gen_movi_i64(psw_addr, pc + offset); ++ } ++ else { ++ m = tcg_const_i32(mask); ++ p = tcg_const_i64(pc); ++ o = tcg_const_i32(offset); ++ gen_helper_brc(cc, m, p, o); ++ tcg_temp_free(m); ++ tcg_temp_free(p); ++ tcg_temp_free(o); ++ } ++} ++ ++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, tmp2, tmp3; ++ ++ 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); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x12: /* LT R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ set_cc_s32(tmp2); ++ tcg_temp_free(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_temp_free(tmp); ++ tmp = load_reg(r1); ++ tcg_gen_mul_i64(tmp, tmp, tmp2); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp2); ++ 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); ++ } ++ else { ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ } ++ else if (op == 0x18) { ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ } ++ else { ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tcg_temp_free(tmp); ++ 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(); ++ } ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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] */ ++ tmp2 = tcg_temp_new_i64(); ++ if (op == 0x19) { ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ } ++ else if (op == 0x1b) { ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ } ++ else { ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ } ++ tcg_temp_free(tmp); ++ 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(); ++ } ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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: break; ++ default: tcg_abort(); ++ } ++ store_reg(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ store_reg(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); ++ store_reg(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_gen_bswap32_i64(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(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); ++ break; ++ case 0x31: ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ break; ++ default: ++ tcg_abort(); ++ } ++ tcg_temp_free(tmp); ++ 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(); ++ } ++ tcg_temp_free(tmp2); ++ break; ++ case 0x24: /* stg r1, d2(x2,b2) */ ++ tmp2 = load_reg(r1); ++ tcg_gen_qemu_st64(tmp2, tmp, 1); ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x50: /* STY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tcg_gen_qemu_st32(tmp2, tmp, 1); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x57: /* XY R1,D2(X2,B2) [RXY] */ ++ tmp2 = load_reg32(r1); ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp, 1); ++ tcg_gen_xor_i32(tmp, tmp2, tmp3); ++ store_reg32(r1, tmp); ++ set_cc_nz_u32(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0x58: /* LY R1,D2(X2,B2) [RXY] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp, 1); ++ store_reg32(r1, tmp3); ++ tcg_temp_free(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_i64(); ++ 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(); ++ } ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp3, tmp, 1); ++ store_reg8(r1, tmp3); ++ tcg_temp_free(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_i64(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ break; ++ case 0x77: ++ tcg_gen_ext8s_i64(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ break; ++ default: tcg_abort(); ++ } ++ tcg_temp_free(tmp2); ++ break; ++ case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32(r1); ++ gen_helper_mlg(tmp, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32(r1); ++ gen_helper_dlg(tmp, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld64(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = load_reg(r1); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32(r1); ++ gen_helper_addc_u32(cc, cc, tmp, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = load_reg32(r1); ++ tmp3 = tcg_const_i32(r1); ++ gen_helper_slb(cc, cc, tmp3, tmp, tmp2); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal e3 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++ tcg_temp_free(tmp); ++} ++ ++static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2) ++{ ++ TCGv tmp, tmp2, tmp3, tmp4; ++ 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_i64(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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_i64(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ } ++ } ++ 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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ tcg_temp_free(tmp4); ++ } ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0x51: /* TMY D1(B1),I2 [SIY] */ ++ tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32((r1 << 4) | r3); ++ gen_helper_tm(cc, tmp2, tmp); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x55: /* CLIY D1(B1),I2 [SIY] */ ++ tmp3 = get_address(0, b2, d2); /* SIY -> this is the 1st operand */ ++ tmp = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp, tmp3, 1); ++ cmp_u32c(tmp, (r1 << 4) | r3); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal eb operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++} ++ ++static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) ++{ ++ TCGv_i32 tmp; ++ TCGv tmp2, tmp3; ++ 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] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp2, 1); ++ gen_helper_ceb(cc, tmp, tmp3); ++ tcg_temp_free(tmp3); ++ break; ++ case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp2, 1); ++ gen_helper_aeb(cc, tmp, tmp3); ++ tcg_temp_free(tmp3); ++ break; ++ case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp2, 1); ++ gen_helper_seb(cc, tmp, tmp3); ++ tcg_temp_free(tmp3); ++ break; ++ case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp2, 1); ++ gen_helper_deb(tmp, tmp3); ++ tcg_temp_free(tmp3); ++ 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] */ ++ tmp3 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp3, tmp2, 1); ++ gen_helper_meeb(tmp, tmp3); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal ed operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ return; ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++} ++ ++static void disas_a5(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp, tmp2; ++ 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); ++ tcg_temp_free(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); ++ tcg_temp_free(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); ++ tcg_temp_free(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 */ ++ tcg_temp_free(tmp2); ++ 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); ++ return; ++ } ++ tcg_temp_free(tmp); ++} ++ ++static void disas_a7(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp, tmp2, tmp3; ++ 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); ++ tcg_temp_free(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); ++ tcg_temp_free(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); ++ tcg_temp_free(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); ++ tcg_temp_free(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; ++ return; ++ case 0x5: /* BRAS R1,I2 [RI] */ ++ tmp = tcg_const_i64(s->pc + 4); ++ store_reg(r1, tmp); ++ tcg_temp_free(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; ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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; ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ return; ++ } ++ tcg_temp_free(tmp); ++} ++ ++static void disas_b2(DisasContext *s, int op, int r1, int r2) ++{ ++ TCGv_i32 tmp, tmp2, tmp3; ++ 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); ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal b2 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ return; ++ } ++ tcg_temp_free(tmp); ++} ++ ++static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) ++{ ++ TCGv_i32 tmp, tmp2, tmp3; ++ 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); \ ++ tcg_temp_free(tmp); \ ++ tcg_temp_free(tmp2); ++ ++#define FP_HELPER_CC(i) \ ++ tmp = tcg_const_i32(r1); \ ++ tmp2 = tcg_const_i32(r2); \ ++ gen_helper_ ## i (cc, tmp, tmp2); \ ++ tcg_temp_free(tmp); \ ++ tcg_temp_free(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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp); ++ tmp = load_freg(r2 + 2); ++ store_freg(r1 + 2, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x74: /* LZER R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzer(tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x75: /* LZDR R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzdr(tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x76: /* LZXR R1 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ gen_helper_lzxr(tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x84: /* SFPC R1 [RRE] */ ++ tmp = load_reg32(r1); ++ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fpc)); ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0xa6: /* CXGBR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg(r2); ++ gen_helper_cxgbr(tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal b3 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++} ++ ++static void disas_b9(DisasContext *s, int op, int r1, int r2) ++{ ++ TCGv tmp, tmp2, tmp3; ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 1: /* LNGR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_nabs_i64(cc, tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 2: /* LTGR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ if (r1 != r2) store_reg(r1, tmp); ++ set_cc_s64(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ break; ++ case 4: /* LGR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x6: /* LGBR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tcg_gen_ext8s_i64(tmp2, tmp2); ++ store_reg(r1, tmp2); ++ tcg_temp_free(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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x16: /* LLGFR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_ext32u_i64(tmp, tmp); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x17: /* LLGTR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL); ++ tcg_gen_ext32u_i64(tmp, tmp); ++ store_reg(r1, tmp); ++ tcg_temp_free(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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x26: /* LBR R1,R2 [RRE] */ ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext8s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x27: /* LHR R1,R2 [RRE] */ ++ tmp2 = load_reg32(r2); ++ tcg_gen_ext16s_i32(tmp2, tmp2); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x83: /* FLOGR R1,R2 [RRE] */ ++ tmp2 = load_reg(r2); ++ tmp = tcg_const_i32(r1); ++ gen_helper_flogr(cc, tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x84: /* LLGCR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ tcg_gen_andi_i64(tmp, tmp, 0xff); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x85: /* LLGHR R1,R2 [RRE] */ ++ tmp = load_reg(r2); ++ tcg_gen_andi_i64(tmp, tmp, 0xffff); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x87: /* DLGR R1,R2 [RRE] */ ++ tmp = tcg_const_i32(r1); ++ tmp2 = load_reg(r2); ++ gen_helper_dlg(tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0x94: /* LLCR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i32(tmp, tmp, 0xff); ++ store_reg32(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x95: /* LLHR R1,R2 [RRE] */ ++ tmp = load_reg32(r2); ++ tcg_gen_andi_i32(tmp, tmp, 0xffff); ++ store_reg32(r1, tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ default: ++ LOG_DISAS("illegal b9 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++} ++ ++static void disas_c0(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp, tmp2, tmp3; ++ 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); ++ tcg_temp_free(tmp); ++ break; ++ case 0x1: /* LGFI R1,I2 [RIL] */ ++ tmp = tcg_const_i64((int64_t)i2); ++ store_reg(r1, tmp); ++ tcg_temp_free(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; ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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; ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(tmp); ++ break; ++ case 0x9: /* IILF R1,I2 [RIL] */ ++ tmp = tcg_const_i32((uint32_t)i2); ++ store_reg32(r1, tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ break; ++ case 0xe: /* LLIHF R1,I2 [RIL] */ ++ tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0xf: /* LLILF R1,I2 [RIL] */ ++ tmp = tcg_const_i64((uint32_t)i2); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ break; ++ default: ++ LOG_DISAS("illegal c0 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++} ++ ++static void disas_c2(DisasContext *s, int op, int r1, int i2) ++{ ++ TCGv tmp, tmp2, tmp3; ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ break; ++ case 0xc: /* CGFI R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ cmp_s64c(tmp, (int64_t)i2); ++ tcg_temp_free(tmp); ++ break; ++ case 0xe: /* CLGFI R1,I2 [RIL] */ ++ tmp = load_reg(r1); ++ cmp_u64c(tmp, (uint64_t)(uint32_t)i2); ++ tcg_temp_free(tmp); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ break; ++ default: ++ LOG_DISAS("illegal c2 operation 0x%x\n", op); ++ gen_illegal_opcode(s); ++ break; ++ } ++} ++ ++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, tmp2, tmp3; ++ 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 FREE_RX \ ++ tcg_temp_free(tmp); ++ ++#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); ++ ++#define FREE_SI \ ++ tcg_temp_free(tmp); ++ ++ 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)); ++ tcg_temp_free(tmp); ++ 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)); ++ tcg_temp_free(tmp2); ++ s->is_jmp = DISAS_JUMP; ++ } ++ tcg_temp_free(tmp); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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); ++ tcg_temp_free(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); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ s->pc += 2; ++ break; ++ case 0x18: /* LR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_reg32(r2); ++ store_reg32(r1, tmp); ++ tcg_temp_free(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; ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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(); ++ } ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ s->pc += 2; ++ break; ++ case 0x28: /* LDR R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_freg(r2); ++ store_freg(r1, tmp); ++ tcg_temp_free(tmp); ++ s->pc += 2; ++ break; ++ case 0x38: /* LER R1,R2 [RR] */ ++ FETCH_DECODE_RR ++ tmp = load_freg32(r2); ++ store_freg32(r1, tmp); ++ tcg_temp_free(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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x41: /* la */ ++ FETCH_DECODE_RX ++ store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ ++ FREE_RX ++ 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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x43: /* IC R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ store_reg8(r1, tmp2); ++ FREE_RX ++ tcg_temp_free(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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x49: /* CH R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ FREE_RX ++ tmp = load_reg32(r1); ++ cmp_s32(tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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_i64(); ++ tcg_gen_qemu_ld16s(tmp2, tmp, 1); ++ FREE_RX ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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; ++ FREE_RX ++ tcg_temp_free(tmp2); ++ break; ++ case 0x55: /* CL R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ FREE_RX ++ tmp = load_reg32(r1); ++ cmp_u32(tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ FREE_RX ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x58: /* l r1, d2(x2, b2) */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x59: /* C R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ FREE_RX ++ tmp = load_reg32(r1); ++ cmp_s32(tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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(); ++ } ++ FREE_RX ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ 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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ 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); ++ FREE_RX ++ tcg_temp_free(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); ++ FREE_RX ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x71: /* MS R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32s(tmp2, tmp, 1); ++ FREE_RX ++ tmp = load_reg(r1); ++ tcg_gen_mul_i32(tmp, tmp, tmp2); ++ store_reg(r1, tmp); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x78: /* LE R1,D2(X2,B2) [RX] */ ++ FETCH_DECODE_RX ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_freg32(r1, tmp2); ++ FREE_RX ++ tcg_temp_free(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; ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ break; ++ case 0x91: /* TM D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ FREE_SI ++ tmp = tcg_const_i32(i2); ++ gen_helper_tm(cc, tmp2, tmp); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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); ++ FREE_SI ++ tcg_temp_free(tmp2); ++ 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_i64(); ++ 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); ++ FREE_SI ++ tcg_temp_free(tmp2); ++ s->pc += 4; ++ break; ++ case 0x95: /* CLI D1(B1),I2 [SI] */ ++ FETCH_DECODE_SI ++ tmp2 = tcg_temp_new_i64(); ++ tcg_gen_qemu_ld8u(tmp2, tmp, 1); ++ cmp_u32c(tmp2, i2); ++ FREE_SI ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ 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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(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_i64(); ++ tcg_gen_qemu_ld32u(tmp2, tmp, 1); ++ store_reg32(r1, tmp2); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32(r3); ++ gen_helper_set_cc_icm(cc, tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(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_i64(); ++ 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); ++ tcg_temp_free(tmp); ++ tmp = tcg_const_i32(r3); ++ gen_helper_set_cc_icm(cc, tmp, tmp2); ++ tcg_temp_free(tmp); ++ tcg_temp_free(tmp2); ++ tcg_temp_free(tmp3); ++ } ++ else { ++ tmp = tcg_const_i32(0); ++ gen_helper_set_cc_icm(cc, tmp, tmp); /* i.e. env->cc = 0 */ ++ tcg_temp_free(tmp); ++ } ++ 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; ++ } ++} ++ ++static 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 && !env->singlestep_enabled); ++ 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, +diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c +index 356b1a4..00954c7 100644 +--- a/tcg/s390/tcg-target.c ++++ b/tcg/s390/tcg-target.c +@@ -29,24 +29,109 @@ static const int tcg_target_call_iarg_regs[] = { + }; + + static const int tcg_target_call_oarg_regs[] = { ++#ifndef NDEBUG ++static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ++ "%r0", ++ "%r1", ++ "%r2", ++ "%r3", ++ "%r4", ++ "%r5", ++ "%r6", ++ "%r7", ++ "%r8", ++ "%r9", ++ "%r10", ++ "%r11", ++ "%r12", ++ "%r13", ++ "%r14", ++ "%r15" ++}; ++#endif ++ ++static const int tcg_target_reg_alloc_order[] = { ++ TCG_REG_R6, ++ TCG_REG_R7, ++ TCG_REG_R8, ++ TCG_REG_R9, ++ TCG_REG_R10, ++ TCG_REG_R11, ++ TCG_REG_R12, ++ TCG_REG_R13, ++ TCG_REG_R14, ++ /* 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, ++ TCG_REG_R4, ++ TCG_REG_R5, ++}; ++ ++static const int tcg_target_call_iarg_regs[4] = { ++ TCG_REG_R2, TCG_REG_R3, TCG_REG_R4, TCG_REG_R5 ++}; ++static const int tcg_target_call_oarg_regs[2] = { ++ TCG_REG_R2, TCG_REG_R3 + }; + + static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) + { +- tcg_abort(); ++ switch (type) { ++ case R_390_PC32DBL: ++ *(uint32_t*)code_ptr = (value - ((tcg_target_long)code_ptr + addend)) >> 1; ++ break; ++ default: ++ tcg_abort(); ++ break; ++ } + } + ++/* maximum number of register used for input function arguments */ + static inline int tcg_target_get_call_iarg_regs_count(int flags) + { +- tcg_abort(); +- return 0; ++ 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) + { +- tcg_abort(); ++ const char *ct_str; ++ ++ ct->ct |= TCG_CT_REG; ++ tcg_regset_set32(ct->u.regs, 0, 0xffff); ++ ct_str = *pct_str; ++ switch (ct_str[0]) { ++ case 'L': /* qemu_ld constraint */ ++ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2); ++#ifdef CONFIG_SOFTMMU ++ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); ++#endif ++ break; ++ case 'S': /* qemu_st constraint */ ++ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2); ++#ifdef CONFIG_SOFTMMU ++ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); ++ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); ++#endif ++ break; ++ 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; ++ } ++ ct_str++; ++ *pct_str = ct_str; ++ + return 0; + } + +@@ -54,49 +139,1010 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) + { +- tcg_abort(); ++ int ct; ++ ct = arg_ct->ct; ++ if (ct & TCG_CT_CONST) ++ return 1; ++ 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 ++ ++#include "../../softmmu_defs.h" ++ ++static void *qemu_ld_helpers[4] = { ++ __ldb_mmu, ++ __ldw_mmu, ++ __ldl_mmu, ++ __ldq_mmu, ++}; ++ ++static void *qemu_st_helpers[4] = { ++ __stb_mmu, ++ __stw_mmu, ++ __stl_mmu, ++ __stq_mmu, ++}; ++#endif ++ ++static uint8_t *tb_ret_addr; ++ ++/* signed/unsigned is handled by using COMPARE and COMPARE LOGICAL, ++ respectively */ ++static const uint8_t tcg_cond_to_s390_cond[10] = { ++ [TCG_COND_EQ] = 8, ++ [TCG_COND_LT] = 4, ++ [TCG_COND_LTU] = 4, ++ [TCG_COND_LE] = 8 | 4, ++ [TCG_COND_LEU] = 8 | 4, ++ [TCG_COND_GT] = 2, ++ [TCG_COND_GTU] = 2, ++ [TCG_COND_GE] = 8 | 2, ++ [TCG_COND_GEU] = 8 | 2, ++ [TCG_COND_NE] = 4 | 2 | 1, ++}; ++ ++/* emit load/store (and then some) instructions (E3 prefix) */ ++static inline void tcg_out_e3(TCGContext* s, int op, int r1, int r2, int disp) ++{ ++ tcg_out16(s, 0xe300 | (r1 << 4)); ++ tcg_out32(s, op | (r2 << 28) | ((disp & 0xfff) << 16) | ((disp >> 12) << 8)); ++} ++#define E3_LG 0x04 ++#define E3_LRVG 0x0f ++#define E3_LGF 0x14 ++#define E3_LGH 0x15 ++#define E3_LLGF 0x16 ++#define E3_LRV 0x1e ++#define E3_LRVH 0x1f ++#define E3_CG 0x20 ++#define E3_STG 0x24 ++#define E3_STRVG 0x2f ++#define E3_STRV 0x3e ++#define E3_STRVH 0x3f ++#define E3_STHY 0x70 ++#define E3_STCY 0x72 ++#define E3_LGB 0x77 ++#define E3_LLGC 0x90 ++#define E3_LLGH 0x91 ++ ++/* emit 64-bit register/register insns (B9 prefix) */ ++static inline void tcg_out_b9(TCGContext* s, int op, int r1, int r2) ++{ ++ tcg_out32(s, 0xb9000000 | (op << 16) | (r1 << 4) | r2); ++} ++#define B9_LGR 0x04 ++#define B9_AGR 0x08 ++#define B9_SGR 0x09 ++#define B9_MSGR 0x0c ++#define B9_LGFR 0x14 ++#define B9_LLGFR 0x16 ++#define B9_CGR 0x20 ++#define B9_CLGR 0x21 ++#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) ++{ ++ tcg_out16(s, (op << 8) | (r1 << 4) | r2); ++} ++#define RR_BASR 0x0d ++#define RR_NR 0x14 ++#define RR_CLR 0x15 ++#define RR_OR 0x16 ++#define RR_XR 0x17 ++#define RR_LR 0x18 ++#define RR_CR 0x19 ++#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) ++{ ++ tcg_out16(s, 0xeb00 | (r0 << 4) | r1); ++ tcg_out32(s, op | (r2 << 28) | ((imm & 0xfff) << 16) | ((imm >> 12) << 8)); ++} ++#define SH64_REG_NONE 0 /* use immediate only (not R0!) */ ++#define SH64_SRAG 0x0a ++#define SH64_SRLG 0x0c ++#define SH64_SLLG 0x0d ++ ++/* emit 32-bit shifts */ ++static inline void tcg_out_sh32(TCGContext* s, int op, int r0, int r1, int imm) ++{ ++ tcg_out32(s, 0x80000000 | (op << 24) | (r0 << 20) | (r1 << 12) | imm); ++} ++#define SH32_REG_NONE 0 /* use immediate only (not R0!) */ ++#define SH32_SRL 0x8 ++#define SH32_SLL 0x9 ++#define SH32_SRA 0xa ++ ++/* branch to relative address (long) */ ++static inline void tcg_out_brasl(TCGContext* s, int r, tcg_target_long raddr) ++{ ++ tcg_out16(s, 0xc005 | (r << 4)); ++ tcg_out32(s, raddr >> 1); ++} ++ ++/* store 8/16/32 bits */ ++static inline void tcg_out_store(TCGContext* s, int op, int r0, int r1, int off) ++{ ++ tcg_out32(s, (op << 24) | (r0 << 20) | (r1 << 12) | off); ++} ++#define ST_STH 0x40 ++#define ST_STC 0x42 ++#define ST_ST 0x50 ++ + /* load a register with an immediate value */ + static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) + { +- tcg_abort(); ++ //fprintf(stderr,"tcg_out_movi ret 0x%x arg 0x%lx\n",ret,arg); ++ if (arg >= -0x8000 && arg < 0x8000) { /* signed immediate load */ ++ /* lghi %rret, arg */ ++ tcg_out32(s, 0xa7090000 | (ret << 20) | (arg & 0xffff)); ++ } ++ else if (!(arg & 0xffffffffffff0000UL)) { ++ /* llill %rret, arg */ ++ tcg_out32(s, 0xa50f0000 | (ret << 20) | arg); ++ } ++ 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 & 0xffffffff) >> 16)); ++ } ++ else { ++ /* branch over constant and store its address in R13 */ ++ tcg_out_brasl(s, TCG_REG_R13, 14); ++ /* 64-bit constant */ ++ tcg_out32(s,arg >> 32); ++ tcg_out32(s,arg); ++ /* load constant to ret */ ++ tcg_out_e3(s, E3_LG, ret, TCG_REG_R13, 0); ++ } + } + + /* load data without address translation or endianness conversion */ + static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) + { +- tcg_abort(); ++ int op; ++ //fprintf(stderr,"tcg_out_ld type %d arg %d arg1 %d arg2 %ld\n",type,arg,arg1,arg2); ++ ++ if (type == TCG_TYPE_I32) op = E3_LLGF; /* 32-bit zero-extended */ ++ else op = E3_LG; /* 64-bit */ ++ ++ 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 */ ++ } ++ else { ++ tcg_out_e3(s, op, arg, arg1, arg2); /* load the data */ ++ } ++} ++ ++/* load data with address translation (if applicable) and endianness conversion */ ++static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc) ++{ ++ int addr_reg, data_reg, mem_index, s_bits; ++#if defined(CONFIG_SOFTMMU) ++ uint16_t *label1_ptr, *label2_ptr; ++#endif ++ ++ data_reg = *args++; ++ addr_reg = *args++; ++ mem_index = *args; ++ ++ s_bits = opc & 3; ++ ++ int arg0 = TCG_REG_R2; ++#ifdef CONFIG_SOFTMMU ++ int arg1 = TCG_REG_R3; ++#endif ++ ++ /* fprintf(stderr,"tcg_out_qemu_ld opc %d data_reg %d addr_reg %d mem_index %d s_bits %d\n", ++ opc, data_reg, addr_reg, mem_index, s_bits); */ ++ ++#ifdef CONFIG_SOFTMMU ++ tcg_out_b9(s, B9_LGR, arg1, addr_reg); ++ tcg_out_b9(s, B9_LGR, arg0, addr_reg); ++ ++ tcg_out_sh64(s, SH64_SRLG, arg1, addr_reg, SH64_REG_NONE, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); ++ tcg_out_b9(s, B9_NGR, arg0, TCG_REG_R13); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ++ tcg_out_b9(s, B9_NGR, arg1, TCG_REG_R13); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); ++ tcg_out_b9(s, B9_AGR, arg1, TCG_REG_R13); ++ ++ tcg_out_b9(s, B9_AGR, arg1, TCG_AREG0); ++ ++ tcg_out_e3(s, E3_CG, arg0, arg1, 0); ++ ++ label1_ptr = (uint16_t*)s->code_ptr; ++ 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) { ++ 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); ++ break; ++ case 1 | 4: ++ tcg_out_sh64(s, SH64_SLLG, data_reg, arg0, SH64_REG_NONE, 48); ++ tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 48); ++ break; ++ case 2 | 4: ++ tcg_out_b9(s, B9_LGFR, data_reg, arg0); ++ break; ++ case 0: case 1: case 2: case 3: default: ++ /* unsigned -> just copy */ ++ tcg_out_b9(s, B9_LGR, data_reg, arg0); ++ break; ++ } ++ ++ /* jump to label2 (end) */ ++ label2_ptr = (uint16_t*)s->code_ptr; ++ tcg_out32(s, 0xa7d50000); /* bras %r13, label2 */ ++ ++ /* this is label1, patch branch */ ++ *(label1_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label1_ptr) >> 1; ++ ++ tcg_out_e3(s, E3_LG, arg1, arg1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read)); ++ ++#if TARGET_LONG_BITS == 32 ++ /* zero upper 32 bits */ ++ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); ++#else ++ /* just copy */ ++ tcg_out_b9(s, B9_LGR, arg0, addr_reg); ++#endif ++ tcg_out_b9(s, B9_AGR, arg0, arg1); ++ ++#else /* CONFIG_SOFTMMU */ ++ /* user mode, no address translation required */ ++ arg0 = addr_reg; ++#endif ++ ++ switch (opc) { ++ case 0: /* unsigned byte */ ++ tcg_out_e3(s, E3_LLGC, data_reg, arg0, 0); ++ break; ++ case 0 | 4: /* signed byte */ ++ tcg_out_e3(s, E3_LGB, data_reg, arg0, 0); ++ break; ++ case 1: /* unsigned short */ ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_LLGH, data_reg, arg0, 0); ++#else ++ /* swapped unsigned halfword load with upper bits zeroed */ ++ tcg_out_e3(s, E3_LRVH, data_reg, arg0, 0); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, 0xffffL); ++ tcg_out_b9(s, B9_NGR, data_reg, 13); ++#endif ++ break; ++ case 1 | 4: /* signed short */ ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_LGH, data_reg, arg0, 0); ++#else ++ /* swapped sign-extended halfword load */ ++ tcg_out_e3(s, E3_LRVH, data_reg, arg0, 0); ++ tcg_out_sh64(s, SH64_SLLG, data_reg, data_reg, SH64_REG_NONE, 48); ++ tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 48); ++#endif ++ break; ++ case 2: /* unsigned int */ ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_LLGF, data_reg, arg0, 0); ++#else ++ /* swapped unsigned int load with upper bits zeroed */ ++ tcg_out_e3(s, E3_LRV, data_reg, arg0, 0); ++ tcg_out_b9(s, B9_LLGFR, data_reg, data_reg); ++#endif ++ break; ++ case 2 | 4: /* signed int */ ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_LGF, data_reg, arg0, 0); ++#else ++ /* swapped sign-extended int load */ ++ tcg_out_e3(s, E3_LRV, data_reg, arg0, 0); ++ tcg_out_b9(s, B9_LGFR, data_reg, data_reg); ++#endif ++ break; ++ case 3: /* long (64 bit) */ ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_LG, data_reg, arg0, 0); ++#else ++ tcg_out_e3(s, E3_LRVG, data_reg, arg0, 0); ++#endif ++ break; ++ default: ++ tcg_abort(); ++ } ++ ++#ifdef CONFIG_SOFTMMU ++ /* this is label2, patch branch */ ++ *(label2_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label2_ptr) >> 1; ++#endif ++} ++ ++static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc) ++{ ++ int addr_reg, data_reg, mem_index, s_bits; ++#if defined(CONFIG_SOFTMMU) ++ uint16_t *label1_ptr, *label2_ptr; ++#endif ++ ++ data_reg = *args++; ++ addr_reg = *args++; ++ mem_index = *args; ++ ++ s_bits = opc; ++ ++ int arg0 = TCG_REG_R2; ++#ifdef CONFIG_SOFTMMU ++ int arg1 = TCG_REG_R3; ++ int arg2 = TCG_REG_R4; ++#endif ++ ++ /* fprintf(stderr,"tcg_out_qemu_st opc %d data_reg %d addr_reg %d mem_index %d s_bits %d\n", ++ 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); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); ++ tcg_out_b9(s, B9_NGR, arg0, TCG_REG_R13); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ++ tcg_out_b9(s, B9_NGR, arg1, TCG_REG_R13); ++ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); ++ tcg_out_b9(s, B9_AGR, arg1, TCG_REG_R13); ++ ++ tcg_out_b9(s, B9_AGR, arg1, TCG_AREG0); ++ ++ 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 */ ++ ++ /* call store helper */ ++ tcg_out_b9(s, B9_LGR, arg1, data_reg); ++ tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (tcg_target_ulong)qemu_st_helpers[s_bits]); ++ tcg_out_rr(s, RR_BASR, TCG_REG_R14, TCG_REG_R13); ++ ++ /* jump to label2 (end) */ ++ label2_ptr = (uint16_t*)s->code_ptr; ++ tcg_out32(s, 0xa7d50000); /* bras %r13, label2 */ ++ ++ /* this is label1, patch branch */ ++ *(label1_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label1_ptr) >> 1; ++ ++ tcg_out_e3(s, E3_LG, arg1, arg1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write)); ++ ++#if TARGET_LONG_BITS == 32 ++ /* zero upper 32 bits */ ++ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); ++#else ++ /* just copy */ ++ tcg_out_b9(s, B9_LGR, arg0, addr_reg); ++#endif ++ tcg_out_b9(s, B9_AGR, arg0, arg1); ++ ++#else /* CONFIG_SOFTMMU */ ++ /* user mode, no address translation required */ ++ arg0 = addr_reg; ++#endif ++ ++ 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); ++#else ++ tcg_out_e3(s, E3_STRVH, data_reg, arg0, 0); ++#endif ++ break; ++ case 2: ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_store(s, ST_ST, data_reg, arg0, 0); ++#else ++ tcg_out_e3(s, E3_STRV, data_reg, arg0, 0); ++#endif ++ break; ++ case 3: ++#ifdef TARGET_WORDS_BIGENDIAN ++ tcg_out_e3(s, E3_STG, data_reg, arg0, 0); ++#else ++ tcg_out_e3(s, E3_STRVG, data_reg, arg0, 0); ++#endif ++ break; ++ default: ++ tcg_abort(); ++ } ++ ++#ifdef CONFIG_SOFTMMU ++ /* this is label2, patch branch */ ++ *(label2_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label2_ptr) >> 1; ++#endif + } + + static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) + { +- tcg_abort(); ++ //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) { ++ 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); ++ } ++ else tcg_out_store(s, ST_ST, arg, arg1, arg2); ++ } ++ else { ++ if (((long)arg2) < -0x80000 || ((long)arg2) > 0x7ffff) tcg_abort(); ++ tcg_out_e3(s, E3_STG, arg, arg1, arg2); ++ } + } + + static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) + { +- tcg_abort(); ++ TCGLabel* l; ++ int op; ++ int op2; ++ //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]); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]); /* return value */ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (unsigned long)tb_ret_addr); ++ tcg_out16(s,0x7fd); /* br %r13 */ ++ 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) { ++ tcg_abort(); ++ } ++ else { ++ tcg_target_long off = ((tcg_target_long)(s->tb_next + args[0]) - (tcg_target_long)s->code_ptr) >> 1; ++ if (off > -0x80000000L && off < 0x7fffffffL) { /* load address relative to PC */ ++ /* larl %r13, off */ ++ tcg_out16(s,0xc0d0); tcg_out32(s,off); ++ } ++ else { /* too far for larl */ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (tcg_target_long)(s->tb_next + args[0])); ++ } ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R13, TCG_REG_R13, 0); /* load address stored at s->tb_next + args[0] */ ++ tcg_out_rr(s, RR_BASR, TCG_REG_R13, TCG_REG_R13); /* and go there */ ++ } ++ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; ++ 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]) { ++ 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); ++ tcg_abort(); // untested ++ } ++ else { /* too far for a relative call, load full address */ ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, args[0]); ++ tcg_out_rr(s, RR_BASR, TCG_REG_R14, TCG_REG_R13); ++ } ++ } ++ else { /* call function in register args[0] */ ++ tcg_out_rr(s, RR_BASR, TCG_REG_R14, args[0]); ++ } ++ break; ++ case INDEX_op_jmp: ++ fprintf(stderr,"op 0x%x jmp 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_abort(); ++ break; ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8u_i64: ++ //fprintf(stderr,"op 0x%x ld8u_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { ++ tcg_out_e3(s, E3_LLGC, args[0], args[1], args[2]); ++ } ++ else { /* displacement too large, have to calculate address manually */ ++ tcg_abort(); ++ } ++ break; ++ case INDEX_op_ld8s_i32: ++ fprintf(stderr,"op 0x%x ld8s_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_abort(); ++ break; ++ case INDEX_op_ld16u_i32: ++ fprintf(stderr,"op 0x%x ld16u_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { ++ tcg_out_e3(s, E3_LLGH, args[0], args[1], args[2]); ++ } ++ else { /* displacement too large, have to calculate address manually */ ++ tcg_abort(); ++ } ++ break; ++ case INDEX_op_ld16s_i32: ++ fprintf(stderr,"op 0x%x ld16s_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_abort(); ++ break; ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld32u_i64: ++ 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) { ++ 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) */ ++ } ++ else { ++ tcg_out_e3(s, E3_LGF, args[0], args[1], args[2]); /* load the data (sign-extended) */ ++ } ++ break; ++ case INDEX_op_ld_i64: ++ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]); ++ break; ++ 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) ++ tcg_out_store(s, ST_STC, args[0], args[1], args[2]); ++ 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 ++ } ++ else tcg_abort(); ++ break; ++ 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) ++ tcg_out_store(s, ST_STH, args[0], args[1], args[2]); ++ 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 ++ } ++ else tcg_abort(); ++ break; ++ case INDEX_op_st_i32: ++ case INDEX_op_st32_i64: ++ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); ++ break; ++ case INDEX_op_st_i64: ++ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); ++ break; ++ case INDEX_op_mov_i32: ++ fprintf(stderr,"op 0x%x mov_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_abort(); ++ break; ++ case INDEX_op_movi_i32: ++ fprintf(stderr,"op 0x%x movi_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ tcg_abort(); ++ break; ++ case INDEX_op_add_i32: ++ 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]) { ++ tcg_out_rr(s, RR_AR, args[0], args[1]); ++ } ++ else { ++ tcg_out_rr(s, RR_LR, args[0], args[1]); ++ tcg_out_rr(s, RR_AR, args[0], args[2]); ++ } ++ 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]) { ++ tcg_out_rr(s, RR_SR, args[1], args[2]); /* sr %ra0/1, %ra2 */ ++ } ++ 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 */ ++ } ++ else { ++ tcg_out_rr(s, RR_LR, args[0], args[1]); /* lr %ra0, %ra1 */ ++ tcg_out_rr(s, RR_SR, args[0], args[2]); /* sr %ra0, %ra2 */ ++ } ++ break; ++ ++ 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]) { ++ tcg_out_b9(s, B9_SGR, args[1], args[2]); /* sgr %ra0/1, %ra2 */ ++ } ++ 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 */ ++ } ++ else { ++ tcg_out_b9(s, B9_LGR, args[0], args[1]); /* lgr %ra0, %ra1 */ ++ tcg_out_b9(s, B9_SGR, args[0], args[2]); /* sgr %ra0, %ra2 */ ++ } ++ 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]) { ++ tcg_out_b9(s, B9_AGR, args[1], args[2]); ++ } ++ else if (args[0] == args[2]) { ++ tcg_out_b9(s, B9_AGR, args[0], args[1]); ++ } ++ else { ++ tcg_out_b9(s, B9_LGR, args[0], args[1]); ++ tcg_out_b9(s, B9_AGR, args[0], args[2]); ++ } ++ break; ++ ++ case INDEX_op_and_i32: ++ op = RR_NR; ++do_logic_i32: ++ if (args[0] == args[1]) { ++ tcg_out_rr(s, op, args[1], args[2]); /* xr %ra0/1, %ra2 */ ++ } ++ 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 */ ++ } ++ break; ++ case INDEX_op_or_i32: op = RR_OR; goto do_logic_i32; ++ case INDEX_op_xor_i32: op = RR_XR; goto do_logic_i32; ++ ++ case INDEX_op_and_i64: ++ //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]) { ++ tcg_out_b9(s, op, 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]); ++ } ++ break; ++ case INDEX_op_or_i64: op = B9_OGR; goto do_logic_i64; ++ case INDEX_op_xor_i64: op = B9_XGR; goto do_logic_i64; ++ ++ case INDEX_op_neg_i32: ++ //fprintf(stderr,"op 0x%x neg_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ /* FIXME: optimize args[0] != args[1] case */ ++ tcg_out_rr(s, RR_LR, 13, args[1]); ++ tcg_out32(s, 0xa7090000 | (args[0] << 20)); /* lghi %ra0, 0 */ ++ tcg_out_rr(s, RR_SR, args[0], 13); ++ break; ++ case INDEX_op_neg_i64: ++ //fprintf(stderr,"op 0x%x neg_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ /* FIXME: optimize args[0] != args[1] case */ ++ tcg_out_b9(s, B9_LGR, 13, args[1]); ++ tcg_out32(s, 0xa7090000 | (args[0] << 20)); /* lghi %ra0, 0 */ ++ tcg_out_b9(s, B9_SGR, args[0], 13); ++ break; ++ ++ case INDEX_op_mul_i32: ++ //fprintf(stderr,"op 0x%x mul_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ if (args[0] == args[1]) ++ 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_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]) { ++ tcg_out_b9(s, B9_MSGR, 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]) { ++ 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]) { ++ tcg_out_sh32(s, op, args[0], args[2], 0); ++ } ++ else ++ tcg_out_sh64(s, op2, args[0], args[1], args[2], 0); ++ } ++ break; ++ case INDEX_op_shr_i32: op = SH32_SRL; op2 = SH64_SRLG; goto do_shift32; ++ case INDEX_op_sar_i32: op = SH32_SRA; op2 = SH64_SRAG; goto do_shift32; ++ ++ case INDEX_op_shl_i64: ++ op = SH64_SLLG; ++do_shift64: ++ if (const_args[2]) { ++ tcg_out_sh64(s, op, args[0], args[1], SH64_REG_NONE, args[2]); ++ } ++ else { ++ tcg_out_sh64(s, op, args[0], args[1], args[2], 0); ++ } ++ break; ++ case INDEX_op_shr_i64: op = SH64_SRLG; goto do_shift64; ++ case INDEX_op_sar_i64: op = SH64_SRAG; goto do_shift64; ++ ++ case INDEX_op_br: ++ //fprintf(stderr,"op 0x%x br 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); ++ l = &s->labels[args[0]]; ++ if (l->has_value) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, l->u.value); ++ } ++ else { ++ /* larl %r13, ... */ ++ tcg_out16(s, 0xc0d0); ++ tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, args[0], -2); ++ s->code_ptr += 4; ++ } ++ tcg_out_rr(s, RR_BASR, TCG_REG_R13, TCG_REG_R13); ++ break; ++ case INDEX_op_brcond_i64: ++ //fprintf(stderr,"op 0x%x brcond_i64 0x%lx 0x%lx (c %d) 0x%lx\n",opc,args[0],args[1],const_args[1],args[2]); ++ if (args[2] > TCG_COND_GT) { /* unsigned */ ++ tcg_out_b9(s, B9_CLGR, args[0], args[1]); /* clgr %ra0, %ra1 */ ++ } ++ else { /* signed */ ++ tcg_out_b9(s, B9_CGR, args[0], args[1]); /* cgr %ra0, %ra1 */ ++ } ++ goto do_brcond; ++ case INDEX_op_brcond_i32: ++ //fprintf(stderr,"op 0x%x brcond_i32 0x%lx 0x%lx (c %d) 0x%lx\n",opc,args[0],args[1],const_args[1],args[2]); ++ if (args[2] > TCG_COND_GT) { /* unsigned */ ++ tcg_out_rr(s, RR_CLR, args[0], args[1]); /* clr %ra0, %ra1 */ ++ } ++ else { /* signed */ ++ tcg_out_rr(s, RR_CR, args[0], args[1]); /* cr %ra0, %ra1 */ ++ } ++do_brcond: ++ l = &s->labels[args[3]]; ++ if (l->has_value) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, l->u.value); ++ } ++ else { ++ /* larl %r13, ... */ ++ tcg_out16(s, 0xc0d0); ++ tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, args[3], -2); ++ s->code_ptr += 4; ++ } ++ tcg_out16(s, 0x070d | (tcg_cond_to_s390_cond[args[2]] << 4)); /* bcr cond,%r13 */ ++ break; ++ ++ case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); break; ++ case INDEX_op_qemu_ld8s: tcg_out_qemu_ld(s, args, 0 | 4); break; ++ case INDEX_op_qemu_ld16u: tcg_out_qemu_ld(s, args, 1); break; ++ case INDEX_op_qemu_ld16s: tcg_out_qemu_ld(s, args, 1 | 4); break; ++ case INDEX_op_qemu_ld32u: tcg_out_qemu_ld(s, args, 2); break; ++ case INDEX_op_qemu_ld32s: tcg_out_qemu_ld(s, args, 2 | 4); break; ++ case INDEX_op_qemu_ld64: tcg_out_qemu_ld(s, args, 3); break; ++ case INDEX_op_qemu_st8: tcg_out_qemu_st(s, args, 0); break; ++ case INDEX_op_qemu_st16: tcg_out_qemu_st(s, args, 1); break; ++ case INDEX_op_qemu_st32: tcg_out_qemu_st(s, args, 2); break; ++ case INDEX_op_qemu_st64: tcg_out_qemu_st(s, args, 3); break; ++ ++ default: ++ fprintf(stderr,"unimplemented opc 0x%x\n",opc); ++ tcg_abort(); ++ } + } + ++static const TCGTargetOpDef s390_op_defs[] = { ++ { INDEX_op_exit_tb, { } }, ++ { INDEX_op_goto_tb, { } }, ++ { INDEX_op_call, { "ri" } }, ++ { INDEX_op_jmp, { "ri" } }, ++ { INDEX_op_br, { } }, ++ ++ { INDEX_op_mov_i32, { "r", "r" } }, ++ { INDEX_op_movi_i32, { "r" } }, ++ ++ { INDEX_op_ld8u_i32, { "r", "r" } }, ++ { INDEX_op_ld8s_i32, { "r", "r" } }, ++ { INDEX_op_ld16u_i32, { "r", "r" } }, ++ { INDEX_op_ld16s_i32, { "r", "r" } }, ++ { INDEX_op_ld_i32, { "r", "r" } }, ++ { INDEX_op_st8_i32, { "r", "r" } }, ++ { INDEX_op_st16_i32, { "r", "r" } }, ++ { INDEX_op_st_i32, { "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" } }, ++ { INDEX_op_neg_i32, { "r", "r" } }, ++ ++ { INDEX_op_shl_i32, { "r", "r", "Ri" } }, ++ { INDEX_op_shr_i32, { "r", "r", "Ri" } }, ++ { INDEX_op_sar_i32, { "r", "r", "Ri" } }, ++ ++ { INDEX_op_brcond_i32, { "r", "r" } }, ++ ++ { INDEX_op_qemu_ld8u, { "r", "L" } }, ++ { INDEX_op_qemu_ld8s, { "r", "L" } }, ++ { INDEX_op_qemu_ld16u, { "r", "L" } }, ++ { INDEX_op_qemu_ld16s, { "r", "L" } }, ++ { INDEX_op_qemu_ld32u, { "r", "L" } }, ++ { INDEX_op_qemu_ld32s, { "r", "L" } }, ++ ++ { INDEX_op_qemu_st8, { "S", "S" } }, ++ { INDEX_op_qemu_st16, { "S", "S" } }, ++ { INDEX_op_qemu_st32, { "S", "S" } }, ++ ++#if defined(__s390x__) ++ { INDEX_op_mov_i64, { "r", "r" } }, ++ { INDEX_op_movi_i64, { "r" } }, ++ ++ { INDEX_op_ld8u_i64, { "r", "r" } }, ++ { INDEX_op_ld8s_i64, { "r", "r" } }, ++ { INDEX_op_ld16u_i64, { "r", "r" } }, ++ { INDEX_op_ld16s_i64, { "r", "r" } }, ++ { INDEX_op_ld32u_i64, { "r", "r" } }, ++ { INDEX_op_ld32s_i64, { "r", "r" } }, ++ { INDEX_op_ld_i64, { "r", "r" } }, ++ ++ { INDEX_op_st8_i64, { "r", "r" } }, ++ { INDEX_op_st16_i64, { "r", "r" } }, ++ { INDEX_op_st32_i64, { "r", "r" } }, ++ { INDEX_op_st_i64, { "r", "r" } }, ++ ++ { INDEX_op_qemu_ld64, { "L", "L" } }, ++ { INDEX_op_qemu_st64, { "S", "S" } }, ++ ++ { INDEX_op_add_i64, { "r", "r", "r" } }, ++ { INDEX_op_mul_i64, { "r", "r", "r" } }, ++ { INDEX_op_sub_i64, { "r", "r", "r" } }, ++ ++ { INDEX_op_and_i64, { "r", "r", "r" } }, ++ { INDEX_op_or_i64, { "r", "r", "r" } }, ++ { INDEX_op_xor_i64, { "r", "r", "r" } }, ++ { INDEX_op_neg_i64, { "r", "r" } }, ++ ++ { INDEX_op_shl_i64, { "r", "r", "Ri" } }, ++ { INDEX_op_shr_i64, { "r", "r", "Ri" } }, ++ { INDEX_op_sar_i64, { "r", "r", "Ri" } }, ++ ++ { INDEX_op_brcond_i64, { "r", "r" } }, ++#endif ++ ++ { -1 }, ++}; ++ + void tcg_target_init(TCGContext *s) + { +- /* gets called with KVM */ ++ /* fail safe */ ++ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) ++ tcg_abort(); ++ ++ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); ++ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); ++ tcg_regset_set32(tcg_target_call_clobber_regs, 0, ++ (1 << TCG_REG_R0) | ++ (1 << TCG_REG_R1) | ++ (1 << TCG_REG_R2) | ++ (1 << TCG_REG_R3) | ++ (1 << TCG_REG_R4) | ++ (1 << TCG_REG_R5) | ++ (1 << TCG_REG_R14)); /* link register */ ++ ++ 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); + } + + void tcg_target_qemu_prologue(TCGContext *s) + { +- /* gets called with KVM */ ++ tcg_out16(s,0xeb6f);tcg_out32(s,0xf0300024); /* stmg %r6,%r15,48(%r15) (save registers) */ ++ tcg_out32(s, 0xa7fbff60); /* aghi %r15,-160 (stack frame) */ ++ tcg_out16(s,0x7f2); /* br %r2 (go to TB) */ ++ tb_ret_addr = s->code_ptr; ++ tcg_out16(s,0xeb6f);tcg_out32(s, 0xf0d00004); /* lmg %r6,%r15,208(%r15) (restore registers) */ ++ tcg_out16(s,0x7fe); /* br %r14 (return) */ + } + + static inline void tcg_out_mov(TCGContext *s, int ret, int arg) + { +- tcg_abort(); ++ tcg_out_b9(s, B9_LGR, ret, arg); + } + + static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h +index 91b931d..6bae3c2 100644 +--- a/tcg/s390/tcg-target.h ++++ b/tcg/s390/tcg-target.h +@@ -25,6 +25,12 @@ + + #define TCG_TARGET_REG_BITS 64 + #define TCG_TARGET_WORDS_BIGENDIAN ++#define TCG_TARGET_HAS_div_i32 ++#undef TCG_TARGET_HAS_div_i64 ++#undef TCG_TARGET_HAS_bswap32_i32 ++#define TCG_TARGET_HAS_neg_i32 ++#define TCG_TARGET_HAS_neg_i64 ++#undef TCG_TARGET_STACK_GROWSUP + + enum { + TCG_REG_R0 = 0, +@@ -67,3 +73,6 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) + #error not implemented + #endif + } ++ TCG_AREG1 = TCG_REG_R7, ++ TCG_AREG2 = TCG_REG_R8, ++ TCG_AREG3 = TCG_REG_R9, +diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h +index faf2e8b..c1b4710 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 b7f3fd7..5dcdeba 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 */ +@@ -109,6 +110,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 3c0e296..8eb60f8 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -1930,6 +1930,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.4.2 + 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 deleted file mode 100644 index 1996efd3..00000000 --- a/0019-Rewrite-mmap_find_vma-to-work-fine-on-64-bit-hosts.patch +++ /dev/null @@ -1,125 +0,0 @@ -From d7f01e455acae19ef780e29417ffba50ca90ffde 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 deleted file mode 100644 index 7b5f3dd1..00000000 --- a/0020-TCG-sync-op-32-bit-targets-fixed.patch +++ /dev/null @@ -1,82 +0,0 @@ -From ea0b70265614b950d1e2ed48a9581ecd5e63ac97 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 7cb6934..cfd6160 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 deleted file mode 100644 index e8d1c93f..00000000 --- a/0021-S-390-CPU-emulation.patch +++ /dev/null @@ -1,4753 +0,0 @@ -From 5567f8f0512bc4fa8a31b4691d9fce49eaf40bb9 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 deleted file mode 100644 index 3baff1cd..00000000 --- a/0022-S-390-host-target-build-system-support.patch +++ /dev/null @@ -1,127 +0,0 @@ -From fba6b2002b323519c4bb03079479de5bc3819642 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 4f79498..e0874b5 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 - ;; - *) -@@ -1837,7 +1842,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 -@@ -1997,6 +2002,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 -@@ -2065,7 +2074,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/0023-S-390-host-support-for-TCG.patch b/0023-S-390-host-support-for-TCG.patch deleted file mode 100644 index 35028cb9..00000000 --- a/0023-S-390-host-support-for-TCG.patch +++ /dev/null @@ -1,1486 +0,0 @@ -From 3a42668021f934d0b36127c2c14479ae5cf62e8f 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", -+ "elf64-s390") -+OUTPUT_ARCH(s390:64-bit) -+ENTRY(_start) -+SEARCH_DIR("/usr/s390x-suse-linux/lib64"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/s390x-suse-linux/lib"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); -+SECTIONS -+{ -+ /* Read-only sections, merged into text segment: */ -+ PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; -+ .interp : { *(.interp) } -+ .note.gnu.build-id : { *(.note.gnu.build-id) } -+ .hash : { *(.hash) } -+ .gnu.hash : { *(.gnu.hash) } -+ .dynsym : { *(.dynsym) } -+ .dynstr : { *(.dynstr) } -+ .gnu.version : { *(.gnu.version) } -+ .gnu.version_d : { *(.gnu.version_d) } -+ .gnu.version_r : { *(.gnu.version_r) } -+ .rel.init : { *(.rel.init) } -+ .rela.init : { *(.rela.init) } -+ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } -+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } -+ .rel.fini : { *(.rel.fini) } -+ .rela.fini : { *(.rela.fini) } -+ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } -+ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } -+ .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } -+ .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } -+ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } -+ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } -+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } -+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } -+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } -+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } -+ .rel.ctors : { *(.rel.ctors) } -+ .rela.ctors : { *(.rela.ctors) } -+ .rel.dtors : { *(.rel.dtors) } -+ .rela.dtors : { *(.rela.dtors) } -+ .rel.got : { *(.rel.got) } -+ .rela.got : { *(.rela.got) } -+ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } -+ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } -+ .rel.plt : { *(.rel.plt) } -+ .rela.plt : { *(.rela.plt) } -+ .init : -+ { -+ KEEP (*(.init)) -+ } =0x07070707 -+ .plt : { *(.plt) } -+ .text : -+ { -+ *(.text .stub .text.* .gnu.linkonce.t.*) -+ /* .gnu.warning sections are handled specially by elf32.em. */ -+ *(.gnu.warning) -+ } =0x07070707 -+ .fini : -+ { -+ KEEP (*(.fini)) -+ } =0x07070707 -+ PROVIDE (__etext = .); -+ PROVIDE (_etext = .); -+ PROVIDE (etext = .); -+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } -+ .rodata1 : { *(.rodata1) } -+ .eh_frame_hdr : { *(.eh_frame_hdr) } -+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } -+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } -+ /* 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 (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); -+ /* Exception handling */ -+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } -+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } -+ /* Thread Local Storage sections */ -+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } -+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } -+ .preinit_array : -+ { -+ PROVIDE_HIDDEN (__preinit_array_start = .); -+ KEEP (*(.preinit_array)) -+ PROVIDE_HIDDEN (__preinit_array_end = .); -+ } -+ .init_array : -+ { -+ PROVIDE_HIDDEN (__init_array_start = .); -+ KEEP (*(SORT(.init_array.*))) -+ KEEP (*(.init_array)) -+ PROVIDE_HIDDEN (__init_array_end = .); -+ } -+ .fini_array : -+ { -+ PROVIDE_HIDDEN (__fini_array_start = .); -+ KEEP (*(.fini_array)) -+ KEEP (*(SORT(.fini_array.*))) -+ PROVIDE_HIDDEN (__fini_array_end = .); -+ } -+ .ctors : -+ { -+ /* gcc uses crtbegin.o to find the start of -+ the constructors, so we make sure it is -+ first. Because this is a wildcard, it -+ doesn't matter if the user does not -+ actually link against crtbegin.o; the -+ linker won't look for a file to match a -+ wildcard. The wildcard also means that it -+ doesn't matter which directory crtbegin.o -+ is in. */ -+ KEEP (*crtbegin.o(.ctors)) -+ KEEP (*crtbegin?.o(.ctors)) -+ /* We don't want to include the .ctor section from -+ the crtend.o file until after the sorted ctors. -+ The .ctor section from the crtend file contains the -+ end of ctors marker and it must be last */ -+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) -+ KEEP (*(SORT(.ctors.*))) -+ KEEP (*(.ctors)) -+ } -+ .dtors : -+ { -+ KEEP (*crtbegin.o(.dtors)) -+ KEEP (*crtbegin?.o(.dtors)) -+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) -+ KEEP (*(SORT(.dtors.*))) -+ KEEP (*(.dtors)) -+ } -+ .jcr : { KEEP (*(.jcr)) } -+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } -+ .dynamic : { *(.dynamic) } -+ . = DATA_SEGMENT_RELRO_END (0, .); -+ .got : { *(.got.plt) *(.got) } -+ .data : -+ { -+ *(.data .data.* .gnu.linkonce.d.*) -+ SORT(CONSTRUCTORS) -+ } -+ .data1 : { *(.data1) } -+ _edata = .; PROVIDE (edata = .); -+ __bss_start = .; -+ .bss : -+ { -+ *(.dynbss) -+ *(.bss .bss.* .gnu.linkonce.b.*) -+ *(COMMON) -+ /* Align here to ensure that the .bss section occupies space up to -+ _end. Align after .bss to ensure correct alignment even if the -+ .bss section disappears because there are no input sections. -+ FIXME: Why do we need it? When there is no .bss section, we don't -+ pad the .data section. */ -+ . = ALIGN(. != 0 ? 64 / 8 : 1); -+ } -+ . = ALIGN(64 / 8); -+ . = ALIGN(64 / 8); -+ _end = .; PROVIDE (end = .); -+ . = DATA_SEGMENT_END (.); -+ /* Stabs debugging sections. */ -+ .stab 0 : { *(.stab) } -+ .stabstr 0 : { *(.stabstr) } -+ .stab.excl 0 : { *(.stab.excl) } -+ .stab.exclstr 0 : { *(.stab.exclstr) } -+ .stab.index 0 : { *(.stab.index) } -+ .stab.indexstr 0 : { *(.stab.indexstr) } -+ .comment 0 : { *(.comment) } -+ /* DWARF debug sections. -+ Symbols in the DWARF debugging sections are relative to the beginning -+ of the section so we begin them at 0. */ -+ /* DWARF 1 */ -+ .debug 0 : { *(.debug) } -+ .line 0 : { *(.line) } -+ /* GNU DWARF 1 extensions */ -+ .debug_srcinfo 0 : { *(.debug_srcinfo) } -+ .debug_sfnames 0 : { *(.debug_sfnames) } -+ /* DWARF 1.1 and DWARF 2 */ -+ .debug_aranges 0 : { *(.debug_aranges) } -+ .debug_pubnames 0 : { *(.debug_pubnames) } -+ /* DWARF 2 */ -+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } -+ .debug_abbrev 0 : { *(.debug_abbrev) } -+ .debug_line 0 : { *(.debug_line) } -+ .debug_frame 0 : { *(.debug_frame) } -+ .debug_str 0 : { *(.debug_str) } -+ .debug_loc 0 : { *(.debug_loc) } -+ .debug_macinfo 0 : { *(.debug_macinfo) } -+ /* SGI/MIPS DWARF 2 extensions */ -+ .debug_weaknames 0 : { *(.debug_weaknames) } -+ .debug_funcnames 0 : { *(.debug_funcnames) } -+ .debug_typenames 0 : { *(.debug_typenames) } -+ .debug_varnames 0 : { *(.debug_varnames) } -+ /* DWARF 3 */ -+ .debug_pubtypes 0 : { *(.debug_pubtypes) } -+ .debug_ranges 0 : { *(.debug_ranges) } -+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } -+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } -+} -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 -+ * -+ * Copyright (c) 2009 Ulrich Hecht -+ * -+ * 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. -+ */ -+ -+#ifndef NDEBUG -+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { -+ "%r0", -+ "%r1", -+ "%r2", -+ "%r3", -+ "%r4", -+ "%r5", -+ "%r6", -+ "%r7", -+ "%r8", -+ "%r9", -+ "%r10", -+ "%r11", -+ "%r12", -+ "%r13", -+ "%r14", -+ "%r15" -+}; -+#endif -+ -+static const int tcg_target_reg_alloc_order[] = { -+ TCG_REG_R6, -+ TCG_REG_R7, -+ TCG_REG_R8, -+ TCG_REG_R9, -+ TCG_REG_R10, -+ TCG_REG_R11, -+ TCG_REG_R12, -+ TCG_REG_R13, -+ TCG_REG_R14, -+ /* 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, -+ TCG_REG_R4, -+ TCG_REG_R5, -+}; -+ -+static const int tcg_target_call_iarg_regs[4] = { -+ TCG_REG_R2, TCG_REG_R3, TCG_REG_R4, TCG_REG_R5 -+}; -+static const int tcg_target_call_oarg_regs[2] = { -+ TCG_REG_R2, TCG_REG_R3 -+}; -+ -+static void patch_reloc(uint8_t *code_ptr, int type, -+ tcg_target_long value, tcg_target_long addend) -+{ -+ switch (type) { -+ case R_390_PC32DBL: -+ *(uint32_t*)code_ptr = (value - ((tcg_target_long)code_ptr + addend)) >> 1; -+ break; -+ default: -+ tcg_abort(); -+ break; -+ } -+} -+ -+/* maximum number of register used for input function arguments */ -+static inline int tcg_target_get_call_iarg_regs_count(int flags) -+{ -+ 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) -+{ -+ const char *ct_str; -+ -+ ct->ct |= TCG_CT_REG; -+ tcg_regset_set32(ct->u.regs, 0, 0xffff); -+ ct_str = *pct_str; -+ switch (ct_str[0]) { -+ case 'L': /* qemu_ld constraint */ -+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2); -+#ifdef CONFIG_SOFTMMU -+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); -+#endif -+ break; -+ case 'S': /* qemu_st constraint */ -+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2); -+#ifdef CONFIG_SOFTMMU -+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); -+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); -+#endif -+ break; -+ 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; -+ } -+ ct_str++; -+ *pct_str = ct_str; -+ -+ return 0; -+} -+ -+/* Test if a constant matches the constraint. */ -+static inline int tcg_target_const_match(tcg_target_long val, -+ const TCGArgConstraint *arg_ct) -+{ -+ int ct; -+ ct = arg_ct->ct; -+ if (ct & TCG_CT_CONST) -+ return 1; -+ 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 -+ -+#include "../../softmmu_defs.h" -+ -+static void *qemu_ld_helpers[4] = { -+ __ldb_mmu, -+ __ldw_mmu, -+ __ldl_mmu, -+ __ldq_mmu, -+}; -+ -+static void *qemu_st_helpers[4] = { -+ __stb_mmu, -+ __stw_mmu, -+ __stl_mmu, -+ __stq_mmu, -+}; -+#endif -+ -+static uint8_t *tb_ret_addr; -+ -+/* signed/unsigned is handled by using COMPARE and COMPARE LOGICAL, -+ respectively */ -+static const uint8_t tcg_cond_to_s390_cond[10] = { -+ [TCG_COND_EQ] = 8, -+ [TCG_COND_LT] = 4, -+ [TCG_COND_LTU] = 4, -+ [TCG_COND_LE] = 8 | 4, -+ [TCG_COND_LEU] = 8 | 4, -+ [TCG_COND_GT] = 2, -+ [TCG_COND_GTU] = 2, -+ [TCG_COND_GE] = 8 | 2, -+ [TCG_COND_GEU] = 8 | 2, -+ [TCG_COND_NE] = 4 | 2 | 1, -+}; -+ -+/* emit load/store (and then some) instructions (E3 prefix) */ -+static inline void tcg_out_e3(TCGContext* s, int op, int r1, int r2, int disp) -+{ -+ tcg_out16(s, 0xe300 | (r1 << 4)); -+ tcg_out32(s, op | (r2 << 28) | ((disp & 0xfff) << 16) | ((disp >> 12) << 8)); -+} -+#define E3_LG 0x04 -+#define E3_LRVG 0x0f -+#define E3_LGF 0x14 -+#define E3_LGH 0x15 -+#define E3_LLGF 0x16 -+#define E3_LRV 0x1e -+#define E3_LRVH 0x1f -+#define E3_CG 0x20 -+#define E3_STG 0x24 -+#define E3_STRVG 0x2f -+#define E3_STRV 0x3e -+#define E3_STRVH 0x3f -+#define E3_STHY 0x70 -+#define E3_STCY 0x72 -+#define E3_LGB 0x77 -+#define E3_LLGC 0x90 -+#define E3_LLGH 0x91 -+ -+/* emit 64-bit register/register insns (B9 prefix) */ -+static inline void tcg_out_b9(TCGContext* s, int op, int r1, int r2) -+{ -+ tcg_out32(s, 0xb9000000 | (op << 16) | (r1 << 4) | r2); -+} -+#define B9_LGR 0x04 -+#define B9_AGR 0x08 -+#define B9_SGR 0x09 -+#define B9_MSGR 0x0c -+#define B9_LGFR 0x14 -+#define B9_LLGFR 0x16 -+#define B9_CGR 0x20 -+#define B9_CLGR 0x21 -+#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) -+{ -+ tcg_out16(s, (op << 8) | (r1 << 4) | r2); -+} -+#define RR_BASR 0x0d -+#define RR_NR 0x14 -+#define RR_CLR 0x15 -+#define RR_OR 0x16 -+#define RR_XR 0x17 -+#define RR_LR 0x18 -+#define RR_CR 0x19 -+#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) -+{ -+ tcg_out16(s, 0xeb00 | (r0 << 4) | r1); -+ tcg_out32(s, op | (r2 << 28) | ((imm & 0xfff) << 16) | ((imm >> 12) << 8)); -+} -+#define SH64_REG_NONE 0 /* use immediate only (not R0!) */ -+#define SH64_SRAG 0x0a -+#define SH64_SRLG 0x0c -+#define SH64_SLLG 0x0d -+ -+/* emit 32-bit shifts */ -+static inline void tcg_out_sh32(TCGContext* s, int op, int r0, int r1, int imm) -+{ -+ tcg_out32(s, 0x80000000 | (op << 24) | (r0 << 20) | (r1 << 12) | imm); -+} -+#define SH32_REG_NONE 0 /* use immediate only (not R0!) */ -+#define SH32_SRL 0x8 -+#define SH32_SLL 0x9 -+#define SH32_SRA 0xa -+ -+/* branch to relative address (long) */ -+static inline void tcg_out_brasl(TCGContext* s, int r, tcg_target_long raddr) -+{ -+ tcg_out16(s, 0xc005 | (r << 4)); -+ tcg_out32(s, raddr >> 1); -+} -+ -+/* store 8/16/32 bits */ -+static inline void tcg_out_store(TCGContext* s, int op, int r0, int r1, int off) -+{ -+ tcg_out32(s, (op << 24) | (r0 << 20) | (r1 << 12) | off); -+} -+#define ST_STH 0x40 -+#define ST_STC 0x42 -+#define ST_ST 0x50 -+ -+/* load a register with an immediate value */ -+static inline void tcg_out_movi(TCGContext *s, TCGType type, -+ 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 */ -+ /* lghi %rret, arg */ -+ tcg_out32(s, 0xa7090000 | (ret << 20) | (arg & 0xffff)); -+ } -+ else if (!(arg & 0xffffffffffff0000UL)) { -+ /* llill %rret, arg */ -+ tcg_out32(s, 0xa50f0000 | (ret << 20) | arg); -+ } -+ 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 & 0xffffffff) >> 16)); -+ } -+ else { -+ /* branch over constant and store its address in R13 */ -+ tcg_out_brasl(s, TCG_REG_R13, 14); -+ /* 64-bit constant */ -+ tcg_out32(s,arg >> 32); -+ tcg_out32(s,arg); -+ /* load constant to ret */ -+ tcg_out_e3(s, E3_LG, ret, TCG_REG_R13, 0); -+ } -+} -+ -+/* load data without address translation or endianness conversion */ -+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, -+ int arg1, tcg_target_long arg2) -+{ -+ int op; -+ //fprintf(stderr,"tcg_out_ld type %d arg %d arg1 %d arg2 %ld\n",type,arg,arg1,arg2); -+ -+ if (type == TCG_TYPE_I32) op = E3_LLGF; /* 32-bit zero-extended */ -+ else op = E3_LG; /* 64-bit */ -+ -+ 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 */ -+ } -+ else { -+ tcg_out_e3(s, op, arg, arg1, arg2); /* load the data */ -+ } -+} -+ -+/* load data with address translation (if applicable) and endianness conversion */ -+static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc) -+{ -+ int addr_reg, data_reg, mem_index, s_bits; -+#if defined(CONFIG_SOFTMMU) -+ uint16_t *label1_ptr, *label2_ptr; -+#endif -+ -+ data_reg = *args++; -+ addr_reg = *args++; -+ mem_index = *args; -+ -+ s_bits = opc & 3; -+ -+ int arg0 = TCG_REG_R2; -+#ifdef CONFIG_SOFTMMU -+ int arg1 = TCG_REG_R3; -+#endif -+ -+ /* fprintf(stderr,"tcg_out_qemu_ld opc %d data_reg %d addr_reg %d mem_index %d s_bits %d\n", -+ opc, data_reg, addr_reg, mem_index, s_bits); */ -+ -+#ifdef CONFIG_SOFTMMU -+ tcg_out_b9(s, B9_LGR, arg1, addr_reg); -+ tcg_out_b9(s, B9_LGR, arg0, addr_reg); -+ -+ tcg_out_sh64(s, SH64_SRLG, arg1, addr_reg, SH64_REG_NONE, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); -+ tcg_out_b9(s, B9_NGR, arg0, TCG_REG_R13); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); -+ tcg_out_b9(s, B9_NGR, arg1, TCG_REG_R13); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); -+ tcg_out_b9(s, B9_AGR, arg1, TCG_REG_R13); -+ -+ tcg_out_b9(s, B9_AGR, arg1, TCG_AREG0); -+ -+ tcg_out_e3(s, E3_CG, arg0, arg1, 0); -+ -+ label1_ptr = (uint16_t*)s->code_ptr; -+ 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) { -+ 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); -+ break; -+ case 1 | 4: -+ tcg_out_sh64(s, SH64_SLLG, data_reg, arg0, SH64_REG_NONE, 48); -+ tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 48); -+ break; -+ case 2 | 4: -+ tcg_out_b9(s, B9_LGFR, data_reg, arg0); -+ break; -+ case 0: case 1: case 2: case 3: default: -+ /* unsigned -> just copy */ -+ tcg_out_b9(s, B9_LGR, data_reg, arg0); -+ break; -+ } -+ -+ /* jump to label2 (end) */ -+ label2_ptr = (uint16_t*)s->code_ptr; -+ tcg_out32(s, 0xa7d50000); /* bras %r13, label2 */ -+ -+ /* this is label1, patch branch */ -+ *(label1_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label1_ptr) >> 1; -+ -+ tcg_out_e3(s, E3_LG, arg1, arg1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read)); -+ -+#if TARGET_LONG_BITS == 32 -+ /* zero upper 32 bits */ -+ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); -+#else -+ /* just copy */ -+ tcg_out_b9(s, B9_LGR, arg0, addr_reg); -+#endif -+ tcg_out_b9(s, B9_AGR, arg0, arg1); -+ -+#else /* CONFIG_SOFTMMU */ -+ /* user mode, no address translation required */ -+ arg0 = addr_reg; -+#endif -+ -+ switch (opc) { -+ case 0: /* unsigned byte */ -+ tcg_out_e3(s, E3_LLGC, data_reg, arg0, 0); -+ break; -+ case 0 | 4: /* signed byte */ -+ tcg_out_e3(s, E3_LGB, data_reg, arg0, 0); -+ break; -+ case 1: /* unsigned short */ -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_LLGH, data_reg, arg0, 0); -+#else -+ /* swapped unsigned halfword load with upper bits zeroed */ -+ tcg_out_e3(s, E3_LRVH, data_reg, arg0, 0); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, 0xffffL); -+ tcg_out_b9(s, B9_NGR, data_reg, 13); -+#endif -+ break; -+ case 1 | 4: /* signed short */ -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_LGH, data_reg, arg0, 0); -+#else -+ /* swapped sign-extended halfword load */ -+ tcg_out_e3(s, E3_LRVH, data_reg, arg0, 0); -+ tcg_out_sh64(s, SH64_SLLG, data_reg, data_reg, SH64_REG_NONE, 48); -+ tcg_out_sh64(s, SH64_SRAG, data_reg, data_reg, SH64_REG_NONE, 48); -+#endif -+ break; -+ case 2: /* unsigned int */ -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_LLGF, data_reg, arg0, 0); -+#else -+ /* swapped unsigned int load with upper bits zeroed */ -+ tcg_out_e3(s, E3_LRV, data_reg, arg0, 0); -+ tcg_out_b9(s, B9_LLGFR, data_reg, data_reg); -+#endif -+ break; -+ case 2 | 4: /* signed int */ -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_LGF, data_reg, arg0, 0); -+#else -+ /* swapped sign-extended int load */ -+ tcg_out_e3(s, E3_LRV, data_reg, arg0, 0); -+ tcg_out_b9(s, B9_LGFR, data_reg, data_reg); -+#endif -+ break; -+ case 3: /* long (64 bit) */ -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_LG, data_reg, arg0, 0); -+#else -+ tcg_out_e3(s, E3_LRVG, data_reg, arg0, 0); -+#endif -+ break; -+ default: -+ tcg_abort(); -+ } -+ -+#ifdef CONFIG_SOFTMMU -+ /* this is label2, patch branch */ -+ *(label2_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label2_ptr) >> 1; -+#endif -+} -+ -+static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc) -+{ -+ int addr_reg, data_reg, mem_index, s_bits; -+#if defined(CONFIG_SOFTMMU) -+ uint16_t *label1_ptr, *label2_ptr; -+#endif -+ -+ data_reg = *args++; -+ addr_reg = *args++; -+ mem_index = *args; -+ -+ s_bits = opc; -+ -+ int arg0 = TCG_REG_R2; -+#ifdef CONFIG_SOFTMMU -+ int arg1 = TCG_REG_R3; -+ int arg2 = TCG_REG_R4; -+#endif -+ -+ /* fprintf(stderr,"tcg_out_qemu_st opc %d data_reg %d addr_reg %d mem_index %d s_bits %d\n", -+ 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); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); -+ tcg_out_b9(s, B9_NGR, arg0, TCG_REG_R13); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); -+ tcg_out_b9(s, B9_NGR, arg1, TCG_REG_R13); -+ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); -+ tcg_out_b9(s, B9_AGR, arg1, TCG_REG_R13); -+ -+ tcg_out_b9(s, B9_AGR, arg1, TCG_AREG0); -+ -+ 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 */ -+ -+ /* call store helper */ -+ tcg_out_b9(s, B9_LGR, arg1, data_reg); -+ tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (tcg_target_ulong)qemu_st_helpers[s_bits]); -+ tcg_out_rr(s, RR_BASR, TCG_REG_R14, TCG_REG_R13); -+ -+ /* jump to label2 (end) */ -+ label2_ptr = (uint16_t*)s->code_ptr; -+ tcg_out32(s, 0xa7d50000); /* bras %r13, label2 */ -+ -+ /* this is label1, patch branch */ -+ *(label1_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label1_ptr) >> 1; -+ -+ tcg_out_e3(s, E3_LG, arg1, arg1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write)); -+ -+#if TARGET_LONG_BITS == 32 -+ /* zero upper 32 bits */ -+ tcg_out_b9(s, B9_LLGFR, arg0, addr_reg); -+#else -+ /* just copy */ -+ tcg_out_b9(s, B9_LGR, arg0, addr_reg); -+#endif -+ tcg_out_b9(s, B9_AGR, arg0, arg1); -+ -+#else /* CONFIG_SOFTMMU */ -+ /* user mode, no address translation required */ -+ arg0 = addr_reg; -+#endif -+ -+ 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); -+#else -+ tcg_out_e3(s, E3_STRVH, data_reg, arg0, 0); -+#endif -+ break; -+ case 2: -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_store(s, ST_ST, data_reg, arg0, 0); -+#else -+ tcg_out_e3(s, E3_STRV, data_reg, arg0, 0); -+#endif -+ break; -+ case 3: -+#ifdef TARGET_WORDS_BIGENDIAN -+ tcg_out_e3(s, E3_STG, data_reg, arg0, 0); -+#else -+ tcg_out_e3(s, E3_STRVG, data_reg, arg0, 0); -+#endif -+ break; -+ default: -+ tcg_abort(); -+ } -+ -+#ifdef CONFIG_SOFTMMU -+ /* this is label2, patch branch */ -+ *(label2_ptr + 1) = ((unsigned long)s->code_ptr - (unsigned long)label2_ptr) >> 1; -+#endif -+} -+ -+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, -+ int arg1, tcg_target_long arg2) -+{ -+ //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) { -+ 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); -+ } -+ else tcg_out_store(s, ST_ST, arg, arg1, arg2); -+ } -+ else { -+ if (((long)arg2) < -0x80000 || ((long)arg2) > 0x7ffff) tcg_abort(); -+ tcg_out_e3(s, E3_STG, arg, arg1, arg2); -+ } -+} -+ -+static inline void tcg_out_op(TCGContext *s, int opc, -+ const TCGArg *args, const int *const_args) -+{ -+ TCGLabel* l; -+ int op; -+ int op2; -+ //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]); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]); /* return value */ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (unsigned long)tb_ret_addr); -+ tcg_out16(s,0x7fd); /* br %r13 */ -+ 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) { -+ tcg_abort(); -+ } -+ else { -+ tcg_target_long off = ((tcg_target_long)(s->tb_next + args[0]) - (tcg_target_long)s->code_ptr) >> 1; -+ if (off > -0x80000000L && off < 0x7fffffffL) { /* load address relative to PC */ -+ /* larl %r13, off */ -+ tcg_out16(s,0xc0d0); tcg_out32(s,off); -+ } -+ else { /* too far for larl */ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, (tcg_target_long)(s->tb_next + args[0])); -+ } -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R13, TCG_REG_R13, 0); /* load address stored at s->tb_next + args[0] */ -+ tcg_out_rr(s, RR_BASR, TCG_REG_R13, TCG_REG_R13); /* and go there */ -+ } -+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; -+ 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]) { -+ 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); -+ tcg_abort(); // untested -+ } -+ else { /* too far for a relative call, load full address */ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, args[0]); -+ tcg_out_rr(s, RR_BASR, TCG_REG_R14, TCG_REG_R13); -+ } -+ } -+ else { /* call function in register args[0] */ -+ tcg_out_rr(s, RR_BASR, TCG_REG_R14, args[0]); -+ } -+ break; -+ case INDEX_op_jmp: -+ fprintf(stderr,"op 0x%x jmp 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ tcg_abort(); -+ break; -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ //fprintf(stderr,"op 0x%x ld8u_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { -+ tcg_out_e3(s, E3_LLGC, args[0], args[1], args[2]); -+ } -+ else { /* displacement too large, have to calculate address manually */ -+ tcg_abort(); -+ } -+ break; -+ case INDEX_op_ld8s_i32: -+ fprintf(stderr,"op 0x%x ld8s_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ tcg_abort(); -+ break; -+ case INDEX_op_ld16u_i32: -+ fprintf(stderr,"op 0x%x ld16u_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { -+ tcg_out_e3(s, E3_LLGH, args[0], args[1], args[2]); -+ } -+ else { /* displacement too large, have to calculate address manually */ -+ tcg_abort(); -+ } -+ break; -+ case INDEX_op_ld16s_i32: -+ fprintf(stderr,"op 0x%x ld16s_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ tcg_abort(); -+ break; -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld32u_i64: -+ 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) { -+ 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) */ -+ } -+ else { -+ tcg_out_e3(s, E3_LGF, args[0], args[1], args[2]); /* load the data (sign-extended) */ -+ } -+ break; -+ case INDEX_op_ld_i64: -+ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ 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) -+ tcg_out_store(s, ST_STC, args[0], args[1], args[2]); -+ 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 -+ } -+ else tcg_abort(); -+ break; -+ 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) -+ tcg_out_store(s, ST_STH, args[0], args[1], args[2]); -+ 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 -+ } -+ else tcg_abort(); -+ break; -+ case INDEX_op_st_i32: -+ case INDEX_op_st32_i64: -+ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_st_i64: -+ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_mov_i32: -+ fprintf(stderr,"op 0x%x mov_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ tcg_abort(); -+ break; -+ case INDEX_op_movi_i32: -+ fprintf(stderr,"op 0x%x movi_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ tcg_abort(); -+ break; -+ case INDEX_op_add_i32: -+ 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]) { -+ tcg_out_rr(s, RR_AR, args[0], args[1]); -+ } -+ else { -+ tcg_out_rr(s, RR_LR, args[0], args[1]); -+ tcg_out_rr(s, RR_AR, args[0], args[2]); -+ } -+ 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]) { -+ tcg_out_rr(s, RR_SR, args[1], args[2]); /* sr %ra0/1, %ra2 */ -+ } -+ 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 */ -+ } -+ else { -+ tcg_out_rr(s, RR_LR, args[0], args[1]); /* lr %ra0, %ra1 */ -+ tcg_out_rr(s, RR_SR, args[0], args[2]); /* sr %ra0, %ra2 */ -+ } -+ break; -+ -+ 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]) { -+ tcg_out_b9(s, B9_SGR, args[1], args[2]); /* sgr %ra0/1, %ra2 */ -+ } -+ 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 */ -+ } -+ else { -+ tcg_out_b9(s, B9_LGR, args[0], args[1]); /* lgr %ra0, %ra1 */ -+ tcg_out_b9(s, B9_SGR, args[0], args[2]); /* sgr %ra0, %ra2 */ -+ } -+ 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]) { -+ tcg_out_b9(s, B9_AGR, args[1], args[2]); -+ } -+ else if (args[0] == args[2]) { -+ tcg_out_b9(s, B9_AGR, args[0], args[1]); -+ } -+ else { -+ tcg_out_b9(s, B9_LGR, args[0], args[1]); -+ tcg_out_b9(s, B9_AGR, args[0], args[2]); -+ } -+ break; -+ -+ case INDEX_op_and_i32: -+ op = RR_NR; -+do_logic_i32: -+ if (args[0] == args[1]) { -+ tcg_out_rr(s, op, args[1], args[2]); /* xr %ra0/1, %ra2 */ -+ } -+ 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 */ -+ } -+ break; -+ case INDEX_op_or_i32: op = RR_OR; goto do_logic_i32; -+ case INDEX_op_xor_i32: op = RR_XR; goto do_logic_i32; -+ -+ case INDEX_op_and_i64: -+ //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]) { -+ tcg_out_b9(s, op, 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]); -+ } -+ break; -+ case INDEX_op_or_i64: op = B9_OGR; goto do_logic_i64; -+ case INDEX_op_xor_i64: op = B9_XGR; goto do_logic_i64; -+ -+ case INDEX_op_neg_i32: -+ //fprintf(stderr,"op 0x%x neg_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ /* FIXME: optimize args[0] != args[1] case */ -+ tcg_out_rr(s, RR_LR, 13, args[1]); -+ tcg_out32(s, 0xa7090000 | (args[0] << 20)); /* lghi %ra0, 0 */ -+ tcg_out_rr(s, RR_SR, args[0], 13); -+ break; -+ case INDEX_op_neg_i64: -+ //fprintf(stderr,"op 0x%x neg_i64 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ /* FIXME: optimize args[0] != args[1] case */ -+ tcg_out_b9(s, B9_LGR, 13, args[1]); -+ tcg_out32(s, 0xa7090000 | (args[0] << 20)); /* lghi %ra0, 0 */ -+ tcg_out_b9(s, B9_SGR, args[0], 13); -+ break; -+ -+ case INDEX_op_mul_i32: -+ //fprintf(stderr,"op 0x%x mul_i32 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ if (args[0] == args[1]) -+ 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_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]) { -+ tcg_out_b9(s, B9_MSGR, 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]) { -+ 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]) { -+ tcg_out_sh32(s, op, args[0], args[2], 0); -+ } -+ else -+ tcg_out_sh64(s, op2, args[0], args[1], args[2], 0); -+ } -+ break; -+ case INDEX_op_shr_i32: op = SH32_SRL; op2 = SH64_SRLG; goto do_shift32; -+ case INDEX_op_sar_i32: op = SH32_SRA; op2 = SH64_SRAG; goto do_shift32; -+ -+ case INDEX_op_shl_i64: -+ op = SH64_SLLG; -+do_shift64: -+ if (const_args[2]) { -+ tcg_out_sh64(s, op, args[0], args[1], SH64_REG_NONE, args[2]); -+ } -+ else { -+ tcg_out_sh64(s, op, args[0], args[1], args[2], 0); -+ } -+ break; -+ case INDEX_op_shr_i64: op = SH64_SRLG; goto do_shift64; -+ case INDEX_op_sar_i64: op = SH64_SRAG; goto do_shift64; -+ -+ case INDEX_op_br: -+ //fprintf(stderr,"op 0x%x br 0x%lx 0x%lx 0x%lx\n",opc,args[0],args[1],args[2]); -+ l = &s->labels[args[0]]; -+ if (l->has_value) { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, l->u.value); -+ } -+ else { -+ /* larl %r13, ... */ -+ tcg_out16(s, 0xc0d0); -+ tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, args[0], -2); -+ s->code_ptr += 4; -+ } -+ tcg_out_rr(s, RR_BASR, TCG_REG_R13, TCG_REG_R13); -+ break; -+ case INDEX_op_brcond_i64: -+ //fprintf(stderr,"op 0x%x brcond_i64 0x%lx 0x%lx (c %d) 0x%lx\n",opc,args[0],args[1],const_args[1],args[2]); -+ if (args[2] > TCG_COND_GT) { /* unsigned */ -+ tcg_out_b9(s, B9_CLGR, args[0], args[1]); /* clgr %ra0, %ra1 */ -+ } -+ else { /* signed */ -+ tcg_out_b9(s, B9_CGR, args[0], args[1]); /* cgr %ra0, %ra1 */ -+ } -+ goto do_brcond; -+ case INDEX_op_brcond_i32: -+ //fprintf(stderr,"op 0x%x brcond_i32 0x%lx 0x%lx (c %d) 0x%lx\n",opc,args[0],args[1],const_args[1],args[2]); -+ if (args[2] > TCG_COND_GT) { /* unsigned */ -+ tcg_out_rr(s, RR_CLR, args[0], args[1]); /* clr %ra0, %ra1 */ -+ } -+ else { /* signed */ -+ tcg_out_rr(s, RR_CR, args[0], args[1]); /* cr %ra0, %ra1 */ -+ } -+do_brcond: -+ l = &s->labels[args[3]]; -+ if (l->has_value) { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, l->u.value); -+ } -+ else { -+ /* larl %r13, ... */ -+ tcg_out16(s, 0xc0d0); -+ tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, args[3], -2); -+ s->code_ptr += 4; -+ } -+ tcg_out16(s, 0x070d | (tcg_cond_to_s390_cond[args[2]] << 4)); /* bcr cond,%r13 */ -+ break; -+ -+ case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); break; -+ case INDEX_op_qemu_ld8s: tcg_out_qemu_ld(s, args, 0 | 4); break; -+ case INDEX_op_qemu_ld16u: tcg_out_qemu_ld(s, args, 1); break; -+ case INDEX_op_qemu_ld16s: tcg_out_qemu_ld(s, args, 1 | 4); break; -+ case INDEX_op_qemu_ld32u: tcg_out_qemu_ld(s, args, 2); break; -+ case INDEX_op_qemu_ld32s: tcg_out_qemu_ld(s, args, 2 | 4); break; -+ case INDEX_op_qemu_ld64: tcg_out_qemu_ld(s, args, 3); break; -+ case INDEX_op_qemu_st8: tcg_out_qemu_st(s, args, 0); break; -+ case INDEX_op_qemu_st16: tcg_out_qemu_st(s, args, 1); break; -+ case INDEX_op_qemu_st32: tcg_out_qemu_st(s, args, 2); break; -+ case INDEX_op_qemu_st64: tcg_out_qemu_st(s, args, 3); break; -+ -+ default: -+ fprintf(stderr,"unimplemented opc 0x%x\n",opc); -+ tcg_abort(); -+ } -+} -+ -+static const TCGTargetOpDef s390_op_defs[] = { -+ { INDEX_op_exit_tb, { } }, -+ { INDEX_op_goto_tb, { } }, -+ { INDEX_op_call, { "ri" } }, -+ { INDEX_op_jmp, { "ri" } }, -+ { INDEX_op_br, { } }, -+ -+ { INDEX_op_mov_i32, { "r", "r" } }, -+ { INDEX_op_movi_i32, { "r" } }, -+ -+ { INDEX_op_ld8u_i32, { "r", "r" } }, -+ { INDEX_op_ld8s_i32, { "r", "r" } }, -+ { INDEX_op_ld16u_i32, { "r", "r" } }, -+ { INDEX_op_ld16s_i32, { "r", "r" } }, -+ { INDEX_op_ld_i32, { "r", "r" } }, -+ { INDEX_op_st8_i32, { "r", "r" } }, -+ { INDEX_op_st16_i32, { "r", "r" } }, -+ { INDEX_op_st_i32, { "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" } }, -+ { INDEX_op_neg_i32, { "r", "r" } }, -+ -+ { INDEX_op_shl_i32, { "r", "r", "Ri" } }, -+ { INDEX_op_shr_i32, { "r", "r", "Ri" } }, -+ { INDEX_op_sar_i32, { "r", "r", "Ri" } }, -+ -+ { INDEX_op_brcond_i32, { "r", "r" } }, -+ -+ { INDEX_op_qemu_ld8u, { "r", "L" } }, -+ { INDEX_op_qemu_ld8s, { "r", "L" } }, -+ { INDEX_op_qemu_ld16u, { "r", "L" } }, -+ { INDEX_op_qemu_ld16s, { "r", "L" } }, -+ { INDEX_op_qemu_ld32u, { "r", "L" } }, -+ { INDEX_op_qemu_ld32s, { "r", "L" } }, -+ -+ { INDEX_op_qemu_st8, { "S", "S" } }, -+ { INDEX_op_qemu_st16, { "S", "S" } }, -+ { INDEX_op_qemu_st32, { "S", "S" } }, -+ -+#if defined(__s390x__) -+ { INDEX_op_mov_i64, { "r", "r" } }, -+ { INDEX_op_movi_i64, { "r" } }, -+ -+ { INDEX_op_ld8u_i64, { "r", "r" } }, -+ { INDEX_op_ld8s_i64, { "r", "r" } }, -+ { INDEX_op_ld16u_i64, { "r", "r" } }, -+ { INDEX_op_ld16s_i64, { "r", "r" } }, -+ { INDEX_op_ld32u_i64, { "r", "r" } }, -+ { INDEX_op_ld32s_i64, { "r", "r" } }, -+ { INDEX_op_ld_i64, { "r", "r" } }, -+ -+ { INDEX_op_st8_i64, { "r", "r" } }, -+ { INDEX_op_st16_i64, { "r", "r" } }, -+ { INDEX_op_st32_i64, { "r", "r" } }, -+ { INDEX_op_st_i64, { "r", "r" } }, -+ -+ { INDEX_op_qemu_ld64, { "L", "L" } }, -+ { INDEX_op_qemu_st64, { "S", "S" } }, -+ -+ { INDEX_op_add_i64, { "r", "r", "r" } }, -+ { INDEX_op_mul_i64, { "r", "r", "r" } }, -+ { INDEX_op_sub_i64, { "r", "r", "r" } }, -+ -+ { INDEX_op_and_i64, { "r", "r", "r" } }, -+ { INDEX_op_or_i64, { "r", "r", "r" } }, -+ { INDEX_op_xor_i64, { "r", "r", "r" } }, -+ { INDEX_op_neg_i64, { "r", "r" } }, -+ -+ { INDEX_op_shl_i64, { "r", "r", "Ri" } }, -+ { INDEX_op_shr_i64, { "r", "r", "Ri" } }, -+ { INDEX_op_sar_i64, { "r", "r", "Ri" } }, -+ -+ { INDEX_op_brcond_i64, { "r", "r" } }, -+#endif -+ -+ { -1 }, -+}; -+ -+void tcg_target_init(TCGContext *s) -+{ -+ /* fail safe */ -+ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) -+ tcg_abort(); -+ -+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); -+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); -+ tcg_regset_set32(tcg_target_call_clobber_regs, 0, -+ (1 << TCG_REG_R0) | -+ (1 << TCG_REG_R1) | -+ (1 << TCG_REG_R2) | -+ (1 << TCG_REG_R3) | -+ (1 << TCG_REG_R4) | -+ (1 << TCG_REG_R5) | -+ (1 << TCG_REG_R14)); /* link register */ -+ -+ 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); -+} -+ -+void tcg_target_qemu_prologue(TCGContext *s) -+{ -+ tcg_out16(s,0xeb6f);tcg_out32(s,0xf0300024); /* stmg %r6,%r15,48(%r15) (save registers) */ -+ tcg_out32(s, 0xa7fbff60); /* aghi %r15,-160 (stack frame) */ -+ tcg_out16(s,0x7f2); /* br %r2 (go to TB) */ -+ tb_ret_addr = s->code_ptr; -+ tcg_out16(s,0xeb6f);tcg_out32(s, 0xf0d00004); /* lmg %r6,%r15,208(%r15) (restore registers) */ -+ tcg_out16(s,0x7fe); /* br %r14 (return) */ -+} -+ -+ -+static inline void tcg_out_mov(TCGContext *s, int ret, int arg) -+{ -+ tcg_out_b9(s, B9_LGR, ret, arg); -+} -+ -+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) -+{ -+ tcg_abort(); -+} -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 -+ * -+ * Copyright (c) 2009 Ulrich Hecht -+ * -+ * 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. -+ */ -+#define TCG_TARGET_S390 1 -+ -+#define TCG_TARGET_REG_BITS 64 -+#define TCG_TARGET_WORDS_BIGENDIAN -+#define TCG_TARGET_HAS_div_i32 -+#undef TCG_TARGET_HAS_div_i64 -+#undef TCG_TARGET_HAS_bswap_i32 -+#define TCG_TARGET_HAS_neg_i32 -+#define TCG_TARGET_HAS_neg_i64 -+#undef TCG_TARGET_STACK_GROWSUP -+ -+enum { -+ TCG_REG_R0 = 0, -+ TCG_REG_R1, -+ TCG_REG_R2, -+ TCG_REG_R3, -+ TCG_REG_R4, -+ TCG_REG_R5, -+ TCG_REG_R6, -+ TCG_REG_R7, -+ TCG_REG_R8, -+ TCG_REG_R9, -+ TCG_REG_R10, -+ TCG_REG_R11, -+ TCG_REG_R12, -+ TCG_REG_R13, -+ TCG_REG_R14, -+ TCG_REG_R15 -+}; -+#define TCG_TARGET_NB_REGS 16 -+ -+/* used for function call generation */ -+#define TCG_REG_CALL_STACK TCG_REG_R15 -+#define TCG_TARGET_STACK_ALIGN 8 -+#define TCG_TARGET_CALL_STACK_OFFSET 0 -+ -+enum { -+ /* Note: must be synced with dyngen-exec.h */ -+ TCG_AREG0 = TCG_REG_R10, -+ TCG_AREG1 = TCG_REG_R7, -+ TCG_AREG2 = TCG_REG_R8, -+ TCG_AREG3 = TCG_REG_R9, -+}; -+ -+static inline void flush_icache_range(unsigned long start, unsigned long stop) -+{ -+#if QEMU_GNUC_PREREQ(4, 1) -+ void __clear_cache(char *beg, char *end); -+ __clear_cache((char *) start, (char *) stop); -+#else -+#error not implemented -+#endif -+} --- -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 deleted file mode 100644 index b0dbfce5..00000000 --- a/0024-linux-user-S-390-64-bit-s390x-support.patch +++ /dev/null @@ -1,1350 +0,0 @@ -From af1a4af732202b6bdacc12bdef6e6a338a38ef67 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 3a8268b..896592d 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 deleted file mode 100644 index 13962d4a..00000000 --- a/0025-linux-user-don-t-do-locking-in-single-threaded-proc.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 603d882c9c1c61475a69f657a9550bb335bf3ca9 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 deleted file mode 100644 index a76a81fd..00000000 --- a/0026-linux-user-dup3-fallocate-syscalls.patch +++ /dev/null @@ -1,80 +0,0 @@ -From ad0b7fcf697651a156c0e4a2911dd9fa69fd011c 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 e0874b5..4be25f6 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 deleted file mode 100644 index 5aa4c315..00000000 --- a/0027-linux-user-fcntl-fixes-for-LTP.patch +++ /dev/null @@ -1,171 +0,0 @@ -From e4f2e031fe5b5f9f11560a51ce607ffdd3090c05 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 deleted file mode 100644 index 4ad79dde..00000000 --- a/0028-linux-user-enable-getdents-for-32-bit-systems.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0a1fc6cfd1798da391335a37ce7f3fd6141c7ff5 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 deleted file mode 100644 index 99079775..00000000 --- a/0029-linux-user-define-a-couple-of-syscalls-for-non-uid1.patch +++ /dev/null @@ -1,271 +0,0 @@ -From d9c50cda4f12fc4c64b8b494a298659b8ad341ed 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 deleted file mode 100644 index c7fa1691..00000000 --- a/0030-linux-user-getpriority-errno-fix.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 03004ec00de3f29699a6bb9458942ea111f528ed 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 deleted file mode 100644 index aa0d3988..00000000 --- a/0031-linux-user-fadvise64-implementation.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 51e609fc6a4a6ff29cd463babfe14032aea18254 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 deleted file mode 100644 index ca88e2a3..00000000 --- a/0032-linux-user-zero-fstat-buffer-to-initialize-nsec-fie.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 50a2b3b61b897ada12c267538e9f65578c256880 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 deleted file mode 100644 index 7a48eb25..00000000 --- a/0033-dup3-check-fallocate-check-fixed.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 1e8223836a2e09899cd946db4e4ee99b64ceb7a4 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 4be25f6..8d3967d 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.11.0.tar.bz2 b/qemu-0.11.0.tar.bz2 deleted file mode 100644 index b86d869f..00000000 --- a/qemu-0.11.0.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:58ad4225ba18ba5166977a7e0f5cd1bb94ee4e5f9fce65274d6dbb30035958ab -size 3292681 diff --git a/qemu-0.12.4.tar.bz2 b/qemu-0.12.4.tar.bz2 new file mode 100644 index 00000000..a1e8c855 --- /dev/null +++ b/qemu-0.12.4.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22829ff344453eec4e0bb3b028b20d677ecb7acd07c0c2e0bf30f04fb9de448a +size 3932800 diff --git a/qemu.changes b/qemu.changes index 1ce78260..1d38f9ec 100644 --- a/qemu.changes +++ b/qemu.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri May 28 18:57:23 CEST 2010 - uli@suse.de + +- update -> 0.12.4 + see http://wiki.qemu.org/ChangeLog for changes + ------------------------------------------------------------------- Wed May 19 17:37:03 UTC 2010 - brogers@novell.com diff --git a/qemu.spec b/qemu.spec index 18870a08..bc628f3a 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,5 +1,5 @@ # -# spec file for package qemu (Version 0.11.0) +# spec file for package qemu (Version 0.12.4) # # Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. # @@ -19,14 +19,14 @@ Name: qemu -BuildRequires: SDL-devel bison bluez-devel curl-devel cyrus-sasl-devel e2fsprogs-devel libaio-devel libgnutls-devel libpcap-devel ncurses-devel zlib-devel-static +BuildRequires: SDL-devel bison bluez-devel curl-devel cyrus-sasl-devel e2fsprogs-devel libaio libaio-devel libgnutls-devel libpcap-devel ncurses-devel zlib-devel-static Url: http://fabrice.bellard.free.fr/qemu/ License: BSD3c(or similar) ; GPLv2+ ; LGPLv2.1+ ; MIT License (or similar) Group: System/Emulators/PC Summary: Universal CPU emulator -Version: 0.11.0 -Release: 6 -Source: %name-0.11.0.tar.bz2 +Version: 0.12.4 +Release: 1 +Source: %name-%version.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 @@ -35,31 +35,14 @@ 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 +Patch9: 0009-qemu-cvs-sched_getaffinity.patch +Patch10: 0010-qemu-cvs-mmap-amd64.patch +Patch11: 0011-qemu-img-vmdk-scsi.patch +Patch12: 0012-qemu-nonvoid_return.patch +Patch13: 0013-i386-linux-user-NPTL-support.patch +Patch14: 0014-qemu-0.11-git-ioctl_mount.patch +Patch15: 0015-qemu-0.11-git-user-linux-ppc-uid16_fix.patch +Patch16: 0016-S-390-support.patch # this is to make lint happy Source300: rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -80,7 +63,7 @@ Authors: Fabrice Bellard %prep -%setup -q -n qemu-0.11.0 +%setup -q %patch1 -p1 %patch2 -p1 %patch3 -p1 @@ -96,27 +79,10 @@ Authors: %patch13 -p1 %patch14 -p1 %patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 %ifarch s390x ppc64 x86_64 # s390 target only builds on 64-bit machines -%patch22 -p1 +%patch16 -p1 %endif -%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 @@ -143,7 +109,7 @@ make clean --interp-prefix=/usr/share/qemu/qemu-i386 \ --enable-linux-user \ --disable-system \ - --static \ + --static --disable-linux-aio \ --extra-cflags="$QEMU_OPT_FLAGS" make %{?jobs:-j%{jobs}} V=1