From 84409ddbda9b4d8f2d2ad4f580e987800b8e7c4e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 6 Apr 2007 08:56:50 +0000 Subject: [PATCH] Code provision for x86_64 and PowerPC 64 linux user mode support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2619 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 41 +++++++++++++++++++++++++++++++++++++++++ linux-user/main.c | 35 +++++++++++++++++++++++++++++++---- linux-user/qemu.h | 2 +- linux-user/signal.c | 6 +++++- linux-user/syscall.c | 4 ++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5caa44eafd..1256dba953 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -44,6 +44,23 @@ static uint32_t get_elf_hwcap(void) return global_env->cpuid_features; } +#ifdef TARGET_X86_64 +#define ELF_START_MMAP 0x2aaaaab000ULL +#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->rax = 0; + regs->rsp = infop->start_stack; + regs->rip = infop->entry; +} + +#else + #define ELF_START_MMAP 0x80000000 /* @@ -72,6 +89,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i A value of 0 tells we have no such handler. */ regs->edx = 0; } +#endif #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -177,9 +195,20 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 +#ifdef TARGET_PPC64 + +#define elf_check_arch(x) ( (x) == EM_PPC64 ) + +#define ELF_CLASS ELFCLASS64 + +#else + #define elf_check_arch(x) ( (x) == EM_PPC ) #define ELF_CLASS ELFCLASS32 + +#endif + #ifdef TARGET_WORDS_BIGENDIAN #define ELF_DATA ELFDATA2MSB #else @@ -222,9 +251,18 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * { target_ulong pos = infop->start_stack; target_ulong tmp; +#ifdef TARGET_PPC64 + target_ulong entry, toc; +#endif _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; +#ifdef TARGET_PPC64 + entry = ldq_raw(infop->entry) + infop->load_addr; + toc = ldq_raw(infop->entry + 8) + infop->load_addr; + _regs->gpr[2] = toc; + infop->entry = entry; +#endif _regs->nip = infop->entry; /* Note that isn't exactly what regular kernel does * but this is what the ABI wants and is needed to allow @@ -917,6 +955,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, unsigned long elf_entry, interp_load_addr = 0; int status; unsigned long start_code, end_code, end_data; + unsigned long reloc_func_desc = 0; unsigned long elf_stack; char passed_fileno[6]; @@ -1181,6 +1220,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, load_bias += error - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); load_addr += load_bias; + reloc_func_desc = load_bias; } } k = elf_ppnt->p_vaddr; @@ -1213,6 +1253,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, &interp_load_addr); } + reloc_func_desc = interp_load_addr; close(interpreter_fd); free(elf_interpreter); diff --git a/linux-user/main.c b/linux-user/main.c index cad10e646b..74798c7cc5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP0D_GPF: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_fault(env); - } else { + } else +#endif + { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; @@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP00_DIVZ: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { /* division by zero */ info.si_signo = SIGFPE; info.si_errno = 0; @@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env) break; case EXCP01_SSTP: case EXCP03_INT3: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { info.si_signo = SIGTRAP; info.si_errno = 0; if (trapnr == EXCP01_SSTP) { @@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env) break; case EXCP04_INTO: case EXCP05_BOUND: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; @@ -1807,6 +1819,17 @@ int main(int argc, char **argv) env->eflags |= IF_MASK; /* linux register setup */ +#if defined(TARGET_X86_64) + 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; @@ -1816,6 +1839,7 @@ int main(int argc, char **argv) env->regs[R_EBP] = regs->ebp; env->regs[R_ESP] = regs->esp; env->eip = regs->eip; +#endif /* linux interrupt setup */ env->idt.base = h2g(idt_table); @@ -1903,6 +1927,9 @@ int main(int argc, char **argv) if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; } +#if defined(TARGET_PPC64) + msr_sf = 1; +#endif env->nip = regs->nip; for(i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index f894dde084..31e29da7dc 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -68,7 +68,7 @@ typedef struct TaskState { uint32_t heap_limit; int swi_errno; #endif -#ifdef TARGET_I386 +#if defined(TARGET_I386) && !defined(TARGET_X86_64) target_ulong target_v86; struct vm86_saved_state vm86_saved_regs; struct target_vm86plus_struct vm86plus; diff --git a/linux-user/signal.c b/linux-user/signal.c index 1e29c2c502..5a99e610dc 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -690,7 +690,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); +#if defined(TARGET_X86_64) +#warning "Fix this !" +#else err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); +#endif err |= __put_user(0x80cd, (short *)(frame->retcode+6)); } @@ -2048,7 +2052,7 @@ void process_pending_signals(void *cpu_env) host_to_target_sigset_internal(&target_old_set, &old_set); /* if the CPU is in VM86 mode, we restore the 32 bit values */ -#ifdef TARGET_I386 +#if defined(TARGET_I386) && !defined(TARGET_X86_64) { CPUX86State *env = cpu_env; if (env->eflags & VM_MASK) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9dc0b09b05..7ab506dd3d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3250,12 +3250,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_modify_ldt: ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); break; +#if !defined(TARGET_X86_64) case TARGET_NR_vm86old: goto unimplemented; case TARGET_NR_vm86: ret = do_vm86(cpu_env, arg1, arg2); break; #endif +#endif case TARGET_NR_adjtimex: goto unimplemented; #ifdef TARGET_NR_create_module @@ -3275,8 +3277,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fchdir: ret = get_errno(fchdir(arg1)); break; +#ifdef TARGET_NR_bdflush /* not on x86_64 */ case TARGET_NR_bdflush: goto unimplemented; +#endif #ifdef TARGET_NR_sysfs case TARGET_NR_sysfs: goto unimplemented; -- 2.11.4.GIT