diff options
author | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-12-08 18:12:40 +0000 |
---|---|---|
committer | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-12-08 18:12:40 +0000 |
commit | f19412a2a6346ff4976d57c2692464f7cd8fa7eb (patch) | |
tree | 33629f97d72a2bb245d4eea9bad8c9dadb4a371a /linux-user | |
parent | 45bc1f5264a6835239e1c183b78d40bb45310f6c (diff) |
linux-user: mremap(): handle MREMAP_FIXED and MREMAP_MAYMOVE correctly
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5959 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/mmap.c | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 2d0c684f4c..aad00e6175 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -537,19 +537,41 @@ int target_munmap(abi_ulong start, abi_ulong len) return ret; } -/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED - blocks which have been allocated starting on a host page */ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, abi_ulong new_addr) { int prot; - unsigned long host_addr; + void *host_addr; mmap_lock(); - /* XXX: use 5 args syscall */ - host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr == -1) { + + if (flags & MREMAP_FIXED) + host_addr = mremap(g2h(old_addr), old_size, new_size, + flags, new_addr); + else if (flags & MREMAP_MAYMOVE) { + abi_ulong mmap_start; + + mmap_start = mmap_find_vma(0, new_size); + + if (mmap_start == -1) { + errno = ENOMEM; + host_addr = MAP_FAILED; + } else + host_addr = mremap(g2h(old_addr), old_size, new_size, + flags | MREMAP_FIXED, g2h(mmap_start)); + } else { + host_addr = mremap(g2h(old_addr), old_size, new_size, flags); + /* Check if address fits target address space */ + if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { + /* Revert mremap() changes */ + host_addr = mremap(g2h(old_addr), new_size, old_size, flags); + errno = ENOMEM; + host_addr = MAP_FAILED; + } + } + + if (host_addr == MAP_FAILED) { new_addr = -1; } else { new_addr = h2g(host_addr); |