You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have found the following issue with using mmap on userland QEMU. The call to mmap is successful, but when the write to the allocated memory occurs (via a SB instruction) QEMU fails with a segmentation fault. This only appears to be an issue with using the N32 ABI; it works correctly when using the N64 ABI.
I am using the upstream PRPL i6400-mips64r6-PRIP4 branch, and I have built the following testcase:
#include <limits.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
main ()
{
char *p;
int dev_zero;
dev_zero = open ("/dev/zero", O_RDONLY);
p = mmap ((void *)0x82080000, 4, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_FIXED|MAP_PRIVATE, dev_zero, 0);
*p = 0;
}
In the following manner using the latest SDK Toolchain: mips-mti-linux-gnu-gcc -mabi=n32 -mips64r2 -static -O2 -mhard-float mmap.c -o mmap.elf
I am running QEMU in the following manner: qemu-mipsn32 -r 2.6.38 -cpu MIPS64R2-generic mmap.elf
And I get the following error: qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Analysis of issue
Written by Leon Alrae
I looked a bit deeper into that. I think I found the root cause, but probably someone who has better understanding of N32 ABI can come up with a proper fix...
target_mmap() in QEMU uses abi_ulong type for the address. Which in N32 means a0=0xffffffff82080000 gets truncated to 32-bits and later zero extended on 64-bit host. So it will mmap() to 0x0000000082080000, but returned pointer has abi_long type, consequently 0x82080000 gets signed extended, thus v0=0xffffffff82080000. Therefore referencing v0 causes segfault as this is different address than mmap'ed.
In N64 everything works just fine because QEMU always refers to 0x0000000082080000 address.
I attached a patch which makes mmap() syscall to return zero extended address in MIPSN32. I doubt this is a proper fix, just a workaround for this particular case to give an idea where is the issue.
Comments
Matthew Fortune wrote:
target_mmap() in QEMU uses abi_ulong type for the address. Which in N32 means
a0=0xffffffff82080000 gets truncated to 32-bits and later zero extended on 64-bit host. So
it will mmap() to 0x0000000082080000, but returned pointer has abi_long type, consequently
0x82080000 gets signed extended, thus v0=0xffffffff82080000. Therefore referencing v0
causes segfault as this is different address than mmap'ed.
In N64 everything works just fine because QEMU always refers to 0x0000000082080000
address.
For N32 (and all MIPS ABIs really it makes more sense to have pointers represented as abi_long
rather than abi_ulong. This is because of the natural sign extended behaviour of addresses
for MIPS but you will only see the effect for N32 which is presumably why we have ended
up with a number of qemu user-mode issues for N32.
I attached a patch which makes mmap() syscall to return zero extended address in
MIPSN32. I doubt this is a proper fix, just a workaround for this particular case to give
an idea where is the issue.
Indeed, the fix I believe should be on the other side of the mmap and the type of the
argument needs changing if at all possible.
The text was updated successfully, but these errors were encountered:
andrewb-IMG
changed the title
mmap issue with linux-userland for MIPS using N32 ABI
mmap issue with MIPS linux-userland when using the N32 ABI
Jun 30, 2015
We need to find out why qemu user emulation chooses to general represent pointer arguments to emulated syscalls as abi_ulong but when returned a pointer is generally abi_long. This breaks n32 many times over and could potentially do the same for other ILP32 ABIs for 64-bit targets although the MIPS memory map and sign-extension behaviour may well be unique. I think the whole of signal.c mmap.c syscall.c elfload.c linuxload.c will need reviewing to deal with this properly. First of all though we need to see if anyone knows why abi_ulong is used on one place and abi_long in the other.
Description of issue
Written by Andrew Bennett
I have found the following issue with using mmap on userland QEMU. The call to mmap is successful, but when the write to the allocated memory occurs (via a SB instruction) QEMU fails with a segmentation fault. This only appears to be an issue with using the N32 ABI; it works correctly when using the N64 ABI.
I am using the upstream PRPL i6400-mips64r6-PRIP4 branch, and I have built the following testcase:
In the following manner using the latest SDK Toolchain:
mips-mti-linux-gnu-gcc -mabi=n32 -mips64r2 -static -O2 -mhard-float mmap.c -o mmap.elf
I am running QEMU in the following manner:
qemu-mipsn32 -r 2.6.38 -cpu MIPS64R2-generic mmap.elf
And I get the following error:
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Analysis of issue
Written by Leon Alrae
I looked a bit deeper into that. I think I found the root cause, but probably someone who has better understanding of N32 ABI can come up with a proper fix...
target_mmap() in QEMU uses abi_ulong type for the address. Which in N32 means a0=0xffffffff82080000 gets truncated to 32-bits and later zero extended on 64-bit host. So it will mmap() to 0x0000000082080000, but returned pointer has abi_long type, consequently 0x82080000 gets signed extended, thus v0=0xffffffff82080000. Therefore referencing v0 causes segfault as this is different address than mmap'ed.
In N64 everything works just fine because QEMU always refers to 0x0000000082080000 address.
I attached a patch which makes mmap() syscall to return zero extended address in MIPSN32. I doubt this is a proper fix, just a workaround for this particular case to give an idea where is the issue.
Comments
Matthew Fortune wrote:
For N32 (and all MIPS ABIs really it makes more sense to have pointers represented as abi_long
rather than abi_ulong. This is because of the natural sign extended behaviour of addresses
for MIPS but you will only see the effect for N32 which is presumably why we have ended
up with a number of qemu user-mode issues for N32.
Indeed, the fix I believe should be on the other side of the mmap and the type of the
argument needs changing if at all possible.
Current patch
The text was updated successfully, but these errors were encountered: