diff options
Diffstat (limited to 'linux-user/i386')
-rw-r--r-- | linux-user/i386/cpu_loop.c | 50 | ||||
-rw-r--r-- | linux-user/i386/elfload.c | 47 | ||||
-rw-r--r-- | linux-user/i386/target_elf.h | 41 | ||||
-rw-r--r-- | linux-user/i386/target_ptrace.h | 32 | ||||
-rw-r--r-- | linux-user/i386/target_syscall.h | 18 | ||||
-rw-r--r-- | linux-user/i386/vdso.S | 2 | ||||
-rwxr-xr-x | linux-user/i386/vdso.so | bin | 2672 -> 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 Binary files differindex bdece5d..e01c381 100755 --- a/linux-user/i386/vdso.so +++ b/linux-user/i386/vdso.so |