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.c165
1 files changed, 125 insertions, 40 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 36b0901055..389ec09764 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -894,6 +894,8 @@ abi_long do_brk(abi_ulong new_brk)
abi_long mapped_addr;
abi_ulong new_alloc_size;
+ /* brk pointers are always untagged */
+
DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
if (!new_brk) {
@@ -912,7 +914,7 @@ abi_long do_brk(abi_ulong new_brk)
/* Heap contents are initialized to zero, as for anonymous
* mapped pages. */
if (new_brk > target_brk) {
- memset(g2h(target_brk), 0, new_brk - target_brk);
+ memset(g2h_untagged(target_brk), 0, new_brk - target_brk);
}
target_brk = new_brk;
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
@@ -938,7 +940,7 @@ abi_long do_brk(abi_ulong new_brk)
* come from the remaining part of the previous page: it may
* contains garbage data due to a previous heap usage (grown
* then shrunken). */
- memset(g2h(target_brk), 0, brk_page - target_brk);
+ memset(g2h_untagged(target_brk), 0, brk_page - target_brk);
target_brk = new_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
@@ -3524,8 +3526,9 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
return -TARGET_EINVAL;
}
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
return -TARGET_EFAULT;
+ }
addr = alloca(addrlen);
@@ -3555,8 +3558,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
return -TARGET_EINVAL;
}
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
return -TARGET_EFAULT;
+ }
addr = alloca(addrlen);
@@ -3586,8 +3590,9 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
return -TARGET_EINVAL;
}
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
return -TARGET_EFAULT;
+ }
addr = alloca(addrlen);
@@ -4599,6 +4604,8 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
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)) {
@@ -4615,14 +4622,14 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
return -TARGET_EINVAL;
}
}
- if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
+ if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
return -TARGET_EINVAL;
}
mmap_lock();
if (shmaddr)
- host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+ host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
else {
abi_ulong mmap_start;
@@ -4633,7 +4640,8 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
errno = ENOMEM;
host_raddr = (void *)-1;
} else
- host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
+ host_raddr = shmat(shmid, g2h_untagged(mmap_start),
+ shmflg | SHM_REMAP);
}
if (host_raddr == (void *)-1) {
@@ -4643,8 +4651,8 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
raddr=h2g((unsigned long)host_raddr);
page_set_flags(raddr, raddr + shm_info.shm_segsz,
- PAGE_VALID | PAGE_READ |
- ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
+ 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) {
@@ -4665,6 +4673,8 @@ 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) {
@@ -4674,7 +4684,7 @@ static inline abi_long do_shmdt(abi_ulong shmaddr)
break;
}
}
- rv = get_errno(shmdt(g2h(shmaddr)));
+ rv = get_errno(shmdt(g2h_untagged(shmaddr)));
mmap_unlock();
@@ -6145,10 +6155,10 @@ static abi_long write_ldt(CPUX86State *env,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (env->ldt.base == -1)
return -TARGET_ENOMEM;
- memset(g2h(env->ldt.base), 0,
+ memset(g2h_untagged(env->ldt.base), 0,
TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
env->ldt.limit = 0xffff;
- ldt_table = g2h(env->ldt.base);
+ ldt_table = g2h_untagged(env->ldt.base);
}
/* NOTE: same code as Linux kernel */
@@ -6216,7 +6226,7 @@ static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
#if defined(TARGET_ABI32)
abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
{
- uint64_t *gdt_table = g2h(env->gdt.base);
+ uint64_t *gdt_table = g2h_untagged(env->gdt.base);
struct target_modify_ldt_ldt_s ldt_info;
struct target_modify_ldt_ldt_s *target_ldt_info;
int seg_32bit, contents, read_exec_only, limit_in_pages;
@@ -6302,7 +6312,7 @@ install:
static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
{
struct target_modify_ldt_ldt_s *target_ldt_info;
- uint64_t *gdt_table = g2h(env->gdt.base);
+ uint64_t *gdt_table = g2h_untagged(env->gdt.base);
uint32_t base_addr, limit, flags;
int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
int seg_not_present, useable, lm;
@@ -7597,8 +7607,8 @@ static int do_safe_futex(int *uaddr, int op, int val,
tricky. However they're probably useless because guest atomic
operations won't work either. */
#if defined(TARGET_NR_futex)
-static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
- target_ulong uaddr2, int val3)
+static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val,
+ target_ulong timeout, target_ulong uaddr2, int val3)
{
struct timespec ts, *pts;
int base_op;
@@ -7619,11 +7629,14 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
} else {
pts = NULL;
}
- return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
+ return do_safe_futex(g2h(cpu, uaddr),
+ op, tswap32(val), pts, NULL, val3);
case FUTEX_WAKE:
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ return do_safe_futex(g2h(cpu, uaddr),
+ op, val, NULL, NULL, 0);
case FUTEX_FD:
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ return do_safe_futex(g2h(cpu, uaddr),
+ op, val, NULL, NULL, 0);
case FUTEX_REQUEUE:
case FUTEX_CMP_REQUEUE:
case FUTEX_WAKE_OP:
@@ -7633,10 +7646,9 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
to satisfy the compiler. We do not need to tswap TIMEOUT
since it's not compared to guest memory. */
pts = (struct timespec *)(uintptr_t) timeout;
- return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
+ return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
(base_op == FUTEX_CMP_REQUEUE
- ? tswap32(val3)
- : val3));
+ ? tswap32(val3) : val3));
default:
return -TARGET_ENOSYS;
}
@@ -7644,7 +7656,8 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
#endif
#if defined(TARGET_NR_futex_time64)
-static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong timeout,
+static int do_futex_time64(CPUState *cpu, target_ulong uaddr, int op,
+ int val, target_ulong timeout,
target_ulong uaddr2, int val3)
{
struct timespec ts, *pts;
@@ -7668,11 +7681,12 @@ static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong tim
} else {
pts = NULL;
}
- return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
+ return do_safe_futex(g2h(cpu, uaddr), op,
+ tswap32(val), pts, NULL, val3);
case FUTEX_WAKE:
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
case FUTEX_FD:
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
+ return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
case FUTEX_REQUEUE:
case FUTEX_CMP_REQUEUE:
case FUTEX_WAKE_OP:
@@ -7682,10 +7696,9 @@ static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong tim
to satisfy the compiler. We do not need to tswap TIMEOUT
since it's not compared to guest memory. */
pts = (struct timespec *)(uintptr_t) timeout;
- return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
+ return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
(base_op == FUTEX_CMP_REQUEUE
- ? tswap32(val3)
- : val3));
+ ? tswap32(val3) : val3));
default:
return -TARGET_ENOSYS;
}
@@ -7860,7 +7873,7 @@ static int open_self_maps(void *cpu_env, int fd)
const char *path;
max = h2g_valid(max - 1) ?
- max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1;
+ max : (uintptr_t) g2h_untagged(GUEST_ADDR_MAX) + 1;
if (page_check_range(h2g(min), max - min, flags) == -1) {
continue;
@@ -8277,8 +8290,8 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
if (ts->child_tidptr) {
put_user_u32(0, ts->child_tidptr);
- do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
- NULL, NULL, 0);
+ do_sys_futex(g2h(cpu, ts->child_tidptr),
+ FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}
thread_cpu = NULL;
g_free(ts);
@@ -8643,7 +8656,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
if (!arg5) {
ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
} else {
- ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
+ ret = mount(p, p2, p3, (unsigned long)arg4, g2h(cpu, arg5));
}
ret = get_errno(ret);
@@ -9699,6 +9712,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
v5, v6));
}
#else
+ /* mmap pointers are always untagged */
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
@@ -9717,8 +9731,10 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return get_errno(ret);
#endif
case TARGET_NR_munmap:
+ arg1 = cpu_untagged_addr(cpu, arg1);
return get_errno(target_munmap(arg1, arg2));
case TARGET_NR_mprotect:
+ arg1 = cpu_untagged_addr(cpu, arg1);
{
TaskState *ts = cpu->opaque;
/* Special hack to detect libc making the stack executable. */
@@ -9733,20 +9749,22 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return get_errno(target_mprotect(arg1, arg2, arg3));
#ifdef TARGET_NR_mremap
case TARGET_NR_mremap:
+ arg1 = cpu_untagged_addr(cpu, arg1);
+ /* mremap new_addr (arg5) is always untagged */
return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
#endif
/* ??? msync/mlock/munlock are broken for softmmu. */
#ifdef TARGET_NR_msync
case TARGET_NR_msync:
- return get_errno(msync(g2h(arg1), arg2, arg3));
+ return get_errno(msync(g2h(cpu, arg1), arg2, arg3));
#endif
#ifdef TARGET_NR_mlock
case TARGET_NR_mlock:
- return get_errno(mlock(g2h(arg1), arg2));
+ return get_errno(mlock(g2h(cpu, arg1), arg2));
#endif
#ifdef TARGET_NR_munlock
case TARGET_NR_munlock:
- return get_errno(munlock(g2h(arg1), arg2));
+ return get_errno(munlock(g2h(cpu, arg1), arg2));
#endif
#ifdef TARGET_NR_mlockall
case TARGET_NR_mlockall:
@@ -10975,6 +10993,73 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
}
return -TARGET_EINVAL;
+ case TARGET_PR_SET_TAGGED_ADDR_CTRL:
+ {
+ abi_ulong valid_mask = TARGET_PR_TAGGED_ADDR_ENABLE;
+ CPUARMState *env = cpu_env;
+ ARMCPU *cpu = env_archcpu(env);
+
+ if (cpu_isar_feature(aa64_mte, cpu)) {
+ valid_mask |= TARGET_PR_MTE_TCF_MASK;
+ valid_mask |= TARGET_PR_MTE_TAG_MASK;
+ }
+
+ if ((arg2 & ~valid_mask) || arg3 || arg4 || arg5) {
+ return -TARGET_EINVAL;
+ }
+ env->tagged_addr_enable = arg2 & TARGET_PR_TAGGED_ADDR_ENABLE;
+
+ if (cpu_isar_feature(aa64_mte, cpu)) {
+ switch (arg2 & TARGET_PR_MTE_TCF_MASK) {
+ case TARGET_PR_MTE_TCF_NONE:
+ case TARGET_PR_MTE_TCF_SYNC:
+ case TARGET_PR_MTE_TCF_ASYNC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
+ * Note that the syscall values are consistent with hw.
+ */
+ env->cp15.sctlr_el[1] =
+ deposit64(env->cp15.sctlr_el[1], 38, 2,
+ arg2 >> TARGET_PR_MTE_TCF_SHIFT);
+
+ /*
+ * Write PR_MTE_TAG to GCR_EL1[Exclude].
+ * Note that the syscall uses an include mask,
+ * and hardware uses an exclude mask -- invert.
+ */
+ env->cp15.gcr_el1 =
+ deposit64(env->cp15.gcr_el1, 0, 16,
+ ~arg2 >> TARGET_PR_MTE_TAG_SHIFT);
+ arm_rebuild_hflags(env);
+ }
+ return 0;
+ }
+ case TARGET_PR_GET_TAGGED_ADDR_CTRL:
+ {
+ abi_long ret = 0;
+ CPUARMState *env = cpu_env;
+ ARMCPU *cpu = env_archcpu(env);
+
+ if (arg2 || arg3 || arg4 || arg5) {
+ return -TARGET_EINVAL;
+ }
+ if (env->tagged_addr_enable) {
+ ret |= TARGET_PR_TAGGED_ADDR_ENABLE;
+ }
+ if (cpu_isar_feature(aa64_mte, cpu)) {
+ /* See above. */
+ ret |= (extract64(env->cp15.sctlr_el[1], 38, 2)
+ << TARGET_PR_MTE_TCF_SHIFT);
+ ret = deposit64(ret, TARGET_PR_MTE_TAG_SHIFT, 16,
+ ~env->cp15.gcr_el1);
+ }
+ return ret;
+ }
#endif /* AARCH64 */
case PR_GET_SECCOMP:
case PR_SET_SECCOMP:
@@ -12237,7 +12322,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
case TARGET_NR_set_tid_address:
- return get_errno(set_tid_address((int *)g2h(arg1)));
+ return get_errno(set_tid_address((int *)g2h(cpu, arg1)));
#endif
case TARGET_NR_tkill:
@@ -12324,11 +12409,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_futex
case TARGET_NR_futex:
- return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
+ return do_futex(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef TARGET_NR_futex_time64
case TARGET_NR_futex_time64:
- return do_futex_time64(arg1, arg2, arg3, arg4, arg5, arg6);
+ return do_futex_time64(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
case TARGET_NR_inotify_init: