On Sun, Sep 30, 2007 at 11:53:20AM +0200, Edgar E. Iglesias wrote: % make > sparc64-unknown-linux-gnu-gcc -Wall -W -g -O2 -c -o ctest.o ctest.c > sparc64-unknown-linux-gnu-gcc -static ctest.o -o ctest > % file ctest > ctest: ELF 64-bit MSB executable, SPARC V9, version 1 (SYSV), for GNU/Linux > 2.4.1, statically linked, not stripped > % ~/src/c/qemu/sparc/sparc64-linux-user/qemu-sparc64 ./ctest > Segmentation fault > > I'll retry with a fresh CVS build.
With a fresh CVS build I managed to emulate some sparc64 programs. It was very unreliable though, but the failures are different from the ones I saw with the CRIS and MIPS 8K page targets. qemu CRIS and MIPS would gracefully exit after failing to load the ELF interpreter whereas Sparc64 randomly segfaults. I reworked target_mmap a bit more, among other things cleaning up some of the issues I mentioned to J. Mayer regarding long vs target_long inconsistencies. target_mmap now returns a target_long. There is still more work to be done here though, this is just a first step. With this updated patch, I can now reliably run statically linked sparc64 programs on my 32 bit host. Dynamically linked sparc64 programs reliably fail with an unhandled trap 0x37. qemu m68k reliably segfaults with and without the patch. Again, I tested CRIS and MIPS 8K and they both reliably manage to load and run my programs. I also ran some arm (4K pages) programs, which worked fine. I should mention that the sparc64 user emulator does not build correctly from CVS, linux/sparc64/target_signal.h lacks get_sp_from_cpu_state. I simply put a stub there with an abort() which didn't hit me. Comments appreciated! Best regards -- Edgar E. Iglesias Axis Communications AB Index: mmap.c =================================================================== RCS file: /sources/qemu/qemu/linux-user/mmap.c,v retrieving revision 1.15 diff -u -p -b -u -p -r1.15 mmap.c --- mmap.c 27 Sep 2007 04:10:43 -0000 1.15 +++ mmap.c 30 Sep 2007 11:14:37 -0000 @@ -36,7 +36,8 @@ int target_mprotect(target_ulong start, int prot1, ret; #ifdef DEBUG_MMAP - printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + printf("mprotect: start=0x" TARGET_FMT_lx + "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); @@ -151,11 +152,11 @@ static int mmap_frag(target_ulong real_s } /* NOTE: all the constants are the HOST ones */ -long target_mmap(target_ulong start, target_ulong len, int prot, +target_long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset) { target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; - long host_start; + unsigned long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ defined(__ia64) || defined(__mips__) static target_ulong last_start = 0x40000000; @@ -166,7 +167,8 @@ long target_mmap(target_ulong start, tar #ifdef DEBUG_MMAP { - printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + printf("mmap: start=0x" TARGET_FMT_lx + " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', @@ -186,7 +188,7 @@ long target_mmap(target_ulong start, tar printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); break; } - printf("fd=%d offset=%lx\n", fd, offset); + printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); } #endif @@ -209,34 +211,59 @@ long target_mmap(target_ulong start, tar 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 */ - /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ - /* reserve a memory area */ - /* ??? This needs fixing for remapping. */ -abort(); - host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; - real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (real_start == -1) - return real_start; - real_end = real_start + host_len; - start = HOST_PAGE_ALIGN(real_start); - end = start + HOST_PAGE_ALIGN(len); - if (start > real_start) - munmap((void *)g2h(real_start), start - real_start); - if (end < real_end) - munmap((void *)g2h(end), real_end - end); - /* use it as a fixed mapping */ - flags |= MAP_FIXED; - } else { - /* if not fixed, no need to do anything */ host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; + + if (qemu_host_page_size > qemu_real_host_page_size) { + /* + * The guest expects to see mmapped areas aligned to it's pagesize. + * If the hosts real page size is smaller than the guests, we need + * to fixup the maps. It is done by allocating a larger area, + * displacing the map (if needed) and finally choping off the spare + * room at the edges. + */ + + /* + * We assume qemu_host_page_size is always the same as + * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the + * hosts real page size. + */ + target_ulong host_end; + unsigned long host_aligned_start; + + host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size + - qemu_real_host_page_size); + host_start = (unsigned long) mmap(real_start ? + g2h(real_start) : NULL, + host_len, prot, flags, + fd, host_offset); + if (host_start == -1) + return -1; + + host_end = host_start + host_len; + + /* Find start and end, aligned to the targets pagesize with-in the + large mmaped area. */ + host_aligned_start = TARGET_PAGE_ALIGN(host_start); + if (!(flags & MAP_ANONYMOUS)) + host_aligned_start += offset - host_offset; + + start = h2g(host_aligned_start); + end = start + TARGET_PAGE_ALIGN(len); + + /* Chop off the leftovers, if any. */ + if (host_aligned_start > host_start) + munmap((void *)host_start, host_aligned_start - host_start); + if (end < host_end) + munmap((void *)g2h(end), host_end - end); + + goto the_end1; + } else { + /* if not fixed, no need to do anything */ host_start = (long)mmap(real_start ? g2h(real_start) : NULL, host_len, prot, flags, fd, host_offset); if (host_start == -1) - return host_start; + return -1; /* update start so that it points to the file position at 'offset' */ if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; @@ -267,7 +294,7 @@ abort(); MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) - return retaddr; + return -1; pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); @@ -300,7 +327,7 @@ abort(); prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) - return ret; + return -1; real_end -= qemu_host_page_size; } @@ -314,13 +341,13 @@ abort(); ret = (long)mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (ret == -1) - return ret; + return -1; } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP - printf("ret=0x%lx\n", (long)start); + printf("ret=0x%llx\n", start); page_dump(stdout); printf("\n"); #endif @@ -381,17 +408,18 @@ int target_munmap(target_ulong start, ta /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -long target_mremap(target_ulong old_addr, target_ulong old_size, +target_long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr) { int prot; + unsigned long host_addr; /* XXX: use 5 args syscall */ - new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); - if (new_addr == -1) - return new_addr; - new_addr = h2g(new_addr); + host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); + if (host_addr == -1) + return -1; + new_addr = h2g(host_addr); prot = page_get_flags(old_addr); page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); Index: qemu.h =================================================================== RCS file: /sources/qemu/qemu/linux-user/qemu.h,v retrieving revision 1.36 diff -u -p -b -u -p -r1.36 qemu.h --- qemu.h 27 Sep 2007 13:57:54 -0000 1.36 +++ qemu.h 30 Sep 2007 11:14:37 -0000 @@ -164,10 +164,10 @@ int do_vm86(CPUX86State *env, long subfu /* mmap.c */ int target_mprotect(target_ulong start, target_ulong len, int prot); -long target_mmap(target_ulong start, target_ulong len, int prot, +target_long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset); int target_munmap(target_ulong start, target_ulong len); -long target_mremap(target_ulong old_addr, target_ulong old_size, +target_long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr); int target_msync(target_ulong start, target_ulong len, int flags);