aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/cpu_loop.c38
-rw-r--r--linux-user/aarch64/target_signal.h3
-rw-r--r--linux-user/aarch64/target_syscall.h13
-rw-r--r--linux-user/elfload.c18
-rw-r--r--linux-user/flatload.c2
-rw-r--r--linux-user/hppa/cpu_loop.c39
-rw-r--r--linux-user/i386/cpu_loop.c6
-rw-r--r--linux-user/i386/signal.c5
-rw-r--r--linux-user/main.c4
-rw-r--r--linux-user/mmap.c88
-rw-r--r--linux-user/ppc/signal.c4
-rw-r--r--linux-user/qemu.h76
-rw-r--r--linux-user/syscall.c165
-rw-r--r--linux-user/syscall_defs.h1
-rw-r--r--linux-user/uaccess.c82
15 files changed, 358 insertions, 186 deletions
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index 42b9c15f53..7c42f65706 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -23,6 +23,7 @@
#include "cpu_loop-common.h"
#include "qemu/guest-random.h"
#include "hw/semihosting/common-semi.h"
+#include "target/arm/syndrome.h"
#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
@@ -76,7 +77,7 @@
void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr;
+ int trapnr, ec, fsc;
abi_long ret;
target_siginfo_t info;
@@ -117,9 +118,29 @@ void cpu_loop(CPUARMState *env)
case EXCP_DATA_ABORT:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->exception.vaddress;
+
+ /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
+ ec = syn_get_ec(env->exception.syndrome);
+ assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
+
+ /* Both EC have the same format for FSC, or close enough. */
+ fsc = extract32(env->exception.syndrome, 0, 6);
+ switch (fsc) {
+ case 0x04 ... 0x07: /* Translation fault, level {0-3} */
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
+ case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
+ info.si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x11: /* Synchronous Tag Check Fault */
+ info.si_code = TARGET_SEGV_MTESERR;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_DEBUG:
@@ -143,6 +164,17 @@ void cpu_loop(CPUARMState *env)
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
+
+ /* Check for MTE asynchronous faults */
+ if (unlikely(env->cp15.tfsr_el[0])) {
+ env->cp15.tfsr_el[0] = 0;
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = 0;
+ info.si_code = TARGET_SEGV_MTEAERR;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+
process_pending_signals(env);
/* Exception return on AArch64 always clears the exclusive monitor,
* so any return to running guest code implies this.
diff --git a/linux-user/aarch64/target_signal.h b/linux-user/aarch64/target_signal.h
index ddd73169f0..18013e1b23 100644
--- a/linux-user/aarch64/target_signal.h
+++ b/linux-user/aarch64/target_signal.h
@@ -21,5 +21,8 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
+#define TARGET_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
+#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
+
#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* AARCH64_TARGET_SIGNAL_H */
diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h
index 3194e6b009..76f6c3391d 100644
--- a/linux-user/aarch64/target_syscall.h
+++ b/linux-user/aarch64/target_syscall.h
@@ -30,4 +30,17 @@ struct target_pt_regs {
# define TARGET_PR_PAC_APDBKEY (1 << 3)
# define TARGET_PR_PAC_APGAKEY (1 << 4)
+#define TARGET_PR_SET_TAGGED_ADDR_CTRL 55
+#define TARGET_PR_GET_TAGGED_ADDR_CTRL 56
+# define TARGET_PR_TAGGED_ADDR_ENABLE (1UL << 0)
+/* MTE tag check fault modes */
+# define TARGET_PR_MTE_TCF_SHIFT 1
+# define TARGET_PR_MTE_TCF_NONE (0UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_SYNC (1UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_ASYNC (2UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_MASK (3UL << TARGET_PR_MTE_TCF_SHIFT)
+/* MTE tag inclusion mask */
+# define TARGET_PR_MTE_TAG_SHIFT 3
+# define TARGET_PR_MTE_TAG_MASK (0xffffUL << TARGET_PR_MTE_TAG_SHIFT)
+
#endif /* AARCH64_TARGET_SYSCALL_H */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f5bd4076fc..73d750c809 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -389,7 +389,7 @@ enum {
static bool init_guest_commpage(void)
{
- void *want = g2h(ARM_COMMPAGE & -qemu_host_page_size);
+ void *want = g2h_untagged(ARM_COMMPAGE & -qemu_host_page_size);
void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
@@ -402,7 +402,7 @@ static bool init_guest_commpage(void)
}
/* Set kernel helper versions; rest of page is 0. */
- __put_user(5, (uint32_t *)g2h(0xffff0ffcu));
+ __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
perror("Protecting guest commpage");
@@ -1872,8 +1872,8 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
here is still actually needed. For now, continue with it,
but merge it with the "normal" mmap that would allocate the bss. */
- host_start = (uintptr_t) g2h(elf_bss);
- host_end = (uintptr_t) g2h(last_bss);
+ host_start = (uintptr_t) g2h_untagged(elf_bss);
+ host_end = (uintptr_t) g2h_untagged(last_bss);
host_map_start = REAL_HOST_PAGE_ALIGN(host_start);
if (host_map_start < host_end) {
@@ -2135,9 +2135,9 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
void *addr, *test;
if (!QEMU_IS_ALIGNED(guest_base, align)) {
- fprintf(stderr, "Requested guest base 0x%lx does not satisfy "
+ fprintf(stderr, "Requested guest base %p does not satisfy "
"host minimum alignment (0x%lx)\n",
- guest_base, align);
+ (void *)guest_base, align);
exit(EXIT_FAILURE);
}
@@ -2171,7 +2171,7 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
}
/* Reserve the address space for the binary, or reserved_va. */
- test = g2h(guest_loaddr);
+ test = g2h_untagged(guest_loaddr);
addr = mmap(test, guest_hiaddr - guest_loaddr, PROT_NONE, flags, -1, 0);
if (test != addr) {
pgb_fail_in_use(image_name);
@@ -2393,7 +2393,7 @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
/* Reserve the memory on the host. */
assert(guest_base != 0);
- test = g2h(0);
+ test = g2h_untagged(0);
addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0);
if (addr == MAP_FAILED || addr != test) {
error_report("Unable to reserve 0x%lx bytes of virtual address "
@@ -3510,7 +3510,7 @@ static int vma_get_mapping_count(const struct mm_struct *mm)
static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
{
/* if we cannot even read the first page, skip it */
- if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
+ if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
return (0);
/*
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 14d2999d15..3e5594cf89 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -668,7 +668,7 @@ static int load_flat_file(struct linux_binprm * bprm,
}
/* zero the BSS. */
- memset(g2h(datapos + data_len), 0, bss_len);
+ memset(g2h_untagged(datapos + data_len), 0, bss_len);
return 0;
}
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index d7e1ec7722..3aaaf3337c 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -23,6 +23,7 @@
static abi_ulong hppa_lws(CPUHPPAState *env)
{
+ CPUState *cs = env_cpu(env);
uint32_t which = env->gr[20];
abi_ulong addr = env->gr[26];
abi_ulong old = env->gr[25];
@@ -34,12 +35,12 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
return -TARGET_ENOSYS;
case 0: /* elf32 atomic 32bit cmpxchg */
- if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
+ if ((addr & 3) || !access_ok(cs, VERIFY_WRITE, addr, 4)) {
return -TARGET_EFAULT;
}
old = tswap32(old);
new = tswap32(new);
- ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
ret = tswap32(ret);
break;
@@ -49,47 +50,47 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
return -TARGET_ENOSYS;
}
if (((addr | old | new) & ((1 << size) - 1))
- || !access_ok(VERIFY_WRITE, addr, 1 << size)
- || !access_ok(VERIFY_READ, old, 1 << size)
- || !access_ok(VERIFY_READ, new, 1 << size)) {
+ || !access_ok(cs, VERIFY_WRITE, addr, 1 << size)
+ || !access_ok(cs, VERIFY_READ, old, 1 << size)
+ || !access_ok(cs, VERIFY_READ, new, 1 << size)) {
return -TARGET_EFAULT;
}
/* Note that below we use host-endian loads so that the cmpxchg
can be host-endian as well. */
switch (size) {
case 0:
- old = *(uint8_t *)g2h(old);
- new = *(uint8_t *)g2h(new);
- ret = qatomic_cmpxchg((uint8_t *)g2h(addr), old, new);
+ old = *(uint8_t *)g2h(cs, old);
+ new = *(uint8_t *)g2h(cs, new);
+ ret = qatomic_cmpxchg((uint8_t *)g2h(cs, addr), old, new);
ret = ret != old;
break;
case 1:
- old = *(uint16_t *)g2h(old);
- new = *(uint16_t *)g2h(new);
- ret = qatomic_cmpxchg((uint16_t *)g2h(addr), old, new);
+ old = *(uint16_t *)g2h(cs, old);
+ new = *(uint16_t *)g2h(cs, new);
+ ret = qatomic_cmpxchg((uint16_t *)g2h(cs, addr), old, new);
ret = ret != old;
break;
case 2:
- old = *(uint32_t *)g2h(old);
- new = *(uint32_t *)g2h(new);
- ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ old = *(uint32_t *)g2h(cs, old);
+ new = *(uint32_t *)g2h(cs, new);
+ ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
ret = ret != old;
break;
case 3:
{
uint64_t o64, n64, r64;
- o64 = *(uint64_t *)g2h(old);
- n64 = *(uint64_t *)g2h(new);
+ o64 = *(uint64_t *)g2h(cs, old);
+ n64 = *(uint64_t *)g2h(cs, new);
#ifdef CONFIG_ATOMIC64
- r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(addr),
+ r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(cs, addr),
o64, n64);
ret = r64 != o64;
#else
start_exclusive();
- r64 = *(uint64_t *)g2h(addr);
+ r64 = *(uint64_t *)g2h(cs, addr);
ret = 1;
if (r64 == o64) {
- *(uint64_t *)g2h(addr) = n64;
+ *(uint64_t *)g2h(cs, addr) = n64;
ret = 0;
}
end_exclusive();
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 70cde417e6..f813e87294 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -99,7 +99,7 @@ static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len)
* For all the vsyscalls, NULL means "don't write anything" not
* "write it at address 0".
*/
- if (addr == 0 || access_ok(VERIFY_WRITE, addr, len)) {
+ if (addr == 0 || access_ok(env_cpu(env), VERIFY_WRITE, addr, len)) {
return true;
}
@@ -379,7 +379,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- idt_table = g2h(env->idt.base);
+ idt_table = g2h_untagged(env->idt.base);
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
@@ -409,7 +409,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
- gdt_table = g2h(env->gdt.base);
+ gdt_table = g2h_untagged(env->gdt.base);
#ifdef TARGET_ABI32
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 97a39204cc..9320e1d472 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -513,9 +513,10 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
fpstate_addr = tswapl(sc->fpstate);
if (fpstate_addr != 0) {
- if (!access_ok(VERIFY_READ, fpstate_addr,
- sizeof(struct target_fpstate)))
+ if (!access_ok(env_cpu(env), VERIFY_READ, fpstate_addr,
+ sizeof(struct target_fpstate))) {
goto badframe;
+ }
#ifndef TARGET_X86_64
cpu_x86_frstor(env, fpstate_addr, 1);
#else
diff --git a/linux-user/main.c b/linux-user/main.c
index 2e3c169878..81f48ff54e 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -59,7 +59,7 @@ static const char *cpu_model;
static const char *cpu_type;
static const char *seed_optarg;
unsigned long mmap_min_addr;
-unsigned long guest_base;
+uintptr_t guest_base;
bool have_guest_base;
/*
@@ -824,7 +824,7 @@ int main(int argc, char **argv, char **envp)
g_free(target_environ);
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
- qemu_log("guest_base 0x%lx\n", guest_base);
+ qemu_log("guest_base %p\n", (void *)guest_base);
log_page_dump("binary load");
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 1c9faef476..7e3b245036 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -84,18 +84,24 @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
| (prot & PROT_EXEC ? PROT_READ : 0);
#ifdef TARGET_AARCH64
- /*
- * The PROT_BTI bit is only accepted if the cpu supports the feature.
- * Since this is the unusual case, don't bother checking unless
- * the bit has been requested. If set and valid, record the bit
- * within QEMU's page_flags.
- */
- if (prot & TARGET_PROT_BTI) {
+ {
ARMCPU *cpu = ARM_CPU(thread_cpu);
- if (cpu_isar_feature(aa64_bti, cpu)) {
+
+ /*
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
+ * Since this is the unusual case, don't bother checking unless
+ * the bit has been requested. If set and valid, record the bit
+ * within QEMU's page_flags.
+ */
+ if ((prot & TARGET_PROT_BTI) && cpu_isar_feature(aa64_bti, cpu)) {
valid |= TARGET_PROT_BTI;
page_flags |= PAGE_BTI;
}
+ /* Similarly for the PROT_MTE bit. */
+ if ((prot & TARGET_PROT_MTE) && cpu_isar_feature(aa64_mte, cpu)) {
+ valid |= TARGET_PROT_MTE;
+ page_flags |= PAGE_MTE;
+ }
}
#endif
@@ -119,7 +125,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
}
len = TARGET_PAGE_ALIGN(len);
end = start + len;
- if (!guest_range_valid(start, len)) {
+ if (!guest_range_valid_untagged(start, len)) {
return -TARGET_ENOMEM;
}
if (len == 0) {
@@ -141,7 +147,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
}
end = host_end;
}
- ret = mprotect(g2h(host_start), qemu_host_page_size,
+ ret = mprotect(g2h_untagged(host_start), qemu_host_page_size,
prot1 & PAGE_BITS);
if (ret != 0) {
goto error;
@@ -153,7 +159,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
- ret = mprotect(g2h(host_end - qemu_host_page_size),
+ ret = mprotect(g2h_untagged(host_end - qemu_host_page_size),
qemu_host_page_size, prot1 & PAGE_BITS);
if (ret != 0) {
goto error;
@@ -163,7 +169,8 @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
/* handle the pages in the middle */
if (host_start < host_end) {
- ret = mprotect(g2h(host_start), host_end - host_start, host_prot);
+ ret = mprotect(g2h_untagged(host_start),
+ host_end - host_start, host_prot);
if (ret != 0) {
goto error;
}
@@ -186,7 +193,7 @@ static int mmap_frag(abi_ulong real_start,
int prot1, prot_new;
real_end = real_start + qemu_host_page_size;
- host_start = g2h(real_start);
+ host_start = g2h_untagged(real_start);
/* get the protection of the target pages outside the mapping */
prot1 = 0;
@@ -218,7 +225,7 @@ static int mmap_frag(abi_ulong real_start,
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
- if (pread(fd, g2h(start), end - start, offset) == -1)
+ if (pread(fd, g2h_untagged(start), end - start, offset) == -1)
return -1;
/* put final protection */
@@ -229,7 +236,7 @@ static int mmap_frag(abi_ulong real_start,
mprotect(host_start, qemu_host_page_size, prot_new);
}
if (prot_new & PROT_WRITE) {
- memset(g2h(start), 0, end - start);
+ memset(g2h_untagged(start), 0, end - start);
}
}
return 0;
@@ -338,7 +345,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
* - mremap() with MREMAP_FIXED flag
* - shmat() with SHM_REMAP flag
*/
- ptr = mmap(g2h(addr), size, PROT_NONE,
+ ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
/* ENOMEM, if host address space has no memory */
@@ -497,7 +504,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
/* Note: we prefer to control the mapping address. It is
especially important if qemu_host_page_size >
qemu_real_host_page_size */
- p = mmap(g2h(start), host_len, host_prot,
+ p = mmap(g2h_untagged(start), host_len, host_prot,
flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) {
goto fail;
@@ -505,10 +512,10 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
/* update start so that it points to the file position at 'offset' */
host_start = (unsigned long)p;
if (!(flags & MAP_ANONYMOUS)) {
- p = mmap(g2h(start), len, host_prot,
+ p = mmap(g2h_untagged(start), len, host_prot,
flags | MAP_FIXED, fd, host_offset);
if (p == MAP_FAILED) {
- munmap(g2h(start), host_len);
+ munmap(g2h_untagged(start), host_len);
goto fail;
}
host_start += offset - host_offset;
@@ -527,7 +534,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
* It can fail only on 64-bit host with 32-bit target.
* On any other target/host host mmap() handles this error correctly.
*/
- if (end < start || !guest_range_valid(start, len)) {
+ if (end < start || !guest_range_valid_untagged(start, len)) {
errno = ENOMEM;
goto fail;
}
@@ -548,7 +555,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
-1, 0);
if (retaddr == -1)
goto fail;
- if (pread(fd, g2h(start), len, offset) == -1)
+ if (pread(fd, g2h_untagged(start), len, offset) == -1)
goto fail;
if (!(host_prot & PROT_WRITE)) {
ret = target_mprotect(start, len, target_prot);
@@ -592,13 +599,17 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
offset1 = 0;
else
offset1 = offset + real_start - start;
- p = mmap(g2h(real_start), real_end - real_start,
+ p = mmap(g2h_untagged(real_start), real_end - real_start,
host_prot, flags, fd, offset1);
if (p == MAP_FAILED)
goto fail;
}
}
the_end1:
+ if (flags & MAP_ANONYMOUS) {
+ page_flags |= PAGE_ANON;
+ }
+ page_flags |= PAGE_RESET;
page_set_flags(start, start + len, page_flags);
the_end:
trace_target_mmap_complete(start);
@@ -648,7 +659,7 @@ static void mmap_reserve(abi_ulong start, abi_ulong size)
real_end -= qemu_host_page_size;
}
if (real_start != real_end) {
- mmap(g2h(real_start), real_end - real_start, PROT_NONE,
+ mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
-1, 0);
}
@@ -664,7 +675,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
if (start & ~TARGET_PAGE_MASK)
return -TARGET_EINVAL;
len = TARGET_PAGE_ALIGN(len);
- if (len == 0 || !guest_range_valid(start, len)) {
+ if (len == 0 || !guest_range_valid_untagged(start, len)) {
return -TARGET_EINVAL;
}
@@ -703,7 +714,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
if (reserved_va) {
mmap_reserve(real_start, real_end - real_start);
} else {
- ret = munmap(g2h(real_start), real_end - real_start);
+ ret = munmap(g2h_untagged(real_start), real_end - real_start);
}
}
@@ -722,11 +733,11 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
int prot;
void *host_addr;
- if (!guest_range_valid(old_addr, old_size) ||
+ if (!guest_range_valid_untagged(old_addr, old_size) ||
((flags & MREMAP_FIXED) &&
- !guest_range_valid(new_addr, new_size)) ||
+ !guest_range_valid_untagged(new_addr, new_size)) ||
((flags & MREMAP_MAYMOVE) == 0 &&
- !guest_range_valid(old_addr, new_size))) {
+ !guest_range_valid_untagged(old_addr, new_size))) {
errno = ENOMEM;
return -1;
}
@@ -734,8 +745,8 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
mmap_lock();
if (flags & MREMAP_FIXED) {
- host_addr = mremap(g2h(old_addr), old_size, new_size,
- flags, g2h(new_addr));
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags, g2h_untagged(new_addr));
if (reserved_va && host_addr != MAP_FAILED) {
/* If new and old addresses overlap then the above mremap will
@@ -751,8 +762,9 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
errno = ENOMEM;
host_addr = MAP_FAILED;
} else {
- host_addr = mremap(g2h(old_addr), old_size, new_size,
- flags | MREMAP_FIXED, g2h(mmap_start));
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags | MREMAP_FIXED,
+ g2h_untagged(mmap_start));
if (reserved_va) {
mmap_reserve(old_addr, old_size);
}
@@ -768,14 +780,15 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
}
}
if (prot == 0) {
- host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
+ host_addr = mremap(g2h_untagged(old_addr),
+ old_size, new_size, flags);
if (host_addr != MAP_FAILED) {
/* Check if address fits target address space */
- if (!guest_range_valid(h2g(host_addr), new_size)) {
+ if (!guest_range_valid_untagged(h2g(host_addr), new_size)) {
/* Revert mremap() changes */
- host_addr = mremap(g2h(old_addr), new_size, old_size,
- flags);
+ host_addr = mremap(g2h_untagged(old_addr),
+ new_size, old_size, flags);
errno = ENOMEM;
host_addr = MAP_FAILED;
} else if (reserved_va && old_size > new_size) {
@@ -794,7 +807,8 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
new_addr = h2g(host_addr);
prot = page_get_flags(old_addr);
page_set_flags(old_addr, old_addr + old_size, 0);
- page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
+ page_set_flags(new_addr, new_addr + new_size,
+ prot | PAGE_VALID | PAGE_RESET);
}
tb_invalidate_phys_range(new_addr, new_addr + new_size);
mmap_unlock();
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 20a02c197c..b78613f7c8 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -365,7 +365,7 @@ static void restore_user_regs(CPUPPCState *env,
uint64_t v_addr;
/* 64-bit needs to recover the pointer to the vectors from the frame */
__get_user(v_addr, &frame->v_regs);
- v_regs = g2h(v_addr);
+ v_regs = g2h(env_cpu(env), v_addr);
#else
v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
#endif
@@ -552,7 +552,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if (get_ppc64_abi(image) < 2) {
/* ELFv1 PPC64 function pointers are pointers to OPD entries. */
struct target_func_ptr *handler =
- (struct target_func_ptr *)g2h(ka->_sa_handler);
+ (struct target_func_ptr *)g2h(env_cpu(env), ka->_sa_handler);
env->nip = tswapl(handler->entry);
env->gpr[2] = tswapl(handler->toc);
} else {
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 17aa992165..d25a5dafc0 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -7,8 +7,6 @@
#include "exec/cpu_ldst.h"
#undef DEBUG_REMAP
-#ifdef DEBUG_REMAP
-#endif /* DEBUG_REMAP */
#include "exec/user/abitypes.h"
@@ -488,15 +486,23 @@ extern unsigned long guest_stack_size;
/* user access */
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1 /* implies read access */
+#define VERIFY_READ PAGE_READ
+#define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)
-static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
+static inline bool access_ok_untagged(int type, abi_ulong addr, abi_ulong size)
{
- return guest_addr_valid(addr) &&
- (size == 0 || guest_addr_valid(addr + size - 1)) &&
- page_check_range((target_ulong)addr, size,
- (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
+ if (size == 0
+ ? !guest_addr_valid_untagged(addr)
+ : !guest_range_valid_untagged(addr, size)) {
+ return false;
+ }
+ return page_check_range((target_ulong)addr, size, type) == 0;
+}
+
+static inline bool access_ok(CPUState *cpu, int type,
+ abi_ulong addr, abi_ulong size)
+{
+ return access_ok_untagged(type, cpu_untagged_addr(cpu, addr), size);
}
/* NOTE __get_user and __put_user use host pointers and don't check access.
@@ -621,8 +627,8 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
* buffers between the target and host. These internally perform
* locking/unlocking of the memory.
*/
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
/* Functions for accessing guest memory. The tget and tput functions
read/write single values, byteswapping as necessary. The lock_user function
@@ -632,56 +638,24 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
/* Lock an area of guest memory into the host. If copy is true then the
host area will have the same contents as the guest. */
-static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
-{
- if (!access_ok(type, guest_addr, len))
- return NULL;
-#ifdef DEBUG_REMAP
- {
- void *addr;
- addr = g_malloc(len);
- if (copy)
- memcpy(addr, g2h(guest_addr), len);
- else
- memset(addr, 0, len);
- return addr;
- }
-#else
- return g2h(guest_addr);
-#endif
-}
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy);
/* Unlock an area of guest memory. The first LEN bytes must be
flushed back to guest memory. host_ptr = NULL is explicitly
allowed and does nothing. */
-static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
- long len)
-{
-
-#ifdef DEBUG_REMAP
- if (!host_ptr)
- return;
- if (host_ptr == g2h(guest_addr))
- return;
- if (len > 0)
- memcpy(g2h(guest_addr), host_ptr, len);
- g_free(host_ptr);
+#ifndef DEBUG_REMAP
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
+{ }
+#else
+void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
#endif
-}
/* Return the length of a string in target memory or -TARGET_EFAULT if
access error. */
-abi_long target_strlen(abi_ulong gaddr);
+ssize_t target_strlen(abi_ulong gaddr);
/* Like lock_user but for null terminated strings. */
-static inline void *lock_user_string(abi_ulong guest_addr)
-{
- abi_long len;
- len = target_strlen(guest_addr);
- if (len < 0)
- return NULL;
- return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
-}
+void *lock_user_string(abi_ulong guest_addr);
/* Helper macros for locking/unlocking a target struct. */
#define lock_user_struct(type, host_ptr, guest_addr, copy) \
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:
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index f98c1c1c8d..46a960fccb 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1311,6 +1311,7 @@ struct target_winsize {
#ifdef TARGET_AARCH64
#define TARGET_PROT_BTI 0x10
+#define TARGET_PROT_MTE 0x20
#endif
/* Common */
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
index e215ecc2a6..c696913016 100644
--- a/linux-user/uaccess.c
+++ b/linux-user/uaccess.c
@@ -4,46 +4,93 @@
#include "qemu.h"
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy)
+{
+ void *host_addr;
+
+ guest_addr = cpu_untagged_addr(thread_cpu, guest_addr);
+ if (!access_ok_untagged(type, guest_addr, len)) {
+ return NULL;
+ }
+ host_addr = g2h_untagged(guest_addr);
+#ifdef DEBUG_REMAP
+ if (copy) {
+ host_addr = g_memdup(host_addr, len);
+ } else {
+ host_addr = g_malloc0(len);
+ }
+#endif
+ return host_addr;
+}
+
+#ifdef DEBUG_REMAP
+void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len);
+{
+ void *host_ptr_conv;
+
+ if (!host_ptr) {
+ return;
+ }
+ host_ptr_conv = g2h(thread_cpu, guest_addr);
+ if (host_ptr == host_ptr_conv) {
+ return;
+ }
+ if (len != 0) {
+ memcpy(host_ptr_conv, host_ptr, len);
+ }
+ g_free(host_ptr);
+}
+#endif
+
+void *lock_user_string(abi_ulong guest_addr)
+{
+ ssize_t len = target_strlen(guest_addr);
+ if (len < 0) {
+ return NULL;
+ }
+ return lock_user(VERIFY_READ, guest_addr, (size_t)len + 1, 1);
+}
+
/* copy_from_user() and copy_to_user() are usually used to copy data
* buffers between the target and host. These internally perform
* locking/unlocking of the memory.
*/
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
{
- abi_long ret = 0;
- void *ghptr;
+ int ret = 0;
+ void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1);
- if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
+ if (ghptr) {
memcpy(hptr, ghptr, len);
unlock_user(ghptr, gaddr, 0);
- } else
+ } else {
ret = -TARGET_EFAULT;
-
+ }
return ret;
}
-
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
{
- abi_long ret = 0;
- void *ghptr;
+ int ret = 0;
+ void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0);
- if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
+ if (ghptr) {
memcpy(ghptr, hptr, len);
unlock_user(ghptr, gaddr, len);
- } else
+ } else {
ret = -TARGET_EFAULT;
+ }
return ret;
}
/* Return the length of a string in target memory or -TARGET_EFAULT if
access error */
-abi_long target_strlen(abi_ulong guest_addr1)
+ssize_t target_strlen(abi_ulong guest_addr1)
{
uint8_t *ptr;
abi_ulong guest_addr;
- int max_len, len;
+ size_t max_len, len;
guest_addr = guest_addr1;
for(;;) {
@@ -55,11 +102,12 @@ abi_long target_strlen(abi_ulong guest_addr1)
unlock_user(ptr, guest_addr, 0);
guest_addr += len;
/* we don't allow wrapping or integer overflow */
- if (guest_addr == 0 ||
- (guest_addr - guest_addr1) > 0x7fffffff)
+ if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) {
return -TARGET_EFAULT;
- if (len != max_len)
+ }
+ if (len != max_len) {
break;
+ }
}
return guest_addr - guest_addr1;
}