linux-user: Move shmat and shmdt implementations to mmap.c
Rename from do_* to target_*. Fix some minor checkpatch errors. Tested-by: Helge Deller <deller@gmx.de> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Warner Losh <imp@bsdimp.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
f6d4554242
commit
225a206c44
@ -17,6 +17,7 @@
|
|||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include <sys/shm.h>
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
@ -27,6 +28,14 @@
|
|||||||
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static __thread int mmap_lock_count;
|
static __thread int mmap_lock_count;
|
||||||
|
|
||||||
|
#define N_SHM_REGIONS 32
|
||||||
|
|
||||||
|
static struct shm_region {
|
||||||
|
abi_ulong start;
|
||||||
|
abi_ulong size;
|
||||||
|
bool in_use;
|
||||||
|
} shm_regions[N_SHM_REGIONS];
|
||||||
|
|
||||||
void mmap_lock(void)
|
void mmap_lock(void)
|
||||||
{
|
{
|
||||||
if (mmap_lock_count++ == 0) {
|
if (mmap_lock_count++ == 0) {
|
||||||
@ -981,3 +990,132 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TARGET_FORCE_SHMLBA
|
||||||
|
/*
|
||||||
|
* For most architectures, SHMLBA is the same as the page size;
|
||||||
|
* some architectures have larger values, in which case they should
|
||||||
|
* define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
|
||||||
|
* This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
|
||||||
|
* and defining its own value for SHMLBA.
|
||||||
|
*
|
||||||
|
* The kernel also permits SHMLBA to be set by the architecture to a
|
||||||
|
* value larger than the page size without setting __ARCH_FORCE_SHMLBA;
|
||||||
|
* this means that addresses are rounded to the large size if
|
||||||
|
* SHM_RND is set but addresses not aligned to that size are not rejected
|
||||||
|
* as long as they are at least page-aligned. Since the only architecture
|
||||||
|
* which uses this is ia64 this code doesn't provide for that oddity.
|
||||||
|
*/
|
||||||
|
static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
|
||||||
|
{
|
||||||
|
return TARGET_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
abi_ulong target_shmat(CPUArchState *cpu_env, int shmid,
|
||||||
|
abi_ulong shmaddr, int shmflg)
|
||||||
|
{
|
||||||
|
CPUState *cpu = env_cpu(cpu_env);
|
||||||
|
abi_ulong raddr;
|
||||||
|
void *host_raddr;
|
||||||
|
struct shmid_ds shm_info;
|
||||||
|
int i, ret;
|
||||||
|
abi_ulong shmlba;
|
||||||
|
|
||||||
|
/* shmat pointers are always untagged */
|
||||||
|
|
||||||
|
/* 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 length, bail out */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
shmlba = target_shmlba(cpu_env);
|
||||||
|
|
||||||
|
if (shmaddr & (shmlba - 1)) {
|
||||||
|
if (shmflg & SHM_RND) {
|
||||||
|
shmaddr &= ~(shmlba - 1);
|
||||||
|
} else {
|
||||||
|
return -TARGET_EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
|
||||||
|
return -TARGET_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mmap_lock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're mapping shared memory, so ensure we generate code for parallel
|
||||||
|
* execution and flush old translations. This will work up to the level
|
||||||
|
* supported by the host -- anything that requires EXCP_ATOMIC will not
|
||||||
|
* be atomic with respect to an external process.
|
||||||
|
*/
|
||||||
|
if (!(cpu->tcg_cflags & CF_PARALLEL)) {
|
||||||
|
cpu->tcg_cflags |= CF_PARALLEL;
|
||||||
|
tb_flush(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shmaddr) {
|
||||||
|
host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
|
||||||
|
} else {
|
||||||
|
abi_ulong mmap_start;
|
||||||
|
|
||||||
|
/* In order to use the host shmat, we need to honor host SHMLBA. */
|
||||||
|
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
|
||||||
|
|
||||||
|
if (mmap_start == -1) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
host_raddr = (void *)-1;
|
||||||
|
} else {
|
||||||
|
host_raddr = shmat(shmid, g2h_untagged(mmap_start),
|
||||||
|
shmflg | SHM_REMAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host_raddr == (void *)-1) {
|
||||||
|
mmap_unlock();
|
||||||
|
return get_errno((intptr_t)host_raddr);
|
||||||
|
}
|
||||||
|
raddr = h2g((uintptr_t)host_raddr);
|
||||||
|
|
||||||
|
page_set_flags(raddr, raddr + shm_info.shm_segsz - 1,
|
||||||
|
PAGE_VALID | PAGE_RESET | PAGE_READ |
|
||||||
|
(shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
|
||||||
|
|
||||||
|
for (i = 0; i < N_SHM_REGIONS; i++) {
|
||||||
|
if (!shm_regions[i].in_use) {
|
||||||
|
shm_regions[i].in_use = true;
|
||||||
|
shm_regions[i].start = raddr;
|
||||||
|
shm_regions[i].size = shm_info.shm_segsz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mmap_unlock();
|
||||||
|
return raddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
abi_long target_shmdt(abi_ulong shmaddr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
abi_long rv;
|
||||||
|
|
||||||
|
/* shmdt pointers are always untagged */
|
||||||
|
|
||||||
|
mmap_lock();
|
||||||
|
|
||||||
|
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
||||||
|
if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
|
||||||
|
shm_regions[i].in_use = false;
|
||||||
|
page_set_flags(shmaddr, shmaddr + shm_regions[i].size - 1, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv = get_errno(shmdt(g2h_untagged(shmaddr)));
|
||||||
|
|
||||||
|
mmap_unlock();
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
@ -3725,14 +3725,6 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define N_SHM_REGIONS 32
|
|
||||||
|
|
||||||
static struct shm_region {
|
|
||||||
abi_ulong start;
|
|
||||||
abi_ulong size;
|
|
||||||
bool in_use;
|
|
||||||
} shm_regions[N_SHM_REGIONS];
|
|
||||||
|
|
||||||
#ifndef TARGET_SEMID64_DS
|
#ifndef TARGET_SEMID64_DS
|
||||||
/* asm-generic version of this struct */
|
/* asm-generic version of this struct */
|
||||||
struct target_semid64_ds
|
struct target_semid64_ds
|
||||||
@ -4482,133 +4474,6 @@ static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TARGET_FORCE_SHMLBA
|
|
||||||
/* For most architectures, SHMLBA is the same as the page size;
|
|
||||||
* some architectures have larger values, in which case they should
|
|
||||||
* define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
|
|
||||||
* This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
|
|
||||||
* and defining its own value for SHMLBA.
|
|
||||||
*
|
|
||||||
* The kernel also permits SHMLBA to be set by the architecture to a
|
|
||||||
* value larger than the page size without setting __ARCH_FORCE_SHMLBA;
|
|
||||||
* this means that addresses are rounded to the large size if
|
|
||||||
* SHM_RND is set but addresses not aligned to that size are not rejected
|
|
||||||
* as long as they are at least page-aligned. Since the only architecture
|
|
||||||
* which uses this is ia64 this code doesn't provide for that oddity.
|
|
||||||
*/
|
|
||||||
static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
|
|
||||||
{
|
|
||||||
return TARGET_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static abi_ulong do_shmat(CPUArchState *cpu_env, int shmid,
|
|
||||||
abi_ulong shmaddr, int shmflg)
|
|
||||||
{
|
|
||||||
CPUState *cpu = env_cpu(cpu_env);
|
|
||||||
abi_ulong raddr;
|
|
||||||
void *host_raddr;
|
|
||||||
struct shmid_ds shm_info;
|
|
||||||
int i, ret;
|
|
||||||
abi_ulong shmlba;
|
|
||||||
|
|
||||||
/* shmat pointers are always untagged */
|
|
||||||
|
|
||||||
/* 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 length, bail out */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
shmlba = target_shmlba(cpu_env);
|
|
||||||
|
|
||||||
if (shmaddr & (shmlba - 1)) {
|
|
||||||
if (shmflg & SHM_RND) {
|
|
||||||
shmaddr &= ~(shmlba - 1);
|
|
||||||
} else {
|
|
||||||
return -TARGET_EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
|
|
||||||
return -TARGET_EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mmap_lock();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We're mapping shared memory, so ensure we generate code for parallel
|
|
||||||
* execution and flush old translations. This will work up to the level
|
|
||||||
* supported by the host -- anything that requires EXCP_ATOMIC will not
|
|
||||||
* be atomic with respect to an external process.
|
|
||||||
*/
|
|
||||||
if (!(cpu->tcg_cflags & CF_PARALLEL)) {
|
|
||||||
cpu->tcg_cflags |= CF_PARALLEL;
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shmaddr)
|
|
||||||
host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
|
|
||||||
else {
|
|
||||||
abi_ulong mmap_start;
|
|
||||||
|
|
||||||
/* In order to use the host shmat, we need to honor host SHMLBA. */
|
|
||||||
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
|
|
||||||
|
|
||||||
if (mmap_start == -1) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
host_raddr = (void *)-1;
|
|
||||||
} else
|
|
||||||
host_raddr = shmat(shmid, g2h_untagged(mmap_start),
|
|
||||||
shmflg | SHM_REMAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (host_raddr == (void *)-1) {
|
|
||||||
mmap_unlock();
|
|
||||||
return get_errno((intptr_t)host_raddr);
|
|
||||||
}
|
|
||||||
raddr = h2g((uintptr_t)host_raddr);
|
|
||||||
|
|
||||||
page_set_flags(raddr, raddr + shm_info.shm_segsz - 1,
|
|
||||||
PAGE_VALID | PAGE_RESET | PAGE_READ |
|
|
||||||
(shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
|
|
||||||
|
|
||||||
for (i = 0; i < N_SHM_REGIONS; i++) {
|
|
||||||
if (!shm_regions[i].in_use) {
|
|
||||||
shm_regions[i].in_use = true;
|
|
||||||
shm_regions[i].start = raddr;
|
|
||||||
shm_regions[i].size = shm_info.shm_segsz;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mmap_unlock();
|
|
||||||
return raddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline abi_long do_shmdt(abi_ulong shmaddr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
abi_long rv;
|
|
||||||
|
|
||||||
/* shmdt pointers are always untagged */
|
|
||||||
|
|
||||||
mmap_lock();
|
|
||||||
|
|
||||||
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
|
||||||
if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
|
|
||||||
shm_regions[i].in_use = false;
|
|
||||||
page_set_flags(shmaddr, shmaddr + shm_regions[i].size - 1, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rv = get_errno(shmdt(g2h_untagged(shmaddr)));
|
|
||||||
|
|
||||||
mmap_unlock();
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TARGET_NR_ipc
|
#ifdef TARGET_NR_ipc
|
||||||
/* ??? This only works with linear mappings. */
|
/* ??? This only works with linear mappings. */
|
||||||
/* do_ipc() must return target values and target errnos. */
|
/* do_ipc() must return target values and target errnos. */
|
||||||
@ -4695,7 +4560,7 @@ static abi_long do_ipc(CPUArchState *cpu_env,
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
abi_ulong raddr;
|
abi_ulong raddr;
|
||||||
raddr = do_shmat(cpu_env, first, ptr, second);
|
raddr = target_shmat(cpu_env, first, ptr, second);
|
||||||
if (is_error(raddr))
|
if (is_error(raddr))
|
||||||
return get_errno(raddr);
|
return get_errno(raddr);
|
||||||
if (put_user_ual(raddr, third))
|
if (put_user_ual(raddr, third))
|
||||||
@ -4708,7 +4573,7 @@ static abi_long do_ipc(CPUArchState *cpu_env,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IPCOP_shmdt:
|
case IPCOP_shmdt:
|
||||||
ret = do_shmdt(ptr);
|
ret = target_shmdt(ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPCOP_shmget:
|
case IPCOP_shmget:
|
||||||
@ -11008,11 +10873,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_shmat
|
#ifdef TARGET_NR_shmat
|
||||||
case TARGET_NR_shmat:
|
case TARGET_NR_shmat:
|
||||||
return do_shmat(cpu_env, arg1, arg2, arg3);
|
return target_shmat(cpu_env, arg1, arg2, arg3);
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_shmdt
|
#ifdef TARGET_NR_shmdt
|
||||||
case TARGET_NR_shmdt:
|
case TARGET_NR_shmdt:
|
||||||
return do_shmdt(arg1);
|
return target_shmdt(arg1);
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_fsync:
|
case TARGET_NR_fsync:
|
||||||
return get_errno(fsync(arg1));
|
return get_errno(fsync(arg1));
|
||||||
|
@ -58,4 +58,8 @@ abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong);
|
|||||||
void mmap_fork_start(void);
|
void mmap_fork_start(void);
|
||||||
void mmap_fork_end(int child);
|
void mmap_fork_end(int child);
|
||||||
|
|
||||||
|
abi_ulong target_shmat(CPUArchState *cpu_env, int shmid,
|
||||||
|
abi_ulong shmaddr, int shmflg);
|
||||||
|
abi_long target_shmdt(abi_ulong shmaddr);
|
||||||
|
|
||||||
#endif /* LINUX_USER_USER_MMAP_H */
|
#endif /* LINUX_USER_USER_MMAP_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user