From 84c13ab4da8dff4b2f30e49d5161e82ceee6d573 Mon Sep 17 00:00:00 2001 In-Reply-To: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> References: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> From: Stacey Son Date: Mon, 7 Oct 2013 13:24:20 -0500 Subject: [PATCH v3 12/19] bsd-user: add support for memory management related syscalls This change adds support or stubs for memory management related system calls including mmap(2), munmap(2), mprotect(2), msync(2), mlock(2), munlock(2), mlockall(2), munlockall(2), madvise(2), minherit(2), mincore(2), shm_open(2), shm_unlink(2), shmget(2), shmctl(2), shmat(2), shmdt(2), vadvise(), sbrk(), sstk(), and freebsd6_mmap(). --- bsd-user/Makefile.objs | 2 +- bsd-user/bsd-mem.c | 122 +++++++++++++++ bsd-user/bsd-mem.h | 393 ++++++++++++++++++++++++++++++++++++++++++++++++ bsd-user/mmap.c | 178 ++++++++-------------- bsd-user/qemu-bsd.h | 10 ++ bsd-user/qemu.h | 3 +- bsd-user/syscall.c | 174 +++++++++++++--------- 7 files changed, 700 insertions(+), 182 deletions(-) create mode 100644 bsd-user/bsd-mem.c create mode 100644 bsd-user/bsd-mem.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index caf95ed..77709cd 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,5 +1,5 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - uaccess.o bsd-proc.o \ + uaccess.o bsd-mem.o bsd-proc.o \ $(HOST_VARIANT_DIR)/os-proc.o \ $(HOST_VARIANT_DIR)/os-stat.o \ $(HOST_VARIANT_DIR)/os-sys.o \ diff --git a/bsd-user/bsd-mem.c b/bsd-user/bsd-mem.c new file mode 100644 index 0000000..bfe03aa --- /dev/null +++ b/bsd-user/bsd-mem.c @@ -0,0 +1,122 @@ +/* + * memory management system conversion routines + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "qemu.h" +#include "qemu-bsd.h" + +struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS]; + +abi_ulong bsd_target_brk; +abi_ulong bsd_target_original_brk; + +void target_set_brk(abi_ulong new_brk) +{ + + bsd_target_original_brk = bsd_target_brk = HOST_PAGE_ALIGN(new_brk); +} + +abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, + abi_ulong target_addr) +{ + struct target_ipc_perm *target_ip; + + if (!lock_user_struct(VERIFY_READ, target_ip, target_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(host_ip->cuid, &target_ip->cuid); + __get_user(host_ip->cgid, &target_ip->cgid); + __get_user(host_ip->uid, &target_ip->uid); + __get_user(host_ip->gid, &target_ip->gid); + __get_user(host_ip->mode, &target_ip->mode); + __get_user(host_ip->seq, &target_ip->seq); + __get_user(host_ip->key, &target_ip->key); + unlock_user_struct(target_ip, target_addr, 0); + + return 0; +} + +abi_long host_to_target_ipc_perm(abi_ulong target_addr, + struct ipc_perm *host_ip) +{ + struct target_ipc_perm *target_ip; + + if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_ip->cuid, &target_ip->cuid); + __put_user(host_ip->cgid, &target_ip->cgid); + __put_user(host_ip->uid, &target_ip->uid); + __put_user(host_ip->gid, &target_ip->gid); + __put_user(host_ip->mode, &target_ip->mode); + __put_user(host_ip->seq, &target_ip->seq); + __put_user(host_ip->key, &target_ip->key); + unlock_user_struct(target_ip, target_addr, 1); + + return 0; +} + +abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) { + return -TARGET_EFAULT; + } + if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) { + return -TARGET_EFAULT; + } + __get_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __get_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __get_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __get_user(host_sd->shm_nattch, &target_sd->shm_nattch); + __get_user(host_sd->shm_atime, &target_sd->shm_atime); + __get_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __get_user(host_sd->shm_ctime, &target_sd->shm_ctime); + unlock_user_struct(target_sd, target_addr, 0); + + return 0; +} + +abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) { + return -TARGET_EFAULT; + } + if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) { + return -TARGET_EFAULT; + } + __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); + __put_user(host_sd->shm_atime, &target_sd->shm_atime); + __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); + unlock_user_struct(target_sd, target_addr, 1); + + return 0; +} + diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h new file mode 100644 index 0000000..88c01ec --- /dev/null +++ b/bsd-user/bsd-mem.h @@ -0,0 +1,393 @@ +/* + * memory management system call shims and definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/*-- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BSD_MMAN_H_ +#define _BSD_MMAN_H_ + +#include +#include +#include +#include +#include + +#include "qemu-bsd.h" + +extern struct bsd_shm_regions bsd_shm_regions[]; +extern abi_ulong bsd_target_brk; +extern abi_ulong bsd_target_original_brk; + +/* mmap(2) */ +static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8) +{ + + if (regpairs_aligned(cpu_env) != 0) { + arg6 = arg7; + arg7 = arg8; + } + return get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, + target_offset64(arg6, arg7))); +} + +/* munmap(2) */ +static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2) +{ + + return get_errno(target_munmap(arg1, arg2)); +} + +/* mprotect(2) */ +static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + return get_errno(target_mprotect(arg1, arg2, arg3)); +} + +/* msync(2) */ +static inline abi_long do_bsd_msync(abi_long arg1, abi_long arg2, abi_long arg3) +{ + + return get_errno(msync(g2h(arg1), arg2, arg3)); +} + +/* mlock(2) */ +static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2) +{ + + return get_errno(mlock(g2h(arg1), arg2)); +} + +/* munlock(2) */ +static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2) +{ + + return get_errno(munlock(g2h(arg1), arg2)); +} + +/* mlockall(2) */ +static inline abi_long do_bsd_mlockall(abi_long arg1) +{ + + return get_errno(mlockall(arg1)); +} + +/* munlockall(2) */ +static inline abi_long do_bsd_munlockall(void) +{ + + return get_errno(munlockall()); +} + +/* madvise(2) */ +static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + /* + * A straight passthrough may not be safe because qemu sometimes + * turns private file-backed mapping into anonymous mappings. This + * will break MADV_DONTNEED. This is a hint, so ignoring and returing + * success is ok. + */ + return get_errno(0); +} + +/* minherit(2) */ +static inline abi_long do_bsd_minherit(abi_long addr, abi_long len, + abi_long inherit) +{ + + return get_errno(minherit(g2h(addr), len, inherit)); +} + +/* mincore(2) */ +static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len, + abi_ulong target_vec) +{ + abi_long ret; + void *p, *a; + + a = lock_user(VERIFY_WRITE, target_addr, len, 0); + if (a == NULL) { + return -TARGET_EFAULT; + } + p = lock_user_string(target_vec); + if (p == NULL) { + unlock_user(a, target_addr, 0); + return -TARGET_EFAULT; + } + ret = get_errno(mincore(a, len, p)); + unlock_user(p, target_vec, ret); + unlock_user(a, target_addr, 0); + + return ret; +} + +/* break() XXX this needs some more work. */ +static inline abi_long do_obreak(abi_ulong new_brk) +{ + abi_ulong brk_page; + abi_long mapped_addr; + int new_alloc_size; + + return -TARGET_EINVAL; + + if (!new_brk) { + return 0; + } + if (new_brk < bsd_target_original_brk) { + return -TARGET_EINVAL; + } + + brk_page = HOST_PAGE_ALIGN(bsd_target_brk); + + /* If the new brk is less than this, set it and we're done... */ + if (new_brk < brk_page) { + bsd_target_brk = new_brk; + return 0; + } + + /* We need to allocate more memory after the brk... */ + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)); + + if (!is_error(mapped_addr)) { + bsd_target_brk = new_brk; + } else { + return mapped_addr; + } + + return 0; +} + +/* shm_open(2) */ +static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2, + abi_long arg3) +{ + int ret; + void *p; + + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(shm_open(path(p), + target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); + unlock_user(p, arg1, 0); + + return ret; +} + +/* shm_unlink(2) */ +static inline abi_long do_bsd_shm_unlink(abi_ulong arg1) +{ + int ret; + void *p; + + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(shm_unlink(p)); /* XXX path(p)? */ + unlock_user(p, arg1, 0); + + return ret; +} + +/* shmget(2) */ +static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2, + abi_long arg3) +{ + + return get_errno(shmget(arg1, arg2, arg3)); +} + +/* shmctl(2) */ +static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd, + abi_ulong buff) +{ + struct shmid_ds dsarg; + abi_long ret = -TARGET_EINVAL; + + cmd &= 0xff; + + switch (cmd) { + case IPC_STAT: + case IPC_SET: + if (target_to_host_shmid_ds(&dsarg, buff)) { + return -TARGET_EFAULT; + } + ret = get_errno(shmctl(shmid, cmd, &dsarg)); + if (host_to_target_shmid_ds(buff, &dsarg)) { + return -TARGET_EFAULT; + } + break; + + case IPC_RMID: + ret = get_errno(shmctl(shmid, cmd, NULL)); + break; + + default: + ret = -TARGET_EINVAL; + break; + } + + return ret; +} + +/* shmat(2) */ +static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg) +{ + abi_ulong raddr; + abi_long ret; + void *host_raddr; + struct shmid_ds shm_info; + int i; + + /* Find out the length of the shared memory segment. */ + ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* Can't get the length */ + return ret; + } + + mmap_lock(); + + if (shmaddr) { + host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg); + } else { + abi_ulong mmap_start; + + mmap_start = mmap_find_vma(0, shm_info.shm_segsz); + + if (mmap_start == -1) { + errno = ENOMEM; + host_raddr = (void *)-1; + } else { + host_raddr = shmat(shmid, g2h(mmap_start), + shmflg /* | SHM_REMAP */); + } + } + + if (host_raddr == (void *)-1) { + mmap_unlock(); + return get_errno((long)host_raddr); + } + raddr = h2g((unsigned long)host_raddr); + + page_set_flags(raddr, raddr + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | ((shmflg & SHM_RDONLY) ? 0 : PAGE_WRITE)); + + for (i = 0; i < N_BSD_SHM_REGIONS; i++) { + if (bsd_shm_regions[i].start == 0) { + bsd_shm_regions[i].start = raddr; + bsd_shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + + mmap_unlock(); + return raddr; +} + +/* shmdt(2) */ +static inline abi_long do_bsd_shmdt(abi_ulong shmaddr) +{ + int i; + + for (i = 0; i < N_BSD_SHM_REGIONS; ++i) { + if (bsd_shm_regions[i].start == shmaddr) { + bsd_shm_regions[i].start = 0; + page_set_flags(shmaddr, + shmaddr + bsd_shm_regions[i].size, 0); + break; + } + } + + return get_errno(shmdt(g2h(shmaddr))); +} + + +static inline abi_long do_bsd_vadvise(void) +{ + /* See sys_ovadvise() in vm_unix.c */ + qemu_log("qemu: Unsupported syscall vadvise()\n"); + return -TARGET_ENOSYS; +} + +static inline abi_long do_bsd_sbrk(void) +{ + /* see sys_sbrk() in vm_mmap.c */ + qemu_log("qemu: Unsupported syscall sbrk()\n"); + return -TARGET_ENOSYS; +} + +static inline abi_long do_bsd_sstk(void) +{ + /* see sys_sstk() in vm_mmap.c */ + qemu_log("qemu: Unsupported syscall sstk()\n"); + return -TARGET_ENOSYS; +} + +/* + * undocumented freebsd6_mmap(caddr_t addr, size_t len, int prot, int + * flags, int fd, int pad, off_t pos) system call. + */ +static inline abi_long do_bsd_freebsd6_mmap(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, + abi_long arg7) +{ + + qemu_log("qemu: Unsupported syscall freebsd6_mmap()\n"); + return -TARGET_ENOSYS; +} + +#endif /* !_BSD_MMAN_H_ */ diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index aae8ea1..96a09f3 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -1,4 +1,4 @@ -/* +/** * mmap support for qemu * * Copyright (c) 2003 - 2008 Fabrice Bellard @@ -26,13 +26,11 @@ #include "qemu.h" #include "qemu-common.h" -#include "bsd-mman.h" -//#define DEBUG_MMAP +// #define DEBUG_MMAP -#if defined(CONFIG_USE_NPTL) -pthread_mutex_t mmap_mutex; -static int __thread mmap_lock_count; +pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; +static __thread int mmap_lock_count; void mmap_lock(void) { @@ -63,76 +61,6 @@ void mmap_fork_end(int child) else pthread_mutex_unlock(&mmap_mutex); } -#else -/* We aren't threadsafe to start with, so no need to worry about locking. */ -void mmap_lock(void) -{ -} - -void mmap_unlock(void) -{ -} -#endif - -static void *bsd_vmalloc(size_t size) -{ - void *p; - mmap_lock(); - /* Use map and mark the pages as used. */ - p = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); - - if (h2g_valid(p)) { - /* Allocated region overlaps guest address space. - This may recurse. */ - abi_ulong addr = h2g(p); - page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size), - PAGE_RESERVED); - } - - mmap_unlock(); - return p; -} - -void *g_malloc(size_t size) -{ - char * p; - size += 16; - p = bsd_vmalloc(size); - *(size_t *)p = size; - return p + 16; -} - -/* We use map, which is always zero initialized. */ -void * g_malloc0(size_t size) -{ - return g_malloc(size); -} - -void g_free(void *ptr) -{ - /* FIXME: We should unmark the reserved pages here. However this gets - complicated when one target page spans multiple host pages, so we - don't bother. */ - size_t *p; - p = (size_t *)((char *)ptr - 16); - munmap(p, *p); -} - -void *g_realloc(void *ptr, size_t size) -{ - size_t old_size, copy; - void *new_ptr; - - if (!ptr) - return g_malloc(size); - old_size = *(size_t *)((char *)ptr - 16); - copy = old_size < size ? old_size : size; - new_ptr = g_malloc(size); - memcpy(new_ptr, ptr, copy); - g_free(ptr); - return new_ptr; -} /* NOTE: all the constants are the HOST ones, but addresses are target. */ int target_mprotect(abi_ulong start, abi_ulong len, int prot) @@ -164,11 +92,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) if (start > host_start) { /* handle host page containing start */ prot1 = prot; - for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } if (host_end == host_start + qemu_host_page_size) { - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } end = host_end; @@ -180,7 +108,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) } if (end < host_end) { prot1 = prot; - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, @@ -218,7 +146,7 @@ static int mmap_frag(abi_ulong real_start, /* get the protection of the target pages outside the mapping */ prot1 = 0; - for(addr = real_start; addr < real_end; addr++) { + for (addr = real_start; addr < real_end; addr++) { if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } @@ -238,15 +166,19 @@ static int mmap_frag(abi_ulong real_start, /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED && - (prot & PROT_WRITE)) + (prot & PROT_WRITE)) { return -1; + } /* adjust protection to be able to read */ - if (!(prot1 & PROT_WRITE)) + if (!(prot1 & PROT_WRITE)) { mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); + } /* read the corresponding file data */ - pread(fd, g2h(start), end - start, offset); + if (pread(fd, g2h(start), end - start, offset) == -1) { + return -1; + } /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) @@ -269,13 +201,14 @@ static abi_ulong mmap_next_start = 0x40000000; unsigned long last_brk; -/* find a free memory area of size 'size'. The search starts at - 'start'. If 'start' == 0, then a default start address is used. - Return -1 if error. -*/ +/* + * Find a free memory area of size 'size'. The search starts at + * 'start'. If 'start' == 0, then a default start address is used. + * Return -1 if error. + */ /* page_init() marks pages used by the host as reserved to be sure not to use them. */ -static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) { abi_ulong addr, addr1, addr_start; int prot; @@ -300,9 +233,9 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) if (addr == 0) addr = mmap_next_start; addr_start = addr; - for(;;) { + for (;;) { prot = 0; - for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { + for (addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr1); } if (prot == 0) @@ -319,9 +252,10 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) /* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, - int flags, int fd, abi_ulong offset) + int flags, int fd, off_t offset) { - abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + abi_ulong ret, end, real_start, real_end, retaddr, host_len; + off_t host_offset; unsigned long host_start; mmap_lock(); @@ -337,21 +271,38 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, printf("MAP_FIXED "); if (flags & MAP_ANON) printf("MAP_ANON "); - switch(flags & TARGET_BSD_MAP_FLAGMASK) { - case MAP_PRIVATE: - printf("MAP_PRIVATE "); - break; - case MAP_SHARED: - printf("MAP_SHARED "); - break; - default: - printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK); - break; - } - printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); + if (flags & MAP_PRIVATE) + printf("MAP_PRIVATE "); + if (flags & MAP_SHARED) + printf("MAP_SHARED "); + if (flags & MAP_NOCORE) + printf("MAP_NOCORE "); +#ifdef MAP_STACK + if (flags & MAP_STACK) + printf("MAP_STACK "); +#endif + printf("fd=%d offset=0x%llx\n", fd, offset); } #endif + /* + * Enforce the constraints. + */ + if (len == 0 && fd != -1) { + errno = EINVAL; + goto fail; + } + +#ifdef MAP_STACK + if (flags & MAP_STACK) { + if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) != + (PROT_READ | PROT_WRITE))) { + errno = EINVAL; + goto fail; + } + } +#endif /* MAP_STACK */ + if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; @@ -378,8 +329,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, qemu_real_host_page_size */ p = mmap(g2h(mmap_start), host_len, prot, flags | MAP_FIXED, fd, host_offset); - if (p == MAP_FAILED) + if (p == MAP_FAILED) { goto fail; + } /* update start so that it points to the file position at 'offset' */ host_start = (unsigned long)p; if (!(flags & MAP_ANON)) @@ -396,7 +348,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, end = start + len; real_end = HOST_PAGE_ALIGN(end); - for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { flg = page_get_flags(addr); if (flg & PAGE_RESERVED) { errno = ENXIO; @@ -493,7 +445,9 @@ int target_munmap(abi_ulong start, abi_ulong len) int prot, ret; #ifdef DEBUG_MMAP - printf("munmap: start=0x%lx len=0x%lx\n", start, len); + printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x" + TARGET_ABI_FMT_lx "\n", + start, len); #endif if (start & ~TARGET_PAGE_MASK) return -EINVAL; @@ -508,11 +462,11 @@ int target_munmap(abi_ulong start, abi_ulong len) if (start > real_start) { /* handle host page containing start */ prot = 0; - for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (real_end == real_start + qemu_host_page_size) { - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } end = real_end; @@ -522,7 +476,7 @@ int target_munmap(abi_ulong start, abi_ulong len) } if (end < real_end) { prot = 0; - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (prot != 0) @@ -535,8 +489,10 @@ int target_munmap(abi_ulong start, abi_ulong len) ret = munmap(g2h(real_start), real_end - real_start); } - if (ret == 0) + if (ret == 0) { page_set_flags(start, start + len, 0); + tb_invalidate_phys_range(start, start + len, 0); + } mmap_unlock(); return ret; } diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h index 590c36b..f562aad 100644 --- a/bsd-user/qemu-bsd.h +++ b/bsd-user/qemu-bsd.h @@ -32,6 +32,16 @@ #include #include +/* bsd-mem.c */ +abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, + abi_ulong target_addr); +abi_long host_to_target_ipc_perm(abi_ulong target_addr, + struct ipc_perm *host_ip); +abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr); +abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd); + /* bsd-proc.c */ int target_to_host_resource(int code); rlim_t target_to_host_rlim(abi_ulong target_rlim); diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index e668a67..613a89e 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -219,7 +219,7 @@ void QEMU_NORETURN force_sig(int target_sig); /* mmap.c */ int target_mprotect(abi_ulong start, abi_ulong len, int prot); abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, - int flags, int fd, abi_ulong offset); + int flags, int fd, off_t offset); int target_munmap(abi_ulong start, abi_ulong len); abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, @@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; void mmap_lock(void); void mmap_unlock(void); +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size); void cpu_list_lock(void); void cpu_list_unlock(void); #if defined(CONFIG_USE_NPTL) diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 633d638..e3967fa 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -17,22 +17,16 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#include #include #include #include #include #include -#include -#include #include -#include #include -#include #include #include #include -#include #include "qemu.h" #include "qemu-common.h" @@ -42,6 +36,7 @@ static int host_to_target_errno(int err); /* BSD independent syscall shims */ #include "bsd-file.h" +#include "bsd-mem.h" #include "bsd-proc.h" #include "bsd-signal.h" @@ -53,19 +48,18 @@ static int host_to_target_errno(int err); /* #define DEBUG */ -static abi_ulong target_brk; -static abi_ulong target_original_brk; - /* * errno conversion. */ abi_long get_errno(abi_long ret) { - if (ret == -1) + + if (ret == -1) { /* XXX need to translate host -> target errnos here */ return -(errno); - else + } else { return ret; + } } static int host_to_target_errno(int err) @@ -76,46 +70,8 @@ static int host_to_target_errno(int err) int is_error(abi_long ret) { - return (abi_ulong)ret >= (abi_ulong)(-4096); -} -void target_set_brk(abi_ulong new_brk) -{ - target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); -} - -/* do_obreak() must return target errnos. */ -static abi_long do_obreak(abi_ulong new_brk) -{ - abi_ulong brk_page; - abi_long mapped_addr; - int new_alloc_size; - - if (!new_brk) - return 0; - if (new_brk < target_original_brk) - return -TARGET_EINVAL; - - brk_page = HOST_PAGE_ALIGN(target_brk); - - /* If the new brk is less than this, set it and we're done... */ - if (new_brk < brk_page) { - target_brk = new_brk; - return 0; - } - - /* We need to allocate more memory after the brk... */ - new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); - mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, - PROT_READ|PROT_WRITE, - MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)); - - if (!is_error(mapped_addr)) - target_brk = new_brk; - else - return mapped_addr; - - return 0; + return (abi_ulong)ret >= (abi_ulong)(-4096); } /* FIXME @@ -169,6 +125,13 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, return 0; } + +/* stub for arm semihosting support */ +abi_long do_brk(abi_ulong new_brk) +{ + return do_obreak(new_brk); +} + /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_. */ @@ -340,6 +303,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */ ret = do_freebsd_getloginclass(arg1, arg2); break; + #if 0 case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */ ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4); @@ -417,6 +381,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */ ret = do_freebsd_auditctl(arg1); break; + case TARGET_FREEBSD_NR_utrace: /* utrace(2) */ ret = do_bsd_utrace(arg1, arg2); break; @@ -434,6 +399,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; + /* * File system calls. */ @@ -807,20 +773,95 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; + /* + * Memory management system calls. + */ + case TARGET_FREEBSD_NR_mmap: /* mmap(2) */ + ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8); + break; + + case TARGET_FREEBSD_NR_munmap: /* munmap(2) */ + ret = do_bsd_munmap(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */ + ret = do_bsd_mprotect(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_msync: /* msync(2) */ + ret = do_bsd_msync(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_mlock: /* mlock(2) */ + ret = do_bsd_mlock(arg1, arg2); + break; - case TARGET_FREEBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + case TARGET_FREEBSD_NR_munlock: /* munlock(2) */ + ret = do_bsd_munlock(arg1, arg2); break; - case TARGET_FREEBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); + + case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */ + ret = do_bsd_mlockall(arg1); break; - case TARGET_FREEBSD_NR_break: - ret = do_obreak(arg1); + + case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */ + ret = do_bsd_munlockall(); + break; + + case TARGET_FREEBSD_NR_madvise: /* madvise(2) */ + ret = do_bsd_madvise(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_minherit: /* minherit(2) */ + ret = do_bsd_minherit(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_mincore: /* mincore(2) */ + ret = do_bsd_mincore(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_shm_open: /* shm_open(2) */ + ret = do_bsd_shm_open(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */ + ret = do_bsd_shm_unlink(arg1); + break; + + case TARGET_FREEBSD_NR_shmget: /* shmget(2) */ + ret = do_bsd_shmget(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */ + ret = do_bsd_shmctl(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_shmat: /* shmat(2) */ + ret = do_bsd_shmat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */ + ret = do_bsd_shmdt(arg1); + break; + + case TARGET_FREEBSD_NR_vadvise: + ret = do_bsd_vadvise(); + break; + + case TARGET_FREEBSD_NR_sbrk: + ret = do_bsd_sbrk(); + break; + + case TARGET_FREEBSD_NR_sstk: + ret = do_bsd_sstk(); + break; + + case TARGET_FREEBSD_NR_freebsd6_mmap: /* undocumented */ + ret = do_bsd_freebsd6_mmap(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + break; + + /* * time related system calls. */ @@ -997,6 +1038,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, arg8)); break; } + #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif @@ -1033,13 +1075,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NETBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); break; case TARGET_NETBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); + ret = do_bsd_mprotect(arg1, arg2, arg3); break; case TARGET_NETBSD_NR_syscall: @@ -1086,13 +1125,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_OPENBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); break; case TARGET_OPENBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); + ret = do_bsd_mprotect(arg1, arg2, arg3); break; case TARGET_OPENBSD_NR_syscall: -- 1.7.8