diff --git a/executer/include/uprotocol.h b/executer/include/uprotocol.h index 7c0f6332..ff5c0653 100644 --- a/executer/include/uprotocol.h +++ b/executer/include/uprotocol.h @@ -37,6 +37,7 @@ #define MCEXEC_UP_LOAD_SYSCALL 0x30a02905 #define MCEXEC_UP_SEND_SIGNAL 0x30a02906 #define MCEXEC_UP_GET_CPU 0x30a02907 +#define MCEXEC_UP_STRNCPY_FROM_USER 0x30a02908 #define MCEXEC_UP_PREPARE_DMA 0x30a02910 #define MCEXEC_UP_FREE_DMA 0x30a02911 @@ -115,6 +116,13 @@ struct syscall_ret_desc { unsigned long size; }; +struct strncpy_from_user_desc { + void *dest; + void *src; + unsigned long n; + long result; +}; + struct prepare_dma_desc { unsigned long size; unsigned long pa; diff --git a/executer/kernel/control.c b/executer/kernel/control.c index f13e0049..671b81a5 100644 --- a/executer/kernel/control.c +++ b/executer/kernel/control.c @@ -573,6 +573,58 @@ long mcexec_ret_syscall(ihk_os_t os, struct syscall_ret_desc *__user arg) return 0; } +long mcexec_strncpy_from_user(ihk_os_t os, struct strncpy_from_user_desc * __user arg) +{ + struct strncpy_from_user_desc desc; + void *buf; + void *dest; + void *src; + unsigned long remain; + long want; + long copied; + + if (copy_from_user(&desc, arg, sizeof(desc))) { + return -EFAULT; + } + + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + + dest = desc.dest; + src = desc.src; + remain = desc.n; + want = 0; + copied = 0; + + while ((remain > 0) && (want == copied)) { + want = (remain > PAGE_SIZE)? PAGE_SIZE: remain; + copied = strncpy_from_user(buf, src, want); + if (copied == want) { + if (copy_to_user(dest, buf, copied)) { + copied = -EFAULT; + } + } + else if (copied >= 0) { + if (copy_to_user(dest, buf, copied+1)) { + copied = -EFAULT; + } + } + dest += copied; + src += copied; + remain -= copied; + } + + desc.result = (copied >= 0)? (desc.n - remain): copied; + free_page((unsigned long)buf); + + if (copy_to_user(arg, &desc, sizeof(*arg))) { + return -EFAULT; + } + return 0; +} + long __mcctrl_control(ihk_os_t os, unsigned int req, unsigned long arg) { switch (req) { @@ -600,6 +652,9 @@ long __mcctrl_control(ihk_os_t os, unsigned int req, unsigned long arg) case MCEXEC_UP_GET_CPU: return mcexec_get_cpu(os); + case MCEXEC_UP_STRNCPY_FROM_USER: + return mcexec_strncpy_from_user(os, (struct strncpy_from_user_desc *)arg); + case MCEXEC_UP_PREPARE_DMA: return mcexec_pin_region(os, (unsigned long *)arg); diff --git a/executer/kernel/driver.c b/executer/kernel/driver.c index bb0b6566..9f621376 100644 --- a/executer/kernel/driver.c +++ b/executer/kernel/driver.c @@ -51,6 +51,7 @@ static struct ihk_os_user_call_handler mcctrl_uchs[] = { { .request = MCEXEC_UP_LOAD_SYSCALL, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_SEND_SIGNAL, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_GET_CPU, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_STRNCPY_FROM_USER, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_PREPARE_DMA, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_FREE_DMA, .func = mcctrl_ioctl }, }; diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index 43b86e21..4ab30576 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -883,6 +883,25 @@ kill_thread(unsigned long cpu) } } +static long do_strncpy_from_user(int fd, void *dest, void *src, unsigned long n) +{ + struct strncpy_from_user_desc desc; + int ret; + + desc.dest = dest; + desc.src = src; + desc.n = n; + + ret = ioctl(fd, MCEXEC_UP_STRNCPY_FROM_USER, (unsigned long)&desc); + if (ret) { + ret = -errno; + perror("strncpy_from_user:ioctl"); + return ret; + } + + return desc.result; +} + #define SET_ERR(ret) if (ret == -1) ret = -errno int main_loop(int fd, int cpu, pthread_mutex_t *lock)