On 30.09.2012, at 20:50, Alex Barcelo wrote: > This error may be a PPC specific problem, but I don't have another > environment where I can test it (i386 doesn't seem to use pwrite64), > so I ask for a bit of help/check. > > I am in a 32bit linux testing the qemu-ppc. > > My test program: > > // ------------------------------- > #include <unistd.h> > #include <stdio.h> > #include <sys/types.h> > #include <sys/stat.h> > #include <fcntl.h> > > int main (void) { > int fd, len; > > char* asd = "This is a random test"; > char asd2[20]; > > fd = open ("./test.pwrite", O_RDWR | O_CREAT); > > printf ( "fd: %d\n", fd); > pwrite ( fd, asd, 15, 0 ); > pwrite ( fd, asd+5, 6, 10); > pwrite ( fd, asd, 4, 30); > > len = pread ( fd, asd2, 5, 5); > asd2[len]='\0'; > printf ( "Read %d bytes: %s", len, asd2); > > // This is to force two int arguments for 64bit > //len = pread ( fd, asd2, -1, -1); > close(fd); > return 0; > } > // ------------------------------- > > Then I do > $ powerpc-linux-gnu-gcc -g --static -o pwrite-alien pwrite-test.c > > and when I launch a qemu-ppc to test, it should be (on the file) > This is a is a rThis > > instead I get: > This rs a randorThis > > and if I print some debug information inside pwrite64 and pread64 I see: > syscall: pwrite arg_i: 3 268909324 15 0 0 0 0 0 > syscall: pwrite arg_i: 3 268909329 6 0 0 10 0 0 > syscall: pwrite arg_i: 3 268909324 4 0 0 30 0 0 > syscall: pread arg_i: 3 1082133156 5 0 0 5 0 0 > (those are arg1, arg2, arg3, arg4, arg5, arg6 and the unused arg7 and arg8) > > As can be seen, arg4 is not used, and the line > ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); > should be, in my case > ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg5, arg6))); > > With this changes, the qemu "Works For Me (TM)". > > So, anybody can confirm it or (if it is indeed my problem) can give me > some pointers? I will not post this as a patch until I understand the > problem... and first step is making sure that it really is a qemu > problem. And not my toolchain or something random.
Running the above code on a real ppc machine (compiled with -m32, running a ppc64 kernel) I get: 00000000 54 68 69 73 20 69 73 20 61 20 69 73 20 61 20 72 |This is a is a r| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 68 |..............Th| 00000020 69 73 |is| as output. Is this the expected result? Running it in qemu-ppc, I get: 00000000 54 68 69 73 20 72 73 20 61 20 72 61 6e 64 6f |This rs a rando| 0000000f So yes, something looks broken here. According to arch/powerpc/kernel/sys_ppc32.c, the ppc32 ABI carries 64bit parameters on odd/even pairs: /* * long long munging: * The 32 bit ABI passes long longs in an odd even register pair. */ which is almost the same as what ARM or MIPS do and which explains why you see arg5/arg6 (r7/r8) used instead of arg4/arg5 (r6/r7). Could you please try the below patch? Alex diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1a38169..e03b3a8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -587,12 +587,16 @@ extern int setfsgid(int); extern int setgroups(int, gid_t *); /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ -#ifdef TARGET_ARM +#ifdef TARGET_ARM static inline int regpairs_aligned(void *cpu_env) { return ((((CPUARMState *)cpu_env)->eabi) == 1) ; } #elif defined(TARGET_MIPS) static inline int regpairs_aligned(void *cpu_env) { return 1; } +#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) +/* PPC32 expects 64bit parameters to be passed on odd/even pairs of registers + which is the same as ARM/MIPS, because we start with r3 as arg1. */ +static inline int regpairs_aligned(void *cpu_env) { return 1; } #else static inline int regpairs_aligned(void *cpu_env) { return 0; } #endif @@ -7419,12 +7423,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pread64 case TARGET_NR_pread64: + if (regpairs_aligned(cpu_env)) { + arg4 = arg5; + arg5 = arg6; + } if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite64: + if (regpairs_aligned(cpu_env)) { + arg4 = arg5; + arg5 = arg6; + } if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));