aboutsummaryrefslogtreecommitdiff
path: root/linux-user/i386
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/i386')
-rw-r--r--linux-user/i386/cpu_loop.c50
-rw-r--r--linux-user/i386/elfload.c47
-rw-r--r--linux-user/i386/target_elf.h41
-rw-r--r--linux-user/i386/target_ptrace.h32
-rw-r--r--linux-user/i386/target_syscall.h18
-rw-r--r--linux-user/i386/vdso.S2
-rwxr-xr-xlinux-user/i386/vdso.sobin2672 -> 2792 bytes
7 files changed, 141 insertions, 49 deletions
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index d96d555..f3f5857 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -214,7 +214,7 @@ void cpu_loop(CPUX86State *env)
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
cpu_exec_end(cs);
- process_queued_cpu_work(cs);
+ qemu_process_cpu_events(cs);
switch(trapnr) {
case 0x80:
@@ -331,11 +331,10 @@ static void target_cpu_free(void *obj)
g_free(obj);
}
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cpu, struct image_info *info)
{
- CPUState *cpu = env_cpu(env);
+ CPUArchState *env = cpu_env(cpu);
bool is64 = (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) != 0;
- int i;
OBJECT(cpu)->free = target_cpu_free;
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
@@ -361,28 +360,25 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
- /* linux register setup */
-#ifndef TARGET_ABI32
- env->regs[R_EAX] = regs->rax;
- env->regs[R_EBX] = regs->rbx;
- env->regs[R_ECX] = regs->rcx;
- env->regs[R_EDX] = regs->rdx;
- env->regs[R_ESI] = regs->rsi;
- env->regs[R_EDI] = regs->rdi;
- env->regs[R_EBP] = regs->rbp;
- env->regs[R_ESP] = regs->rsp;
- env->eip = regs->rip;
-#else
- env->regs[R_EAX] = regs->eax;
- env->regs[R_EBX] = regs->ebx;
- env->regs[R_ECX] = regs->ecx;
- env->regs[R_EDX] = regs->edx;
- env->regs[R_ESI] = regs->esi;
- env->regs[R_EDI] = regs->edi;
- env->regs[R_EBP] = regs->ebp;
- env->regs[R_ESP] = regs->esp;
- env->eip = regs->eip;
-#endif
+ /*
+ * Linux register setup.
+ *
+ * SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+ * starts %edx contains a pointer to a function which might be
+ * registered using `atexit'. This provides a mean for the
+ * dynamic linker to call DT_FINI functions for shared libraries
+ * that have been loaded before the code runs.
+ * A value of 0 tells we have no such handler.
+ *
+ * This applies to x86_64 as well as i386.
+ *
+ * That said, the kernel's ELF_PLAT_INIT simply zeros all of the general
+ * registers. Note that x86_cpu_reset_hold will set %edx to cpuid_version;
+ * clear all general registers defensively.
+ */
+ memset(env->regs, 0, sizeof(env->regs));
+ env->regs[R_ESP] = info->start_stack;
+ env->eip = info->entry;
/* linux interrupt setup */
#ifndef TARGET_ABI32
@@ -394,7 +390,7 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
idt_table = g2h_untagged(env->idt.base);
- for (i = 0; i < 20; i++) {
+ for (int i = 0; i < 20; i++) {
set_idt(i, 0, is64);
}
set_idt(3, 3, is64);
diff --git a/linux-user/i386/elfload.c b/linux-user/i386/elfload.c
new file mode 100644
index 0000000..26b1200
--- /dev/null
+++ b/linux-user/i386/elfload.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "loader.h"
+#include "target_elf.h"
+
+
+const char *get_elf_cpu_model(uint32_t eflags)
+{
+ return "max";
+}
+
+abi_ulong get_elf_hwcap(CPUState *cs)
+{
+ return cpu_env(cs)->features[FEAT_1_EDX];
+}
+
+const char *get_elf_platform(CPUState *cs)
+{
+ static const char elf_platform[4][5] = { "i386", "i486", "i586", "i686" };
+ int family = object_property_get_int(OBJECT(cs), "family", NULL);
+
+ family = MAX(MIN(family, 6), 3);
+ return elf_platform[family - 3];
+}
+
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUX86State *env)
+{
+ r->pt.bx = tswapal(env->regs[R_EBX]);
+ r->pt.cx = tswapal(env->regs[R_ECX]);
+ r->pt.dx = tswapal(env->regs[R_EDX]);
+ r->pt.si = tswapal(env->regs[R_ESI]);
+ r->pt.di = tswapal(env->regs[R_EDI]);
+ r->pt.bp = tswapal(env->regs[R_EBP]);
+ r->pt.ax = tswapal(env->regs[R_EAX]);
+ r->pt.ds = tswapal(env->segs[R_DS].selector & 0xffff);
+ r->pt.es = tswapal(env->segs[R_ES].selector & 0xffff);
+ r->pt.fs = tswapal(env->segs[R_FS].selector & 0xffff);
+ r->pt.gs = tswapal(env->segs[R_GS].selector & 0xffff);
+ r->pt.orig_ax = tswapal(get_task_state(env_cpu_const(env))->orig_ax);
+ r->pt.ip = tswapal(env->eip);
+ r->pt.cs = tswapal(env->segs[R_CS].selector & 0xffff);
+ r->pt.flags = tswapal(env->eflags);
+ r->pt.sp = tswapal(env->regs[R_ESP]);
+ r->pt.ss = tswapal(env->segs[R_SS].selector & 0xffff);
+}
diff --git a/linux-user/i386/target_elf.h b/linux-user/i386/target_elf.h
index 238a9ab..eafac8f 100644
--- a/linux-user/i386/target_elf.h
+++ b/linux-user/i386/target_elf.h
@@ -7,8 +7,41 @@
#ifndef I386_TARGET_ELF_H
#define I386_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "max";
-}
+
+#include "target_ptrace.h"
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_MACHINE EM_386
+#define EXSTACK_DEFAULT true
+#define VDSO_HEADER "vdso.c.inc"
+
+#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_PLATFORM 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * See linux kernel: arch/x86/include/asm/elf.h, where elf_gregset_t
+ * is mapped to struct user_regs_struct via sizeof.
+ */
+typedef struct target_elf_gregset_t {
+ struct target_user_regs_struct pt;
+} target_elf_gregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_machine(x) ((x) == EM_386 || (x) == EM_486)
+
+/*
+ * i386 is the only target which supplies AT_SYSINFO for the vdso.
+ * All others only supply AT_SYSINFO_EHDR.
+ */
+#define DLINFO_ARCH_ITEMS (vdso_info != NULL)
+#define ARCH_DLINFO \
+ do { \
+ if (vdso_info) { \
+ NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry); \
+ } \
+ } while (0)
+
#endif
diff --git a/linux-user/i386/target_ptrace.h b/linux-user/i386/target_ptrace.h
new file mode 100644
index 0000000..bc57926
--- /dev/null
+++ b/linux-user/i386/target_ptrace.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef I386_TARGET_PTRACE_H
+#define I386_TARGET_PTRACE_H
+
+/*
+ * Note that arch/x86/include/uapi/asm/ptrace.h (struct pt_regs) and
+ * arch/x86/include/asm/user_32.h (struct user_regs_struct) have the
+ * same layout, though the exact types differ (int vs long vs unsigned).
+ * Define user_regs_struct because that's what's actually used.
+ */
+struct target_user_regs_struct {
+ abi_ulong bx;
+ abi_ulong cx;
+ abi_ulong dx;
+ abi_ulong si;
+ abi_ulong di;
+ abi_ulong bp;
+ abi_ulong ax;
+ abi_ulong ds;
+ abi_ulong es;
+ abi_ulong fs;
+ abi_ulong gs;
+ abi_ulong orig_ax;
+ abi_ulong ip;
+ abi_ulong cs;
+ abi_ulong flags;
+ abi_ulong sp;
+ abi_ulong ss;
+};
+
+#endif /* I386_TARGET_PTRACE_H */
diff --git a/linux-user/i386/target_syscall.h b/linux-user/i386/target_syscall.h
index aaade06..c214a90 100644
--- a/linux-user/i386/target_syscall.h
+++ b/linux-user/i386/target_syscall.h
@@ -5,24 +5,6 @@
#define __USER_CS (0x23)
#define __USER_DS (0x2B)
-struct target_pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- int xds;
- int xes;
- long orig_eax;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
-};
-
/* ioctls */
#define TARGET_LDT_ENTRIES 8192
diff --git a/linux-user/i386/vdso.S b/linux-user/i386/vdso.S
index e7a1f33..8df77b5 100644
--- a/linux-user/i386/vdso.S
+++ b/linux-user/i386/vdso.S
@@ -114,6 +114,7 @@ vdso_syscall3 __vdso_getcpu, __NR_gettimeofday
*/
nop
+sigreturn_region_start:
__kernel_sigreturn:
popl %eax /* pop sig */
.cfi_adjust_cfa_offset -4
@@ -128,6 +129,7 @@ __kernel_rt_sigreturn:
movl $__NR_rt_sigreturn, %eax
int $0x80
endf __kernel_rt_sigreturn
+sigreturn_region_end:
.cfi_endproc
diff --git a/linux-user/i386/vdso.so b/linux-user/i386/vdso.so
index bdece5d..e01c381 100755
--- a/linux-user/i386/vdso.so
+++ b/linux-user/i386/vdso.so
Binary files differ