aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c303
1 files changed, 285 insertions, 18 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9f5e53a7fe..8a92162155 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -95,6 +95,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#endif
#include <linux/fb.h>
#include <linux/vt.h>
+#include <linux/dm-ioctl.h>
#include "linux_loop.h"
#include "cpu-uname.h"
@@ -3354,6 +3355,231 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
return ret;
}
+static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
+ abi_long cmd, abi_long arg)
+{
+ void *argptr;
+ struct dm_ioctl *host_dm;
+ abi_long guest_data;
+ uint32_t guest_data_size;
+ int target_size;
+ const argtype *arg_type = ie->arg_type;
+ abi_long ret;
+ void *big_buf = NULL;
+ char *host_data;
+
+ arg_type++;
+ target_size = thunk_type_size(arg_type, 0);
+ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+ if (!argptr) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+
+ /* buf_temp is too small, so fetch things into a bigger buffer */
+ big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
+ memcpy(big_buf, buf_temp, target_size);
+ buf_temp = big_buf;
+ host_dm = big_buf;
+
+ guest_data = arg + host_dm->data_start;
+ if ((guest_data - arg) < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ guest_data_size = host_dm->data_size - host_dm->data_start;
+ host_data = (char*)host_dm + host_dm->data_start;
+
+ argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
+ switch (ie->host_cmd) {
+ case DM_REMOVE_ALL:
+ case DM_LIST_DEVICES:
+ case DM_DEV_CREATE:
+ case DM_DEV_REMOVE:
+ case DM_DEV_SUSPEND:
+ case DM_DEV_STATUS:
+ case DM_DEV_WAIT:
+ case DM_TABLE_STATUS:
+ case DM_TABLE_CLEAR:
+ case DM_TABLE_DEPS:
+ case DM_LIST_VERSIONS:
+ /* no input data */
+ break;
+ case DM_DEV_RENAME:
+ case DM_DEV_SET_GEOMETRY:
+ /* data contains only strings */
+ memcpy(host_data, argptr, guest_data_size);
+ break;
+ case DM_TARGET_MSG:
+ memcpy(host_data, argptr, guest_data_size);
+ *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
+ break;
+ case DM_TABLE_LOAD:
+ {
+ void *gspec = argptr;
+ void *cur_data = host_data;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+ int spec_size = thunk_type_size(arg_type, 0);
+ int i;
+
+ for (i = 0; i < host_dm->target_count; i++) {
+ struct dm_target_spec *spec = cur_data;
+ uint32_t next;
+ int slen;
+
+ thunk_convert(spec, gspec, arg_type, THUNK_HOST);
+ slen = strlen((char*)gspec + spec_size) + 1;
+ next = spec->next;
+ spec->next = sizeof(*spec) + slen;
+ strcpy((char*)&spec[1], gspec + spec_size);
+ gspec += next;
+ cur_data += spec->next;
+ }
+ break;
+ }
+ default:
+ ret = -TARGET_EINVAL;
+ goto out;
+ }
+ unlock_user(argptr, guest_data, 0);
+
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ guest_data = arg + host_dm->data_start;
+ guest_data_size = host_dm->data_size - host_dm->data_start;
+ argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
+ switch (ie->host_cmd) {
+ case DM_REMOVE_ALL:
+ case DM_DEV_CREATE:
+ case DM_DEV_REMOVE:
+ case DM_DEV_RENAME:
+ case DM_DEV_SUSPEND:
+ case DM_DEV_STATUS:
+ case DM_TABLE_LOAD:
+ case DM_TABLE_CLEAR:
+ case DM_TARGET_MSG:
+ case DM_DEV_SET_GEOMETRY:
+ /* no return data */
+ break;
+ case DM_LIST_DEVICES:
+ {
+ struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
+ uint32_t remaining_data = guest_data_size;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
+ int nl_size = 12; /* can't use thunk_size due to alignment */
+
+ while (1) {
+ uint32_t next = nl->next;
+ if (next) {
+ nl->next = nl_size + (strlen(nl->name) + 1);
+ }
+ if (remaining_data < nl->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
+ strcpy(cur_data + nl_size, nl->name);
+ cur_data += nl->next;
+ remaining_data -= nl->next;
+ if (!next) {
+ break;
+ }
+ nl = (void*)nl + next;
+ }
+ break;
+ }
+ case DM_DEV_WAIT:
+ case DM_TABLE_STATUS:
+ {
+ struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+ int spec_size = thunk_type_size(arg_type, 0);
+ int i;
+
+ for (i = 0; i < host_dm->target_count; i++) {
+ uint32_t next = spec->next;
+ int slen = strlen((char*)&spec[1]) + 1;
+ spec->next = (cur_data - argptr) + spec_size + slen;
+ if (guest_data_size < spec->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
+ strcpy(cur_data + spec_size, (char*)&spec[1]);
+ cur_data = argptr + spec->next;
+ spec = (void*)host_dm + host_dm->data_start + next;
+ }
+ break;
+ }
+ case DM_TABLE_DEPS:
+ {
+ void *hdata = (void*)host_dm + host_dm->data_start;
+ int count = *(uint32_t*)hdata;
+ uint64_t *hdev = hdata + 8;
+ uint64_t *gdev = argptr + 8;
+ int i;
+
+ *(uint32_t*)argptr = tswap32(count);
+ for (i = 0; i < count; i++) {
+ *gdev = tswap64(*hdev);
+ gdev++;
+ hdev++;
+ }
+ break;
+ }
+ case DM_LIST_VERSIONS:
+ {
+ struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
+ uint32_t remaining_data = guest_data_size;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
+ int vers_size = thunk_type_size(arg_type, 0);
+
+ while (1) {
+ uint32_t next = vers->next;
+ if (next) {
+ vers->next = vers_size + (strlen(vers->name) + 1);
+ }
+ if (remaining_data < vers->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
+ strcpy(cur_data + vers_size, vers->name);
+ cur_data += vers->next;
+ remaining_data -= vers->next;
+ if (!next) {
+ break;
+ }
+ vers = (void*)vers + next;
+ }
+ break;
+ }
+ default:
+ ret = -TARGET_EINVAL;
+ goto out;
+ }
+ unlock_user(argptr, guest_data, guest_data_size);
+
+ argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+ if (!argptr) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+out:
+ if (big_buf) {
+ free(big_buf);
+ }
+ return ret;
+}
+
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
@@ -4662,11 +4888,22 @@ static int open_self_stat(void *cpu_env, int fd)
int len;
uint64_t val = 0;
- if (i == 27) {
- /* stack bottom */
- val = start_stack;
+ if (i == 0) {
+ /* pid */
+ val = getpid();
+ snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+ } else if (i == 1) {
+ /* app name */
+ snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
+ } else if (i == 27) {
+ /* stack bottom */
+ val = start_stack;
+ snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+ } else {
+ /* for the rest, there is MasterCard */
+ snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
}
- snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' ');
+
len = strlen(buf);
if (write(fd, buf, len) != len) {
return -1;
@@ -7005,21 +7242,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
goto unimplemented;
#endif
case TARGET_NR_prctl:
- switch (arg1)
- {
- case PR_GET_PDEATHSIG:
- {
- int deathsig;
- ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
- if (!is_error(ret) && arg2
- && put_user_ual(deathsig, arg2))
- goto efault;
- }
- break;
- default:
- ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
- break;
+ switch (arg1) {
+ case PR_GET_PDEATHSIG:
+ {
+ int deathsig;
+ ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+ if (!is_error(ret) && arg2
+ && put_user_ual(deathsig, arg2)) {
+ goto efault;
}
+ break;
+ }
+#ifdef PR_GET_NAME
+ case PR_GET_NAME:
+ {
+ void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
+ if (!name) {
+ goto efault;
+ }
+ ret = get_errno(prctl(arg1, (unsigned long)name,
+ arg3, arg4, arg5));
+ unlock_user(name, arg2, 16);
+ break;
+ }
+ case PR_SET_NAME:
+ {
+ void *name = lock_user(VERIFY_READ, arg2, 16, 1);
+ if (!name) {
+ goto efault;
+ }
+ ret = get_errno(prctl(arg1, (unsigned long)name,
+ arg3, arg4, arg5));
+ unlock_user(name, arg2, 0);
+ break;
+ }
+#endif
+ default:
+ /* Most prctl options have no pointer arguments */
+ ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+ break;
+ }
break;
#ifdef TARGET_NR_arch_prctl
case TARGET_NR_arch_prctl:
@@ -8248,7 +8510,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif /* CONFIG_EVENTFD */
#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
case TARGET_NR_fallocate:
+#if TARGET_ABI_BITS == 32
+ ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
+ target_offset64(arg5, arg6)));
+#else
ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
+#endif
break;
#endif
#if defined(CONFIG_SYNC_FILE_RANGE)