blob: 3e1968718fb27913b7e14bdcdab4daead3c6a2b9 [file] [log] [blame]
/*
* BSD misc system call conversions routines
*
* Copyright (c) 2013 Stacey D. Son
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#define _WANT_SEMUN
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/uuid.h>
#include "qemu.h"
#include "qemu-bsd.h"
/*
* BSD uuidgen(2) struct uuid conversion
*/
abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
{
struct target_uuid *target_uuid;
if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0)) {
return -TARGET_EFAULT;
}
__put_user(host_uuid->time_low, &target_uuid->time_low);
__put_user(host_uuid->time_mid, &target_uuid->time_mid);
__put_user(host_uuid->time_hi_and_version,
&target_uuid->time_hi_and_version);
host_uuid->clock_seq_hi_and_reserved =
target_uuid->clock_seq_hi_and_reserved;
host_uuid->clock_seq_low = target_uuid->clock_seq_low;
memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
unlock_user_struct(target_uuid, target_addr, 1);
return 0;
}
abi_long target_to_host_semarray(int semid, unsigned short **host_array,
abi_ulong target_addr)
{
abi_long ret;
int nsems, i;
unsigned short *array;
union semun semun;
struct semid_ds semid_ds;
semun.buf = &semid_ds;
ret = semctl(semid, 0, IPC_STAT, semun);
if (ret == -1) {
return get_errno(ret);
}
nsems = semid_ds.sem_nsems;
*host_array = g_new(unsigned short, nsems);
array = lock_user(VERIFY_READ, target_addr,
nsems * sizeof(unsigned short), 1);
if (array == NULL) {
free(*host_array);
return -TARGET_EFAULT;
}
for (i = 0; i < nsems; i++) {
__get_user((*host_array)[i], array + i);
}
unlock_user(array, target_addr, 0);
return 0;
}
abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
unsigned short **host_arrayp)
{
g_autofree unsigned short *host_array = *host_arrayp;
abi_long ret;
int nsems, i;
unsigned short *array;
union semun semun;
struct semid_ds semid_ds;
semun.buf = &semid_ds;
ret = semctl(semid, 0, IPC_STAT, semun);
if (ret == -1) {
return get_errno(ret);
}
nsems = semid_ds.sem_nsems;
array = (unsigned short *)lock_user(VERIFY_WRITE, target_addr,
nsems * sizeof(unsigned short), 0);
if (array == NULL) {
return -TARGET_EFAULT;
}
for (i = 0; i < nsems; i++) {
__put_user(array[i], host_array + i);
}
unlock_user(array, target_addr, 1);
return 0;
}
abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
abi_ulong target_addr)
{
struct target_semid_ds *target_sd;
if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
return -TARGET_EFAULT;
}
target_to_host_ipc_perm__locked(&host_sd->sem_perm, &target_sd->sem_perm);
/* sem_base is not used by kernel for IPC_STAT/IPC_SET */
/* host_sd->sem_base = g2h_untagged(target_sd->sem_base); */
__get_user(host_sd->sem_nsems, &target_sd->sem_nsems);
__get_user(host_sd->sem_otime, &target_sd->sem_otime);
__get_user(host_sd->sem_ctime, &target_sd->sem_ctime);
unlock_user_struct(target_sd, target_addr, 0);
return 0;
}
abi_long host_to_target_semid_ds(abi_ulong target_addr,
struct semid_ds *host_sd)
{
struct target_semid_ds *target_sd;
if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
return -TARGET_EFAULT;
}
host_to_target_ipc_perm__locked(&target_sd->sem_perm,
&host_sd->sem_perm);
/* sem_base is not used by kernel for IPC_STAT/IPC_SET */
/* target_sd->sem_base = h2g((void *)host_sd->sem_base); */
__put_user(target_sd->sem_nsems, &host_sd->sem_nsems);
__put_user(target_sd->sem_otime, &host_sd->sem_otime);
__put_user(target_sd->sem_ctime, &host_sd->sem_ctime);
unlock_user_struct(target_sd, target_addr, 1);
return 0;
}
abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
abi_ulong target_addr)
{
struct target_msqid_ds *target_md;
if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
return -TARGET_EFAULT;
}
memset(host_md, 0, sizeof(struct msqid_ds));
target_to_host_ipc_perm__locked(&host_md->msg_perm,
&target_md->msg_perm);
/* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
__get_user(host_md->msg_cbytes, &target_md->msg_cbytes);
__get_user(host_md->msg_qnum, &target_md->msg_qnum);
__get_user(host_md->msg_qbytes, &target_md->msg_qbytes);
__get_user(host_md->msg_lspid, &target_md->msg_lspid);
__get_user(host_md->msg_lrpid, &target_md->msg_lrpid);
__get_user(host_md->msg_stime, &target_md->msg_stime);
__get_user(host_md->msg_rtime, &target_md->msg_rtime);
__get_user(host_md->msg_ctime, &target_md->msg_ctime);
unlock_user_struct(target_md, target_addr, 0);
return 0;
}
abi_long host_to_target_msqid_ds(abi_ulong target_addr,
struct msqid_ds *host_md)
{
struct target_msqid_ds *target_md;
if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
return -TARGET_EFAULT;
}
memset(target_md, 0, sizeof(struct target_msqid_ds));
host_to_target_ipc_perm__locked(&target_md->msg_perm,
&host_md->msg_perm);
/* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
__put_user(target_md->msg_cbytes, &host_md->msg_cbytes);
__put_user(target_md->msg_qnum, &host_md->msg_qnum);
__put_user(target_md->msg_qbytes, &host_md->msg_qbytes);
__put_user(target_md->msg_lspid, &host_md->msg_lspid);
__put_user(target_md->msg_lrpid, &host_md->msg_lrpid);
__put_user(target_md->msg_stime, &host_md->msg_stime);
__put_user(target_md->msg_rtime, &host_md->msg_rtime);
__put_user(target_md->msg_ctime, &host_md->msg_ctime);
unlock_user_struct(target_md, target_addr, 1);
return 0;
}