aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-04-06 08:56:50 +0000
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-04-06 08:56:50 +0000
commit84409ddbda9b4d8f2d2ad4f580e987800b8e7c4e (patch)
tree72e2fd0d27817fb60a24b88a1d7b3b25dd5a111d
parent9ead1a126356a05b61eb4388ef0729f08454a78c (diff)
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
-rw-r--r--linux-user/elfload.c41
-rw-r--r--linux-user/main.c35
-rw-r--r--linux-user/qemu.h2
-rw-r--r--linux-user/signal.c6
-rw-r--r--linux-user/syscall.c4
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;