summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--linux-user/elfload.c30
-rw-r--r--linux-user/mmap.c64
-rw-r--r--linux-user/syscall.c20
-rw-r--r--linux-user/user-internals.h1
-rw-r--r--linux-user/user-mmap.h1
5 files changed, 92 insertions, 24 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f7eae357f4..163fc8a1ee 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -130,19 +130,6 @@ typedef abi_int target_pid_t;
#ifdef TARGET_I386
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
- static char elf_platform[] = "i386";
- int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
- if (family > 6)
- family = 6;
- if (family >= 3)
- elf_platform[1] = '0' + family;
- return elf_platform;
-}
-
#define ELF_HWCAP get_elf_hwcap()
static uint32_t get_elf_hwcap(void)
@@ -158,6 +145,8 @@ static uint32_t get_elf_hwcap(void)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_X86_64
+#define ELF_PLATFORM "x86_64"
+
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->rax = 0;
@@ -221,6 +210,21 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_386
+#define ELF_PLATFORM get_elf_platform()
+
+static const char *get_elf_platform(void)
+{
+ static char elf_platform[] = "i386";
+ int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
+ if (family > 6) {
+ family = 6;
+ }
+ if (family >= 3) {
+ elf_platform[1] = '0' + family;
+ }
+ return elf_platform;
+}
+
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 48e1373796..4e7a6be6ee 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -835,3 +835,67 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
mmap_unlock();
return new_addr;
}
+
+static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end)
+{
+ ulong addr;
+
+ if ((start | end) & ~qemu_host_page_mask) {
+ return false;
+ }
+
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ if (!(page_get_flags(addr) & PAGE_ANON)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
+{
+ abi_ulong len, end;
+ int ret = 0;
+
+ if (start & ~TARGET_PAGE_MASK) {
+ return -TARGET_EINVAL;
+ }
+ len = TARGET_PAGE_ALIGN(len_in);
+
+ if (len_in && !len) {
+ return -TARGET_EINVAL;
+ }
+
+ end = start + len;
+ if (end < start) {
+ return -TARGET_EINVAL;
+ }
+
+ if (end == start) {
+ return 0;
+ }
+
+ if (!guest_range_valid_untagged(start, len)) {
+ return -TARGET_EINVAL;
+ }
+
+ /*
+ * A straight passthrough may not be safe because qemu sometimes turns
+ * private file-backed mappings into anonymous mappings.
+ *
+ * This is a hint, so ignoring and returning success is ok.
+ *
+ * This breaks MADV_DONTNEED, completely implementing which is quite
+ * complicated. However, there is one low-hanging fruit: host-page-aligned
+ * anonymous mappings. In this case passthrough is safe, so do it.
+ */
+ mmap_lock();
+ if ((advice & MADV_DONTNEED) &&
+ can_passthrough_madv_dontneed(start, end)) {
+ ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED));
+ }
+ mmap_unlock();
+
+ return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f55cdebee5..669add74c1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -320,9 +320,6 @@ _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
#endif
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
-_syscall1(int,set_tid_address,int *,tidptr)
-#endif
#if defined(__NR_futex)
_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
@@ -538,7 +535,7 @@ static inline int target_to_host_errno(int target_errno)
}
}
-static inline abi_long get_errno(abi_long ret)
+abi_long get_errno(abi_long ret)
{
if (ret == -1)
return -host_to_target_errno(errno);
@@ -11807,11 +11804,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_madvise
case TARGET_NR_madvise:
- /* A straight passthrough may not be safe because qemu sometimes
- turns private file-backed mappings into anonymous mappings.
- This will break MADV_DONTNEED.
- This is a hint, so ignoring and returning success is ok. */
- return 0;
+ return target_madvise(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_fcntl64
case TARGET_NR_fcntl64:
@@ -12200,9 +12193,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
}
#endif
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+#if defined(TARGET_NR_set_tid_address)
case TARGET_NR_set_tid_address:
- return get_errno(set_tid_address((int *)g2h(cpu, arg1)));
+ {
+ TaskState *ts = cpu->opaque;
+ ts->child_tidptr = arg1;
+ /* do not call host set_tid_address() syscall, instead return tid() */
+ return get_errno(sys_gettid());
+ }
#endif
case TARGET_NR_tkill:
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index 6175ce53db..0280e76add 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -65,6 +65,7 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
abi_long arg8);
extern __thread CPUState *thread_cpu;
G_NORETURN void cpu_loop(CPUArchState *env);
+abi_long get_errno(abi_long ret);
const char *target_strerror(int err);
int get_osversion(void);
void init_qemu_uname_release(void);
diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h
index d1dec99c02..480ce1c114 100644
--- a/linux-user/user-mmap.h
+++ b/linux-user/user-mmap.h
@@ -25,6 +25,7 @@ int target_munmap(abi_ulong start, abi_ulong len);
abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_size, unsigned long flags,
abi_ulong new_addr);
+abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice);
extern unsigned long last_brk;
extern abi_ulong mmap_next_start;
abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong);