Commit 84409ddbda9b4d8f2d2ad4f580e987800b8e7c4e
1 parent
9ead1a12
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
Showing
5 changed files
with
82 additions
and
6 deletions
linux-user/elfload.c
@@ -44,6 +44,23 @@ static uint32_t get_elf_hwcap(void) | @@ -44,6 +44,23 @@ static uint32_t get_elf_hwcap(void) | ||
44 | return global_env->cpuid_features; | 44 | return global_env->cpuid_features; |
45 | } | 45 | } |
46 | 46 | ||
47 | +#ifdef TARGET_X86_64 | ||
48 | +#define ELF_START_MMAP 0x2aaaaab000ULL | ||
49 | +#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) | ||
50 | + | ||
51 | +#define ELF_CLASS ELFCLASS64 | ||
52 | +#define ELF_DATA ELFDATA2LSB | ||
53 | +#define ELF_ARCH EM_X86_64 | ||
54 | + | ||
55 | +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) | ||
56 | +{ | ||
57 | + regs->rax = 0; | ||
58 | + regs->rsp = infop->start_stack; | ||
59 | + regs->rip = infop->entry; | ||
60 | +} | ||
61 | + | ||
62 | +#else | ||
63 | + | ||
47 | #define ELF_START_MMAP 0x80000000 | 64 | #define ELF_START_MMAP 0x80000000 |
48 | 65 | ||
49 | /* | 66 | /* |
@@ -72,6 +89,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -72,6 +89,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
72 | A value of 0 tells we have no such handler. */ | 89 | A value of 0 tells we have no such handler. */ |
73 | regs->edx = 0; | 90 | regs->edx = 0; |
74 | } | 91 | } |
92 | +#endif | ||
75 | 93 | ||
76 | #define USE_ELF_CORE_DUMP | 94 | #define USE_ELF_CORE_DUMP |
77 | #define ELF_EXEC_PAGESIZE 4096 | 95 | #define ELF_EXEC_PAGESIZE 4096 |
@@ -177,9 +195,20 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -177,9 +195,20 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
177 | 195 | ||
178 | #define ELF_START_MMAP 0x80000000 | 196 | #define ELF_START_MMAP 0x80000000 |
179 | 197 | ||
198 | +#ifdef TARGET_PPC64 | ||
199 | + | ||
200 | +#define elf_check_arch(x) ( (x) == EM_PPC64 ) | ||
201 | + | ||
202 | +#define ELF_CLASS ELFCLASS64 | ||
203 | + | ||
204 | +#else | ||
205 | + | ||
180 | #define elf_check_arch(x) ( (x) == EM_PPC ) | 206 | #define elf_check_arch(x) ( (x) == EM_PPC ) |
181 | 207 | ||
182 | #define ELF_CLASS ELFCLASS32 | 208 | #define ELF_CLASS ELFCLASS32 |
209 | + | ||
210 | +#endif | ||
211 | + | ||
183 | #ifdef TARGET_WORDS_BIGENDIAN | 212 | #ifdef TARGET_WORDS_BIGENDIAN |
184 | #define ELF_DATA ELFDATA2MSB | 213 | #define ELF_DATA ELFDATA2MSB |
185 | #else | 214 | #else |
@@ -222,9 +251,18 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * | @@ -222,9 +251,18 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * | ||
222 | { | 251 | { |
223 | target_ulong pos = infop->start_stack; | 252 | target_ulong pos = infop->start_stack; |
224 | target_ulong tmp; | 253 | target_ulong tmp; |
254 | +#ifdef TARGET_PPC64 | ||
255 | + target_ulong entry, toc; | ||
256 | +#endif | ||
225 | 257 | ||
226 | _regs->msr = 1 << MSR_PR; /* Set user mode */ | 258 | _regs->msr = 1 << MSR_PR; /* Set user mode */ |
227 | _regs->gpr[1] = infop->start_stack; | 259 | _regs->gpr[1] = infop->start_stack; |
260 | +#ifdef TARGET_PPC64 | ||
261 | + entry = ldq_raw(infop->entry) + infop->load_addr; | ||
262 | + toc = ldq_raw(infop->entry + 8) + infop->load_addr; | ||
263 | + _regs->gpr[2] = toc; | ||
264 | + infop->entry = entry; | ||
265 | +#endif | ||
228 | _regs->nip = infop->entry; | 266 | _regs->nip = infop->entry; |
229 | /* Note that isn't exactly what regular kernel does | 267 | /* Note that isn't exactly what regular kernel does |
230 | * but this is what the ABI wants and is needed to allow | 268 | * 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, | @@ -917,6 +955,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | ||
917 | unsigned long elf_entry, interp_load_addr = 0; | 955 | unsigned long elf_entry, interp_load_addr = 0; |
918 | int status; | 956 | int status; |
919 | unsigned long start_code, end_code, end_data; | 957 | unsigned long start_code, end_code, end_data; |
958 | + unsigned long reloc_func_desc = 0; | ||
920 | unsigned long elf_stack; | 959 | unsigned long elf_stack; |
921 | char passed_fileno[6]; | 960 | char passed_fileno[6]; |
922 | 961 | ||
@@ -1181,6 +1220,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | @@ -1181,6 +1220,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | ||
1181 | load_bias += error - | 1220 | load_bias += error - |
1182 | TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); | 1221 | TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); |
1183 | load_addr += load_bias; | 1222 | load_addr += load_bias; |
1223 | + reloc_func_desc = load_bias; | ||
1184 | } | 1224 | } |
1185 | } | 1225 | } |
1186 | k = elf_ppnt->p_vaddr; | 1226 | k = elf_ppnt->p_vaddr; |
@@ -1213,6 +1253,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | @@ -1213,6 +1253,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | ||
1213 | elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, | 1253 | elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, |
1214 | &interp_load_addr); | 1254 | &interp_load_addr); |
1215 | } | 1255 | } |
1256 | + reloc_func_desc = interp_load_addr; | ||
1216 | 1257 | ||
1217 | close(interpreter_fd); | 1258 | close(interpreter_fd); |
1218 | free(elf_interpreter); | 1259 | free(elf_interpreter); |
linux-user/main.c
@@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env) | @@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env) | ||
194 | queue_signal(info.si_signo, &info); | 194 | queue_signal(info.si_signo, &info); |
195 | break; | 195 | break; |
196 | case EXCP0D_GPF: | 196 | case EXCP0D_GPF: |
197 | +#ifndef TARGET_X86_64 | ||
197 | if (env->eflags & VM_MASK) { | 198 | if (env->eflags & VM_MASK) { |
198 | handle_vm86_fault(env); | 199 | handle_vm86_fault(env); |
199 | - } else { | 200 | + } else |
201 | +#endif | ||
202 | + { | ||
200 | info.si_signo = SIGSEGV; | 203 | info.si_signo = SIGSEGV; |
201 | info.si_errno = 0; | 204 | info.si_errno = 0; |
202 | info.si_code = TARGET_SI_KERNEL; | 205 | info.si_code = TARGET_SI_KERNEL; |
@@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env) | @@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env) | ||
215 | queue_signal(info.si_signo, &info); | 218 | queue_signal(info.si_signo, &info); |
216 | break; | 219 | break; |
217 | case EXCP00_DIVZ: | 220 | case EXCP00_DIVZ: |
221 | +#ifndef TARGET_X86_64 | ||
218 | if (env->eflags & VM_MASK) { | 222 | if (env->eflags & VM_MASK) { |
219 | handle_vm86_trap(env, trapnr); | 223 | handle_vm86_trap(env, trapnr); |
220 | - } else { | 224 | + } else |
225 | +#endif | ||
226 | + { | ||
221 | /* division by zero */ | 227 | /* division by zero */ |
222 | info.si_signo = SIGFPE; | 228 | info.si_signo = SIGFPE; |
223 | info.si_errno = 0; | 229 | info.si_errno = 0; |
@@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env) | @@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env) | ||
228 | break; | 234 | break; |
229 | case EXCP01_SSTP: | 235 | case EXCP01_SSTP: |
230 | case EXCP03_INT3: | 236 | case EXCP03_INT3: |
237 | +#ifndef TARGET_X86_64 | ||
231 | if (env->eflags & VM_MASK) { | 238 | if (env->eflags & VM_MASK) { |
232 | handle_vm86_trap(env, trapnr); | 239 | handle_vm86_trap(env, trapnr); |
233 | - } else { | 240 | + } else |
241 | +#endif | ||
242 | + { | ||
234 | info.si_signo = SIGTRAP; | 243 | info.si_signo = SIGTRAP; |
235 | info.si_errno = 0; | 244 | info.si_errno = 0; |
236 | if (trapnr == EXCP01_SSTP) { | 245 | if (trapnr == EXCP01_SSTP) { |
@@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env) | @@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env) | ||
245 | break; | 254 | break; |
246 | case EXCP04_INTO: | 255 | case EXCP04_INTO: |
247 | case EXCP05_BOUND: | 256 | case EXCP05_BOUND: |
257 | +#ifndef TARGET_X86_64 | ||
248 | if (env->eflags & VM_MASK) { | 258 | if (env->eflags & VM_MASK) { |
249 | handle_vm86_trap(env, trapnr); | 259 | handle_vm86_trap(env, trapnr); |
250 | - } else { | 260 | + } else |
261 | +#endif | ||
262 | + { | ||
251 | info.si_signo = SIGSEGV; | 263 | info.si_signo = SIGSEGV; |
252 | info.si_errno = 0; | 264 | info.si_errno = 0; |
253 | info.si_code = TARGET_SI_KERNEL; | 265 | info.si_code = TARGET_SI_KERNEL; |
@@ -1807,6 +1819,17 @@ int main(int argc, char **argv) | @@ -1807,6 +1819,17 @@ int main(int argc, char **argv) | ||
1807 | env->eflags |= IF_MASK; | 1819 | env->eflags |= IF_MASK; |
1808 | 1820 | ||
1809 | /* linux register setup */ | 1821 | /* linux register setup */ |
1822 | +#if defined(TARGET_X86_64) | ||
1823 | + env->regs[R_EAX] = regs->rax; | ||
1824 | + env->regs[R_EBX] = regs->rbx; | ||
1825 | + env->regs[R_ECX] = regs->rcx; | ||
1826 | + env->regs[R_EDX] = regs->rdx; | ||
1827 | + env->regs[R_ESI] = regs->rsi; | ||
1828 | + env->regs[R_EDI] = regs->rdi; | ||
1829 | + env->regs[R_EBP] = regs->rbp; | ||
1830 | + env->regs[R_ESP] = regs->rsp; | ||
1831 | + env->eip = regs->rip; | ||
1832 | +#else | ||
1810 | env->regs[R_EAX] = regs->eax; | 1833 | env->regs[R_EAX] = regs->eax; |
1811 | env->regs[R_EBX] = regs->ebx; | 1834 | env->regs[R_EBX] = regs->ebx; |
1812 | env->regs[R_ECX] = regs->ecx; | 1835 | env->regs[R_ECX] = regs->ecx; |
@@ -1816,6 +1839,7 @@ int main(int argc, char **argv) | @@ -1816,6 +1839,7 @@ int main(int argc, char **argv) | ||
1816 | env->regs[R_EBP] = regs->ebp; | 1839 | env->regs[R_EBP] = regs->ebp; |
1817 | env->regs[R_ESP] = regs->esp; | 1840 | env->regs[R_ESP] = regs->esp; |
1818 | env->eip = regs->eip; | 1841 | env->eip = regs->eip; |
1842 | +#endif | ||
1819 | 1843 | ||
1820 | /* linux interrupt setup */ | 1844 | /* linux interrupt setup */ |
1821 | env->idt.base = h2g(idt_table); | 1845 | env->idt.base = h2g(idt_table); |
@@ -1903,6 +1927,9 @@ int main(int argc, char **argv) | @@ -1903,6 +1927,9 @@ int main(int argc, char **argv) | ||
1903 | if (i != 12 && i != 6 && i != 13) | 1927 | if (i != 12 && i != 6 && i != 13) |
1904 | env->msr[i] = (regs->msr >> i) & 1; | 1928 | env->msr[i] = (regs->msr >> i) & 1; |
1905 | } | 1929 | } |
1930 | +#if defined(TARGET_PPC64) | ||
1931 | + msr_sf = 1; | ||
1932 | +#endif | ||
1906 | env->nip = regs->nip; | 1933 | env->nip = regs->nip; |
1907 | for(i = 0; i < 32; i++) { | 1934 | for(i = 0; i < 32; i++) { |
1908 | env->gpr[i] = regs->gpr[i]; | 1935 | env->gpr[i] = regs->gpr[i]; |
linux-user/qemu.h
@@ -68,7 +68,7 @@ typedef struct TaskState { | @@ -68,7 +68,7 @@ typedef struct TaskState { | ||
68 | uint32_t heap_limit; | 68 | uint32_t heap_limit; |
69 | int swi_errno; | 69 | int swi_errno; |
70 | #endif | 70 | #endif |
71 | -#ifdef TARGET_I386 | 71 | +#if defined(TARGET_I386) && !defined(TARGET_X86_64) |
72 | target_ulong target_v86; | 72 | target_ulong target_v86; |
73 | struct vm86_saved_state vm86_saved_regs; | 73 | struct vm86_saved_state vm86_saved_regs; |
74 | struct target_vm86plus_struct vm86plus; | 74 | struct target_vm86plus_struct vm86plus; |
linux-user/signal.c
@@ -690,7 +690,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, | @@ -690,7 +690,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
690 | err |= __put_user(frame->retcode, &frame->pretcode); | 690 | err |= __put_user(frame->retcode, &frame->pretcode); |
691 | /* This is popl %eax ; movl $,%eax ; int $0x80 */ | 691 | /* This is popl %eax ; movl $,%eax ; int $0x80 */ |
692 | err |= __put_user(0xb858, (short *)(frame->retcode+0)); | 692 | err |= __put_user(0xb858, (short *)(frame->retcode+0)); |
693 | +#if defined(TARGET_X86_64) | ||
694 | +#warning "Fix this !" | ||
695 | +#else | ||
693 | err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); | 696 | err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); |
697 | +#endif | ||
694 | err |= __put_user(0x80cd, (short *)(frame->retcode+6)); | 698 | err |= __put_user(0x80cd, (short *)(frame->retcode+6)); |
695 | } | 699 | } |
696 | 700 | ||
@@ -2048,7 +2052,7 @@ void process_pending_signals(void *cpu_env) | @@ -2048,7 +2052,7 @@ void process_pending_signals(void *cpu_env) | ||
2048 | host_to_target_sigset_internal(&target_old_set, &old_set); | 2052 | host_to_target_sigset_internal(&target_old_set, &old_set); |
2049 | 2053 | ||
2050 | /* if the CPU is in VM86 mode, we restore the 32 bit values */ | 2054 | /* if the CPU is in VM86 mode, we restore the 32 bit values */ |
2051 | -#ifdef TARGET_I386 | 2055 | +#if defined(TARGET_I386) && !defined(TARGET_X86_64) |
2052 | { | 2056 | { |
2053 | CPUX86State *env = cpu_env; | 2057 | CPUX86State *env = cpu_env; |
2054 | if (env->eflags & VM_MASK) | 2058 | if (env->eflags & VM_MASK) |
linux-user/syscall.c
@@ -3250,12 +3250,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -3250,12 +3250,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
3250 | case TARGET_NR_modify_ldt: | 3250 | case TARGET_NR_modify_ldt: |
3251 | ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); | 3251 | ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); |
3252 | break; | 3252 | break; |
3253 | +#if !defined(TARGET_X86_64) | ||
3253 | case TARGET_NR_vm86old: | 3254 | case TARGET_NR_vm86old: |
3254 | goto unimplemented; | 3255 | goto unimplemented; |
3255 | case TARGET_NR_vm86: | 3256 | case TARGET_NR_vm86: |
3256 | ret = do_vm86(cpu_env, arg1, arg2); | 3257 | ret = do_vm86(cpu_env, arg1, arg2); |
3257 | break; | 3258 | break; |
3258 | #endif | 3259 | #endif |
3260 | +#endif | ||
3259 | case TARGET_NR_adjtimex: | 3261 | case TARGET_NR_adjtimex: |
3260 | goto unimplemented; | 3262 | goto unimplemented; |
3261 | #ifdef TARGET_NR_create_module | 3263 | #ifdef TARGET_NR_create_module |
@@ -3275,8 +3277,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -3275,8 +3277,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
3275 | case TARGET_NR_fchdir: | 3277 | case TARGET_NR_fchdir: |
3276 | ret = get_errno(fchdir(arg1)); | 3278 | ret = get_errno(fchdir(arg1)); |
3277 | break; | 3279 | break; |
3280 | +#ifdef TARGET_NR_bdflush /* not on x86_64 */ | ||
3278 | case TARGET_NR_bdflush: | 3281 | case TARGET_NR_bdflush: |
3279 | goto unimplemented; | 3282 | goto unimplemented; |
3283 | +#endif | ||
3280 | #ifdef TARGET_NR_sysfs | 3284 | #ifdef TARGET_NR_sysfs |
3281 | case TARGET_NR_sysfs: | 3285 | case TARGET_NR_sysfs: |
3282 | goto unimplemented; | 3286 | goto unimplemented; |