diff options
author | Laurent Vivier <laurent@vivier.eu> | 2017-03-01 10:37:48 +0100 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2017-05-29 14:56:07 +0300 |
commit | 562a20b4ef63bdde6e2e5bac0da02302aeb5299f (patch) | |
tree | 1b7a146d5a815554ce689ab626133c41f4f62ec5 /linux-user/syscall.c | |
parent | 04b9bcf911af2b4563b1f1b2e8a103b796dcc9eb (diff) |
linux-user: fix eventfd
When a fd is opened using eventfd(), a read provides
a 64bit counter in the host byte order, and a
write increase the internal counter by the provided
64bit value.
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b2b563e388..2da8426aaa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7671,6 +7671,28 @@ static target_timer_t get_timer_id(abi_long arg) return timerid; } +static abi_long swap_data_eventfd(void *buf, size_t len) +{ + uint64_t *counter = buf; + int i; + + if (len < sizeof(uint64_t)) { + return -EINVAL; + } + + for (i = 0; i < len; i += sizeof(uint64_t)) { + *counter = tswap64(*counter); + counter++; + } + + return len; +} + +static TargetFdTrans target_eventfd_trans = { + .host_to_target_data = swap_data_eventfd, + .target_to_host_data = swap_data_eventfd, +}; + /* 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_<errcode>. */ @@ -11876,7 +11898,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_eventfd) case TARGET_NR_eventfd: ret = get_errno(eventfd(arg1, 0)); - fd_trans_unregister(ret); + fd_trans_register(ret, &target_eventfd_trans); break; #endif #if defined(TARGET_NR_eventfd2) @@ -11890,7 +11912,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, host_flags |= O_CLOEXEC; } ret = get_errno(eventfd(arg1, host_flags)); - fd_trans_unregister(ret); + fd_trans_register(ret, &target_eventfd_trans); break; } #endif |