From c344741c539e58d99fc4ef039159dab592f2b2168c7221fd3c5a88795a66ed86 Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Mon, 11 Jun 2007 16:17:36 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/qemu?expand=0&rev=7 --- qemu-0.9.0-alt-path.patch | 205 +++++ qemu-0.9.0-fadvise64.patch | 47 ++ qemu-0.9.0-mmap.patch | 219 +++++ qemu-0.9.0-nonetlink.patch | 12 + qemu-0.9.0-nptl.patch | 301 +++++++ qemu-0.9.0-nptl2.patch | 219 +++++ qemu-0.9.0-socket.patch | 22 + qemu-0.9.0-strace.patch | 1582 ++++++++++++++++++++++++++++++++++++ qemu.changes | 12 + qemu.spec | 33 +- 10 files changed, 2648 insertions(+), 4 deletions(-) create mode 100644 qemu-0.9.0-alt-path.patch create mode 100644 qemu-0.9.0-fadvise64.patch create mode 100644 qemu-0.9.0-mmap.patch create mode 100644 qemu-0.9.0-nonetlink.patch create mode 100644 qemu-0.9.0-nptl.patch create mode 100644 qemu-0.9.0-nptl2.patch create mode 100644 qemu-0.9.0-socket.patch create mode 100644 qemu-0.9.0-strace.patch diff --git a/qemu-0.9.0-alt-path.patch b/qemu-0.9.0-alt-path.patch new file mode 100644 index 0000000..1b5953d --- /dev/null +++ b/qemu-0.9.0-alt-path.patch @@ -0,0 +1,205 @@ +--- qemu/linux-user/path.c ++++ qemu/linux-user/path.c +@@ -1,147 +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 stabalized (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); +-} ++static struct path_list_head* list_head; + + void init_paths(const char *prefix) + { + if (prefix[0] != '/' || +- prefix[0] == '\0' || +- !strcmp(prefix, "/")) ++ prefix[0] == '\0' || ++ !strcmp(prefix, "/")) + return; + +- base = new_entry("", NULL, prefix+1); +- base = add_dir_maybe(base); +- if (base->num_entries == 0) { +- free (base); +- base = NULL; +- } else { +- set_parents(base, base); +- } +-} ++ list_head = malloc(sizeof(struct path_list_head)); + +-/* 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; ++ /* 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[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; + } diff --git a/qemu-0.9.0-fadvise64.patch b/qemu-0.9.0-fadvise64.patch new file mode 100644 index 0000000..18750f0 --- /dev/null +++ b/qemu-0.9.0-fadvise64.patch @@ -0,0 +1,47 @@ +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -144,6 +144,7 @@ type name (type1 arg1,type2 arg2,type3 a + #define __NR_sys_getdents64 __NR_getdents64 + #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo + #define __NR_sys_syslog __NR_syslog ++#define __NR_sys_fadvise64 __NR_fadvise64 + + #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) + #define __NR__llseek __NR_lseek +@@ -164,6 +165,7 @@ _syscall5(int, _llseek, uint, fd, ulon + loff_t *, res, uint, wh); + _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) + _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) ++_syscall4(int,sys_fadvise64,int,fd,loff_t,offset,loff_t,len,int,advice) + #ifdef __NR_exit_group + _syscall1(int,exit_group,int,error_code) + #endif +@@ -4151,6 +4153,17 @@ long do_syscall(void *cpu_env, int num, + break; + } + #endif ++#ifdef TARGET_NR_fadvise64 ++ case TARGET_NR_fadvise64: ++ ret = get_errno(sys_fadvise64((int)arg1, arg2, arg3, (int)arg4)); ++ break; ++#endif ++#ifdef TARGET_NR_fadvise64_64 ++ case TARGET_NR_fadvise64_64: ++ // fadvise64_64 should be just a wrapper for fadvise_64 ++ ret = get_errno(sys_fadvise64((int)arg1, arg2, arg3, (int)arg4)); ++ break; ++#endif + default: + unimplemented: + gemu_log("qemu: Unsupported syscall: %d\n", num); +Index: qemu-0.9.0/linux-user/i386/syscall_nr.h +=================================================================== +--- qemu-0.9.0.orig/linux-user/i386/syscall_nr.h ++++ qemu-0.9.0/linux-user/i386/syscall_nr.h +@@ -272,3 +272,4 @@ + #define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) + + #define TARGET_NR_utimes 271 ++#define TARGET_NR_fadvise64_64 272 diff --git a/qemu-0.9.0-mmap.patch b/qemu-0.9.0-mmap.patch new file mode 100644 index 0000000..059fb38 --- /dev/null +++ b/qemu-0.9.0-mmap.patch @@ -0,0 +1,219 @@ +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -185,6 +185,9 @@ extern int getresgid(gid_t *, gid_t *, g + extern int setgroups(int, gid_t *); + extern int uselib(const char*); + ++#include "exec-all.h" ++long mmap_lock; ++ + static inline long get_errno(long ret) + { + if (ret == -1) +@@ -227,9 +235,11 @@ long do_brk(target_ulong new_brk) + + /* We need to allocate more memory after the brk... */ + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); ++ spin_lock(&mmap_lock); + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); ++ spin_unlock(&mmap_lock); + if (is_error(mapped_addr)) { + return mapped_addr; + } else { +@@ -2133,6 +2133,7 @@ static long do_futex(target_ulong uaddr, + struct timespec host_utime; + unsigned long val2 = utime; + ++ spin_lock(&mmap_lock); + if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) { + target_to_host_timespec(&host_utime, utime); + val2 = (unsigned long)&host_utime; +@@ -2230,6 +2265,7 @@ static long do_futex(target_ulong uaddr, + } + #endif + #endif ++ spin_unlock(&mmap_lock); + return syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3); + } + +@@ -2985,15 +3021,19 @@ long do_syscall(void *cpu_env, int num, + v5 = tswapl(v[4]); + v6 = tswapl(v[5]); + unlock_user(v, arg1, 0); ++ spin_lock(&mmap_lock); + ret = get_errno(target_mmap(v1, v2, v3, + target_to_host_bitmask(v4, mmap_flags_tbl), + v5, v6)); ++ spin_unlock(&mmap_lock); + } + #else ++ spin_lock(&mmap_lock); + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); ++ spin_unlock(&mmap_lock); + #endif + break; + #ifdef TARGET_NR_mmap2 +@@ -3003,36 +3043,54 @@ long do_syscall(void *cpu_env, int num, + #else + #define MMAP_SHIFT TARGET_PAGE_BITS + #endif ++ spin_lock(&mmap_lock); + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6 << MMAP_SHIFT)); ++ spin_unlock(&mmap_lock); + break; + #endif + case TARGET_NR_munmap: ++ spin_lock(&mmap_lock); + ret = get_errno(target_munmap(arg1, arg2)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_mprotect: ++ spin_lock(&mmap_lock); + ret = get_errno(target_mprotect(arg1, arg2, arg3)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_mremap: ++ spin_lock(&mmap_lock); + ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); ++ spin_unlock(&mmap_lock); + break; + /* ??? msync/mlock/munlock are broken for softmmu. */ + case TARGET_NR_msync: ++ spin_lock(&mmap_lock); + ret = get_errno(msync(g2h(arg1), arg2, arg3)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_mlock: ++ spin_lock(&mmap_lock); + ret = get_errno(mlock(g2h(arg1), arg2)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_munlock: ++ spin_lock(&mmap_lock); + ret = get_errno(munlock(g2h(arg1), arg2)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_mlockall: ++ spin_lock(&mmap_lock); + ret = get_errno(mlockall(arg1)); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_munlockall: ++ spin_lock(&mmap_lock); + ret = get_errno(munlockall()); ++ spin_unlock(&mmap_lock); + break; + case TARGET_NR_truncate: + p = lock_user_string(arg1); +Index: qemu-0.9.0/exec.c +=================================================================== +--- qemu-0.9.0.orig/exec.c ++++ qemu-0.9.0/exec.c +@@ -1676,6 +1684,50 @@ void page_dump(FILE *f) + } + } + ++/* dump memory mappings */ ++target_ulong page_find_end() ++{ ++ unsigned long start, end; ++ int i, j, prot, prot1; ++ void *firsttb; ++ PageDesc *p; ++ target_ulong last = 0; ++ ++ start = -1; ++ end = -1; ++ prot = 0; ++ for(i = 0; i <= L1_SIZE; i++) { ++ if (i < L1_SIZE) ++ p = l1_map[i]; ++ else ++ p = NULL; ++ for(j = 0;j < L2_SIZE; j++) { ++ if (!p) { ++ firsttb = NULL; ++ prot1 = 0; ++ } ++ else { ++ prot1 = p[j].flags; ++ firsttb = p[j].first_tb; ++ } ++ if (prot1 != prot) { ++ end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); ++ if (start != -1) { ++ last = end; ++ } ++ if (prot1 != 0) ++ start = end; ++ else ++ start = -1; ++ prot = prot1; ++ } ++ if (!p) ++ break; ++ } ++ } ++ return last; ++} ++ + int page_get_flags(target_ulong address) + { + PageDesc *p; +Index: qemu-0.9.0/linux-user/mmap.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/mmap.c ++++ qemu-0.9.0/linux-user/mmap.c +@@ -48,8 +48,14 @@ int target_mprotect(target_ulong start, + end = start + len; + if (end < start) + return -EINVAL; +- if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) +- return -EINVAL; ++ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) { ++#ifdef DEBUG_MMAP ++ gemu_log("mprotect: ERROR (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)\n"); ++#endif ++ // dirty hack to get mplayer running (sets PROT_GROWSDOWN) we just ignore advanced flags ++ prot &= (PROT_READ | PROT_WRITE | PROT_EXEC); ++// return -EINVAL; ++ } + if (len == 0) + return 0; + +@@ -205,9 +233,23 @@ long target_mmap(target_ulong start, tar + defined(__ia64) || defined(__CYGWIN__) + /* tell the kenel to search at the same place as i386 */ + if (real_start == 0) { +- real_start = last_start; +- last_start += HOST_PAGE_ALIGN(len); ++ target_ulong curend = page_find_end(); ++ ++ if(curend > last_start) { ++#ifdef DEBUG_MMAP ++ gemu_log("qemu: set last_start from %p to %p\n", last_start, curend + HOST_PAGE_ALIGN(len)); fflush(stdout); fflush(stderr); ++#endif ++ last_start = curend; ++#ifdef DEBUG_MMAP ++ } else { ++ gemu_log("qemu: curend(%p) <= last_start(%p)\n", curend, last_start); fflush(stdout); fflush(stderr); ++#endif ++ } ++ ++ real_start = last_start; ++ last_start += HOST_PAGE_ALIGN(len); + } ++ + #endif + if (0 && qemu_host_page_size != qemu_real_host_page_size) { + /* NOTE: this code is only for debugging with '-p' option */ diff --git a/qemu-0.9.0-nonetlink.patch b/qemu-0.9.0-nonetlink.patch new file mode 100644 index 0000000..d07ef07 --- /dev/null +++ b/qemu-0.9.0-nonetlink.patch @@ -0,0 +1,12 @@ +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -791,6 +791,7 @@ static long do_socket(int domain, int ty + break; + } + #endif ++ if(domain == PF_NETLINK) return -EAFNOSUPPORT; + return get_errno(socket(domain, type, protocol)); + } + diff --git a/qemu-0.9.0-nptl.patch b/qemu-0.9.0-nptl.patch new file mode 100644 index 0000000..4d23a09 --- /dev/null +++ b/qemu-0.9.0-nptl.patch @@ -0,0 +1,301 @@ +Index: qemu-0.9.0/linux-user/main.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/main.c ++++ qemu-0.9.0/linux-user/main.c +@@ -156,7 +156,7 @@ static void set_gate(void *ptr, unsigned + p[1] = tswapl(e2); + } + +-uint64_t gdt_table[6]; ++uint64_t gdt_table[9]; + uint64_t idt_table[256]; + + /* only dpl matters as we do only user space emulation */ +@@ -1604,7 +1604,11 @@ int main(int argc, char **argv) + int optind; + const char *r; + int gdbstub_port = 0; +- ++ char *assume_kernel = getenv("QEMU_ASSUME_KERNEL"); ++ ++ if (assume_kernel) ++ setenv("LD_ASSUME_KERNEL", assume_kernel, 1); ++ + if (argc <= 1) + usage(); + +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -17,6 +17,8 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ ++ ++#define __user + #include + #include + #include +@@ -57,6 +59,7 @@ + #define tchars host_tchars /* same as target */ + #define ltchars host_ltchars /* same as target */ + ++#include + #include + #include + #include +@@ -1690,6 +1693,80 @@ int do_modify_ldt(CPUX86State *env, int + return ret; + } + ++int do_set_thread_area(CPUX86State *env, target_ulong ptr) ++{ ++ uint64_t *gdt_table = g2h(env->gdt.base); ++ struct target_modify_ldt_ldt_s ldt_info; ++ struct target_modify_ldt_ldt_s *target_ldt_info; ++ int seg_32bit, contents, read_exec_only, limit_in_pages; ++ int seg_not_present, useable; ++ uint32_t *lp, entry_1, entry_2; ++ int i; ++ ++ lock_user_struct(target_ldt_info, ptr, 1); ++ ldt_info.entry_number = tswap32(target_ldt_info->entry_number); ++ ldt_info.base_addr = tswapl(target_ldt_info->base_addr); ++ ldt_info.limit = tswap32(target_ldt_info->limit); ++ ldt_info.flags = tswap32(target_ldt_info->flags); ++ if (ldt_info.entry_number == -1) { ++ for (i=6; i<8; i++) ++ if (gdt_table[i] == 0) { ++ ldt_info.entry_number = i; ++ target_ldt_info->entry_number = tswap32(i); ++ break; ++ } ++ } ++ unlock_user_struct(target_ldt_info, ptr, 0); ++ ++ if (ldt_info.entry_number < 6 || ldt_info.entry_number > 8) ++ return -EINVAL; ++ seg_32bit = ldt_info.flags & 1; ++ contents = (ldt_info.flags >> 1) & 3; ++ read_exec_only = (ldt_info.flags >> 3) & 1; ++ limit_in_pages = (ldt_info.flags >> 4) & 1; ++ seg_not_present = (ldt_info.flags >> 5) & 1; ++ useable = (ldt_info.flags >> 6) & 1; ++ ++ if (contents == 3) { ++ if (seg_not_present == 0) ++ return -EINVAL; ++ } ++ ++ /* NOTE: same code as Linux kernel */ ++ /* Allow LDTs to be cleared by the user. */ ++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { ++ if ((contents == 0 && ++ read_exec_only == 1 && ++ seg_32bit == 0 && ++ limit_in_pages == 0 && ++ seg_not_present == 1 && ++ useable == 0 )) { ++ entry_1 = 0; ++ entry_2 = 0; ++ goto install; ++ } ++ } ++ ++ entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | ++ (ldt_info.limit & 0x0ffff); ++ entry_2 = (ldt_info.base_addr & 0xff000000) | ++ ((ldt_info.base_addr & 0x00ff0000) >> 16) | ++ (ldt_info.limit & 0xf0000) | ++ ((read_exec_only ^ 1) << 9) | ++ (contents << 10) | ++ ((seg_not_present ^ 1) << 15) | ++ (seg_32bit << 22) | ++ (limit_in_pages << 23) | ++ (useable << 20) | ++ 0x7000; ++ ++ /* Install the new entry ... */ ++install: ++ lp = (uint32_t *)(gdt_table + ldt_info.entry_number); ++ lp[0] = tswap32(entry_1); ++ lp[1] = tswap32(entry_2); ++ return 0; ++} + #endif /* defined(TARGET_I386) */ + + /* this stack is the equivalent of the kernel stack associated with a +@@ -1710,9 +1787,14 @@ int do_fork(CPUState *env, unsigned int + TaskState *ts; + uint8_t *new_stack; + CPUState *new_env; +- ++#if defined(TARGET_I386) ++ uint64_t *new_gdt_table; ++#endif ++ printf("qemu fork\n"); + if (flags & CLONE_VM) { + ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); ++ if (!ts) ++ return -ENOMEM; + memset(ts, 0, sizeof(TaskState)); + new_stack = ts->stack; + ts->used = 1; +@@ -1725,6 +1807,29 @@ int do_fork(CPUState *env, unsigned int + #if defined(TARGET_I386) + if (!newsp) + newsp = env->regs[R_ESP]; ++ new_gdt_table = malloc(9 * 8); ++ if (!new_gdt_table) { ++ free(new_env); ++ return -ENOMEM; ++ } ++ /* Copy main GDT table from parent, but clear TLS entries */ ++ memcpy(new_gdt_table, g2h(env->gdt.base), 6 * 8); ++ memset(&new_gdt_table[6], 0, 3 * 8); ++ new_env->gdt.base = h2g(new_gdt_table); ++ if (flags & 0x00080000 /* CLONE_SETTLS */) { ++ ret = do_set_thread_area(new_env, new_env->regs[R_ESI]); ++ if (ret) { ++ free(new_gdt_table); ++ free(new_env); ++ return ret; ++ } ++ } ++ cpu_x86_load_seg(env, R_CS, new_env->regs[R_CS]); ++ cpu_x86_load_seg(env, R_DS, new_env->regs[R_DS]); ++ cpu_x86_load_seg(env, R_ES, new_env->regs[R_ES]); ++ cpu_x86_load_seg(env, R_SS, new_env->regs[R_SS]); ++ cpu_x86_load_seg(env, R_FS, new_env->regs[R_FS]); ++ cpu_x86_load_seg(env, R_GS, new_env->regs[R_GS]); + new_env->regs[R_ESP] = newsp; + new_env->regs[R_EAX] = 0; + #elif defined(TARGET_ARM) +@@ -1991,6 +2096,68 @@ static inline void host_to_target_timesp + unlock_user_struct(target_ts, target_addr, 1); + } + ++static long do_futex(target_ulong uaddr, int op, uint32_t val, ++ target_ulong utime, target_ulong uaddr2, ++ uint32_t val3) ++{ ++ struct timespec host_utime; ++ unsigned long val2 = utime; ++ ++ if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) { ++ target_to_host_timespec(&host_utime, utime); ++ val2 = (unsigned long)&host_utime; ++ } ++ ++#ifdef BSWAP_NEEDED ++ switch(op) { ++ case FUTEX_CMP_REQUEUE: ++ val3 = tswap32(val3); ++ case FUTEX_REQUEUE: ++ val2 = tswap32(val2); ++ case FUTEX_WAIT: ++ case FUTEX_WAKE: ++ val = tswap32(val); ++ case FUTEX_LOCK_PI: /* This one's icky, but comes out OK */ ++ case FUTEX_UNLOCK_PI: ++ break; ++ default: ++ gemu_log("qemu: Unsupported futex op %d\n", op); ++ return -ENOSYS; ++ } ++#if 0 /* No, it's worse than this */ ++ if (op == FUTEX_WAKE_OP) { ++ /* Need to munge the secondary operation (val3) */ ++ val3 = tswap32(val3); ++ int op2 = (val3 >> 28) & 7; ++ int cmp = (val3 >> 24) & 15; ++ int oparg = (val3 << 8) >> 20; ++ int cmparg = (val3 << 20) >> 20; ++ int shift = val3 & (FUTEX_OP_OPARG_SHIFT << 28); ++ ++ if (shift) ++ oparg = (oparg & 7) + 24 - (oparg & 24); ++ else oparg = ++ if (op2 == FUTEX_OP_ADD) { ++ gemu_log("qemu: Unsupported wrong-endian FUTEX_OP_ADD\n"); ++ return -ENOSYS; ++ } ++ if (cmparg == FUTEX_OP_CMP_LT || cmparg == FUTEX_OP_CMP_GE || ++ cmparg == FUTEX_OP_CMP_LE || cmparg == FUTEX_OP_CMP_GT) { ++ gemu_log("qemu: Unsupported wrong-endian futex cmparg %d\n", cmparg); ++ return -ENOSYS; ++ } ++ val3 = shift | (op2<<28) | (cmp<<24) | (oparg<<12) | cmparg; ++ } ++#endif ++#endif ++ return syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3); ++} ++ ++int do_set_tid_address(target_ulong tidptr) ++{ ++ return syscall(__NR_set_tid_address, g2h(tidptr)); ++} ++ + long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) + { +@@ -2008,7 +2175,7 @@ long do_syscall(void *cpu_env, int num, + _mcleanup(); + #endif + gdb_exit(cpu_env, arg1); +- /* XXX: should free thread stack and CPU env */ ++ /* XXX: should free thread stack, GDT and CPU env */ + _exit(arg1); + ret = 0; /* avoid warning */ + break; +@@ -3153,6 +3320,9 @@ long do_syscall(void *cpu_env, int num, + case TARGET_NR_vm86: + ret = do_vm86(cpu_env, arg1, arg2); + break; ++ case TARGET_NR_set_thread_area: ++ ret = get_errno(do_set_thread_area(cpu_env, arg1)); ++ break; + #endif + case TARGET_NR_adjtimex: + goto unimplemented; +@@ -3947,15 +4117,24 @@ long do_syscall(void *cpu_env, int num, + case TARGET_NR_fremovexattr: + goto unimplemented_nowarn; + #endif +-#ifdef TARGET_NR_set_thread_area +- case TARGET_NR_set_thread_area: +- case TARGET_NR_get_thread_area: +- goto unimplemented_nowarn; +-#endif + #ifdef TARGET_NR_getdomainname + case TARGET_NR_getdomainname: + goto unimplemented_nowarn; + #endif ++#ifdef TARGET_NR_futex ++ case TARGET_NR_futex: ++ ret = get_errno(do_futex(arg1, arg2, arg3, arg4, arg5, arg6)); ++ break; ++#endif ++#ifdef TARGET_NR_set_tid_address ++ case TARGET_NR_set_tid_address: ++ ret = get_errno(do_set_tid_address(arg1)); ++ break; ++#endif ++#ifdef TARGET_NR_set_robust_list ++ case TARGET_NR_set_robust_list: ++ goto unimplemented_nowarn; ++#endif + #ifdef TARGET_NR_clock_gettime + case TARGET_NR_clock_gettime: + { +@@ -3975,7 +4154,7 @@ long do_syscall(void *cpu_env, int num, + default: + unimplemented: + gemu_log("qemu: Unsupported syscall: %d\n", num); +-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname) ++#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_set_robust_list) || defined(TARGET_NR_getdomainname) + unimplemented_nowarn: + #endif + ret = -ENOSYS; diff --git a/qemu-0.9.0-nptl2.patch b/qemu-0.9.0-nptl2.patch new file mode 100644 index 0000000..a49fc95 --- /dev/null +++ b/qemu-0.9.0-nptl2.patch @@ -0,0 +1,219 @@ +Index: qemu-0.9.0/linux-user/i386/syscall_nr.h +=================================================================== +--- qemu-0.9.0.orig/linux-user/i386/syscall_nr.h ++++ qemu-0.9.0/linux-user/i386/syscall_nr.h +@@ -271,5 +271,6 @@ + #define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) + #define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) + ++#define TARGET_NR_tgkill 270 + #define TARGET_NR_utimes 271 + #define TARGET_NR_fadvise64_64 272 +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -145,6 +145,8 @@ type name (type1 arg1,type2 arg2,type3 a + #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo + #define __NR_sys_syslog __NR_syslog + #define __NR_sys_fadvise64 __NR_fadvise64 ++#define __NR_sys_tgkill __NR_tgkill ++#define __NR_sys_clone __NR_clone + + #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) + #define __NR__llseek __NR_lseek +@@ -166,6 +168,8 @@ _syscall5(int, _llseek, uint, fd, ulon + _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) + _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) + _syscall4(int,sys_fadvise64,int,fd,loff_t,offset,loff_t,len,int,advice) ++_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) ++_syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, struct user_desc *, newtls, int *, child_tidptr) + #ifdef __NR_exit_group + _syscall1(int,exit_group,int,error_code) + #endif +@@ -1699,7 +1704,7 @@ int do_modify_ldt(CPUX86State *env, int + return ret; + } + +-int do_set_thread_area(CPUX86State *env, target_ulong ptr) ++int do_set_thread_area(CPUX86State *env, target_ulong ptr, int set_shadow_registers) + { + uint64_t *gdt_table = g2h(env->gdt.base); + struct target_modify_ldt_ldt_s ldt_info; +@@ -1708,6 +1713,7 @@ int do_set_thread_area(CPUX86State *env, + int seg_not_present, useable; + uint32_t *lp, entry_1, entry_2; + int i; ++ SegmentCache *sc = &env->segs[R_GS]; + + lock_user_struct(target_ldt_info, ptr, 1); + ldt_info.entry_number = tswap32(target_ldt_info->entry_number); +@@ -1767,6 +1767,12 @@ int do_set_thread_area(CPUX86State *env, + (useable << 20) | + 0x7000; + ++ if(set_shadow_registers) { ++ sc->selector = env->regs[R_GS]; ++ sc->base = ldt_info.base_addr; ++ sc->limit = ldt_info.limit; ++ sc->flags = entry_2; ++ } + /* Install the new entry ... */ + install: + lp = (uint32_t *)(gdt_table + ldt_info.entry_number); +@@ -1779,20 +1802,21 @@ install: + thread/process */ + #define NEW_STACK_SIZE 8192 + +-static int clone_func(void *arg) ++static int clone_func(CPUState *cloneenv) + { +- CPUState *env = arg; +- cpu_loop(env); ++ cpu_loop(cloneenv); + /* never exits */ + return 0; + } + +-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) ++int do_fork(CPUState *env, unsigned int flags, target_ulong newsp, target_ulong parent_tidptr, target_ulong newtls, target_ulong child_tidptr) + { + int ret; ++ int cpu_index; ++ unsigned long parent_tid=gettid(); + TaskState *ts; + uint8_t *new_stack; +- CPUState *new_env; ++ CPUState *new_env, *next_cpu; + #if defined(TARGET_I386) + uint64_t *new_gdt_table; + #endif +@@ -1807,9 +1835,14 @@ int do_fork(CPUState *env, unsigned int + /* add in task state list */ + ts->next = first_task_state; + first_task_state = ts; +- /* we create a new CPU instance. */ +- new_env = cpu_init(); +- memcpy(new_env, env, sizeof(CPUState)); ++ /* we create a new CPU instance. (cpu_copy() in cvs) */ ++ new_env = cpu_init(); ++ /* preserve chaining and index */ ++ next_cpu = new_env->next_cpu; ++ cpu_index = new_env->cpu_index; ++ memcpy(new_env, env, sizeof(CPUState)); ++ new_env->next_cpu = next_cpu; ++ new_env->cpu_index = cpu_index; + #if defined(TARGET_I386) + if (!newsp) + newsp = env->regs[R_ESP]; +@@ -1818,26 +1851,20 @@ int do_fork(CPUState *env, unsigned int + free(new_env); + return -ENOMEM; + } + /* Copy main GDT table from parent, but clear TLS entries */ + memcpy(new_gdt_table, g2h(env->gdt.base), 6 * 8); + memset(&new_gdt_table[6], 0, 3 * 8); + new_env->gdt.base = h2g(new_gdt_table); +- if (flags & 0x00080000 /* CLONE_SETTLS */) { +- ret = do_set_thread_area(new_env, new_env->regs[R_ESI]); ++ if (flags & CLONE_SETTLS) { ++ ret = do_set_thread_area(new_env, newtls, 1); + if (ret) { + free(new_gdt_table); + free(new_env); + return ret; + } + } +- cpu_x86_load_seg(env, R_CS, new_env->regs[R_CS]); +- cpu_x86_load_seg(env, R_DS, new_env->regs[R_DS]); +- cpu_x86_load_seg(env, R_ES, new_env->regs[R_ES]); +- cpu_x86_load_seg(env, R_SS, new_env->regs[R_SS]); +- cpu_x86_load_seg(env, R_FS, new_env->regs[R_FS]); +- cpu_x86_load_seg(env, R_GS, new_env->regs[R_GS]); + new_env->regs[R_ESP] = newsp; + new_env->regs[R_EAX] = 0; + #elif defined(TARGET_ARM) + if (!newsp) + newsp = env->regs[13]; +@@ -1877,16 +1933,28 @@ int do_fork(CPUState *env, unsigned int + #endif + new_env->opaque = ts; + #ifdef __ia64__ +- ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); ++ ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env); + #else +- ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); ++ ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env); + #endif + } else { + /* if no CLONE_VM, we consider it is a fork */ +- if ((flags & ~CSIGNAL) != 0) +- return -EINVAL; +- ret = fork(); ++ ret = sys_clone(flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), 0, g2h(parent_tidptr), NULL, g2h(child_tidptr)); ++ } ++ /* Store child thread ID at location parent_tidptr in parent and child memory. ++ Currently this is only done in client memory*/ ++ if(flags & CLONE_PARENT_SETTID) { ++ tput32(parent_tidptr, parent_tid); ++ } ++ ++ /* Store child thread ID at location child_tidptr in child memory. */ ++ if(flags & CLONE_CHILD_SETTID) { ++ if(ret==0) { // only in client memory for fork() ++ tput32(child_tidptr, gettid()); ++ } else if(flags & CLONE_VM) { // real threads need it too ++ tput32(child_tidptr, ret); ++ } + } + return ret; + } + +@@ -2206,7 +2221,7 @@ long do_syscall(void *cpu_env, int num, + ret = do_brk(arg1); + break; + case TARGET_NR_fork: +- ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); ++ ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0,0,0)); + break; + case TARGET_NR_waitpid: + { +@@ -3281,7 +3297,7 @@ long do_syscall(void *cpu_env, int num, + ret = get_errno(fsync(arg1)); + break; + case TARGET_NR_clone: +- ret = get_errno(do_fork(cpu_env, arg1, arg2)); ++ ret = get_errno(do_fork(cpu_env, arg1, arg2,arg3,arg4,arg5)); + break; + #ifdef __NR_exit_group + /* new thread calls */ +@@ -3339,7 +3397,7 @@ long do_syscall(void *cpu_env, int num, + ret = do_vm86(cpu_env, arg1, arg2); + break; + case TARGET_NR_set_thread_area: +- ret = get_errno(do_set_thread_area(cpu_env, arg1)); ++ ret = get_errno(do_set_thread_area(cpu_env, arg1, 0)); + break; + #endif + case TARGET_NR_adjtimex: +@@ -3635,7 +3651,7 @@ long do_syscall(void *cpu_env, int num, + #endif + #ifdef TARGET_NR_vfork + case TARGET_NR_vfork: +- ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); ++ ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0, 0,0,0)); + break; + #endif + #ifdef TARGET_NR_ugetrlimit +@@ -4164,6 +4180,11 @@ long do_syscall(void *cpu_env, int num, + ret = get_errno(sys_fadvise64((int)arg1, arg2, arg3, (int)arg4)); + break; + #endif ++#ifdef TARGET_NR_tgkill ++ case TARGET_NR_tgkill: ++ ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3)); ++ break; ++#endif + default: + unimplemented: + gemu_log("qemu: Unsupported syscall: %d\n", num); diff --git a/qemu-0.9.0-socket.patch b/qemu-0.9.0-socket.patch new file mode 100644 index 0000000..c530f21 --- /dev/null +++ b/qemu-0.9.0-socket.patch @@ -0,0 +1,22 @@ +Index: qemu-0.9.0/linux-user/syscall.c +=================================================================== +--- qemu-0.9.0.orig/linux-user/syscall.c ++++ qemu-0.9.0/linux-user/syscall.c +@@ -869,7 +869,7 @@ static long do_getpeername(int fd, targe + target_ulong target_addrlen) + { + socklen_t addrlen = tget32(target_addrlen); +- void *addr = alloca(target_addrlen); ++ void *addr = alloca(addrlen); + long ret; + + gemu_log("getpeername(%d,0x%lx,0x%lx)\n", fd, addr, addrlen); +@@ -887,7 +887,7 @@ static long do_getsockname(int fd, targe + target_ulong target_addrlen) + { + socklen_t addrlen = tget32(target_addrlen); +- void *addr = alloca(target_addrlen); ++ void *addr = alloca(addrlen); + long ret; + + ret = get_errno(getsockname(fd, addr, &addrlen)); diff --git a/qemu-0.9.0-strace.patch b/qemu-0.9.0-strace.patch new file mode 100644 index 0000000..fecf6a5 --- /dev/null +++ b/qemu-0.9.0-strace.patch @@ -0,0 +1,1582 @@ +Index: qemu/Makefile.target +=================================================================== +--- qemu.orig/Makefile.target 2007-06-02 11:43:16.000000000 -0400 ++++ qemu/Makefile.target 2007-06-02 11:43:22.000000000 -0400 +@@ -240,7 +240,7 @@ + endif + + ifdef CONFIG_LINUX_USER +-OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ ++OBJS= main.o syscall.o syscall_names.o mmap.o signal.o path.o osdep.o thunk.o \ + elfload.o linuxload.o + LIBS+= $(AIOLIBS) + ifdef TARGET_HAS_BFLT +Index: qemu/linux-user/syscall.c +=================================================================== +--- qemu.orig/linux-user/syscall.c 2007-06-02 11:43:16.000000000 -0400 ++++ qemu/linux-user/syscall.c 2007-06-02 12:30:10.000000000 -0400 +@@ -2724,6 +2724,7 @@ + + #ifdef DEBUG + gemu_log("syscall %d", num); ++ print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + #endif + switch(num) { + case TARGET_NR_exit: +@@ -4906,6 +4907,7 @@ + } + fail: + #ifdef DEBUG ++ /* use this to end lines output by print_syscall() above */ + gemu_log(" = %ld\n", ret); + #endif + return ret; +Index: qemu/linux-user/syscall_names.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ qemu/linux-user/syscall_names.c 2007-06-02 12:26:31.000000000 -0400 +@@ -0,0 +1,30 @@ ++#include ++#include "qemu.h" ++ ++struct syscallname { ++ int nr; ++ char *name; ++ char *format; ++}; ++ ++static struct syscallname scnames[] = { ++#include "syscall_names.list" ++}; ++ ++static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname); ++ ++void ++print_syscall(int num, long arg1, long arg2, long arg3, ++ long arg4, long arg5, long arg6) ++{ ++int i; ++char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; ++ ++for(i=0;i>config-host.h -make #%{?jobs:-j%{jobs}} +make %{?jobs:-j%{jobs}} mv */qemu */qemu-* dynamic || true make clean %endif @@ -221,7 +237,7 @@ make clean --interp-prefix=/usr/share/qemu/qemu-i386 \ --target-list="$target_list" --cc=%qemucc \ --enable-adlib --extra-cflags="$QEMU_OPT_FLAGS" -make #%{?jobs:-j%{jobs}} +make %{?jobs:-j%{jobs}} mv */qemu *-*/qemu-* dynamic || true make clean # build userland emus @@ -229,7 +245,7 @@ make clean --interp-prefix=/usr/share/qemu/qemu-i386 \ --target-list="$target_list_user" --cc=%qemucc \ --static --extra-cflags="$QEMU_OPT_FLAGS" -make #%{?jobs:-j%{jobs}} +make %{?jobs:-j%{jobs}} %install install -d -m 755 $RPM_BUILD_ROOT/usr/bin @@ -273,6 +289,15 @@ rm -rf %{gcc33tmp} %endif %changelog +* Mon Jun 11 2007 - agraf@suse.de +- implemented TLS support on i386 so qemu-user can be used to run + with current libc versions (partly done by David Woodhouse, + fixed by Alexander Graf) +- added a dirty hack for an mmap page table bug on qemu-user x86 + emulation +- disable AF_NETLINK in qemu-user (endianness problems) +- applied fast path mangling patch from Kirill A. Shutemov +- applied strace patch for debugging (by Stuart R. Anderson) * Wed Apr 04 2007 - agraf@suse.de - fixed initrd loading on x86 * Thu Mar 29 2007 - ro@suse.de