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 | 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 | 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 | 89 | A value of 0 tells we have no such handler. */ |
73 | 90 | regs->edx = 0; |
74 | 91 | } |
92 | +#endif | |
75 | 93 | |
76 | 94 | #define USE_ELF_CORE_DUMP |
77 | 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 | 195 | |
178 | 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 | 206 | #define elf_check_arch(x) ( (x) == EM_PPC ) |
181 | 207 | |
182 | 208 | #define ELF_CLASS ELFCLASS32 |
209 | + | |
210 | +#endif | |
211 | + | |
183 | 212 | #ifdef TARGET_WORDS_BIGENDIAN |
184 | 213 | #define ELF_DATA ELFDATA2MSB |
185 | 214 | #else |
... | ... | @@ -222,9 +251,18 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * |
222 | 251 | { |
223 | 252 | target_ulong pos = infop->start_stack; |
224 | 253 | target_ulong tmp; |
254 | +#ifdef TARGET_PPC64 | |
255 | + target_ulong entry, toc; | |
256 | +#endif | |
225 | 257 | |
226 | 258 | _regs->msr = 1 << MSR_PR; /* Set user mode */ |
227 | 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 | 266 | _regs->nip = infop->entry; |
229 | 267 | /* Note that isn't exactly what regular kernel does |
230 | 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 | 955 | unsigned long elf_entry, interp_load_addr = 0; |
918 | 956 | int status; |
919 | 957 | unsigned long start_code, end_code, end_data; |
958 | + unsigned long reloc_func_desc = 0; | |
920 | 959 | unsigned long elf_stack; |
921 | 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 | 1220 | load_bias += error - |
1182 | 1221 | TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); |
1183 | 1222 | load_addr += load_bias; |
1223 | + reloc_func_desc = load_bias; | |
1184 | 1224 | } |
1185 | 1225 | } |
1186 | 1226 | k = elf_ppnt->p_vaddr; |
... | ... | @@ -1213,6 +1253,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, |
1213 | 1253 | elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, |
1214 | 1254 | &interp_load_addr); |
1215 | 1255 | } |
1256 | + reloc_func_desc = interp_load_addr; | |
1216 | 1257 | |
1217 | 1258 | close(interpreter_fd); |
1218 | 1259 | free(elf_interpreter); | ... | ... |
linux-user/main.c
... | ... | @@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env) |
194 | 194 | queue_signal(info.si_signo, &info); |
195 | 195 | break; |
196 | 196 | case EXCP0D_GPF: |
197 | +#ifndef TARGET_X86_64 | |
197 | 198 | if (env->eflags & VM_MASK) { |
198 | 199 | handle_vm86_fault(env); |
199 | - } else { | |
200 | + } else | |
201 | +#endif | |
202 | + { | |
200 | 203 | info.si_signo = SIGSEGV; |
201 | 204 | info.si_errno = 0; |
202 | 205 | info.si_code = TARGET_SI_KERNEL; |
... | ... | @@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env) |
215 | 218 | queue_signal(info.si_signo, &info); |
216 | 219 | break; |
217 | 220 | case EXCP00_DIVZ: |
221 | +#ifndef TARGET_X86_64 | |
218 | 222 | if (env->eflags & VM_MASK) { |
219 | 223 | handle_vm86_trap(env, trapnr); |
220 | - } else { | |
224 | + } else | |
225 | +#endif | |
226 | + { | |
221 | 227 | /* division by zero */ |
222 | 228 | info.si_signo = SIGFPE; |
223 | 229 | info.si_errno = 0; |
... | ... | @@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env) |
228 | 234 | break; |
229 | 235 | case EXCP01_SSTP: |
230 | 236 | case EXCP03_INT3: |
237 | +#ifndef TARGET_X86_64 | |
231 | 238 | if (env->eflags & VM_MASK) { |
232 | 239 | handle_vm86_trap(env, trapnr); |
233 | - } else { | |
240 | + } else | |
241 | +#endif | |
242 | + { | |
234 | 243 | info.si_signo = SIGTRAP; |
235 | 244 | info.si_errno = 0; |
236 | 245 | if (trapnr == EXCP01_SSTP) { |
... | ... | @@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env) |
245 | 254 | break; |
246 | 255 | case EXCP04_INTO: |
247 | 256 | case EXCP05_BOUND: |
257 | +#ifndef TARGET_X86_64 | |
248 | 258 | if (env->eflags & VM_MASK) { |
249 | 259 | handle_vm86_trap(env, trapnr); |
250 | - } else { | |
260 | + } else | |
261 | +#endif | |
262 | + { | |
251 | 263 | info.si_signo = SIGSEGV; |
252 | 264 | info.si_errno = 0; |
253 | 265 | info.si_code = TARGET_SI_KERNEL; |
... | ... | @@ -1807,6 +1819,17 @@ int main(int argc, char **argv) |
1807 | 1819 | env->eflags |= IF_MASK; |
1808 | 1820 | |
1809 | 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 | 1833 | env->regs[R_EAX] = regs->eax; |
1811 | 1834 | env->regs[R_EBX] = regs->ebx; |
1812 | 1835 | env->regs[R_ECX] = regs->ecx; |
... | ... | @@ -1816,6 +1839,7 @@ int main(int argc, char **argv) |
1816 | 1839 | env->regs[R_EBP] = regs->ebp; |
1817 | 1840 | env->regs[R_ESP] = regs->esp; |
1818 | 1841 | env->eip = regs->eip; |
1842 | +#endif | |
1819 | 1843 | |
1820 | 1844 | /* linux interrupt setup */ |
1821 | 1845 | env->idt.base = h2g(idt_table); |
... | ... | @@ -1903,6 +1927,9 @@ int main(int argc, char **argv) |
1903 | 1927 | if (i != 12 && i != 6 && i != 13) |
1904 | 1928 | env->msr[i] = (regs->msr >> i) & 1; |
1905 | 1929 | } |
1930 | +#if defined(TARGET_PPC64) | |
1931 | + msr_sf = 1; | |
1932 | +#endif | |
1906 | 1933 | env->nip = regs->nip; |
1907 | 1934 | for(i = 0; i < 32; i++) { |
1908 | 1935 | env->gpr[i] = regs->gpr[i]; | ... | ... |
linux-user/qemu.h
... | ... | @@ -68,7 +68,7 @@ typedef struct TaskState { |
68 | 68 | uint32_t heap_limit; |
69 | 69 | int swi_errno; |
70 | 70 | #endif |
71 | -#ifdef TARGET_I386 | |
71 | +#if defined(TARGET_I386) && !defined(TARGET_X86_64) | |
72 | 72 | target_ulong target_v86; |
73 | 73 | struct vm86_saved_state vm86_saved_regs; |
74 | 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 | 690 | err |= __put_user(frame->retcode, &frame->pretcode); |
691 | 691 | /* This is popl %eax ; movl $,%eax ; int $0x80 */ |
692 | 692 | err |= __put_user(0xb858, (short *)(frame->retcode+0)); |
693 | +#if defined(TARGET_X86_64) | |
694 | +#warning "Fix this !" | |
695 | +#else | |
693 | 696 | err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); |
697 | +#endif | |
694 | 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 | 2052 | host_to_target_sigset_internal(&target_old_set, &old_set); |
2049 | 2053 | |
2050 | 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 | 2057 | CPUX86State *env = cpu_env; |
2054 | 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 | 3250 | case TARGET_NR_modify_ldt: |
3251 | 3251 | ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); |
3252 | 3252 | break; |
3253 | +#if !defined(TARGET_X86_64) | |
3253 | 3254 | case TARGET_NR_vm86old: |
3254 | 3255 | goto unimplemented; |
3255 | 3256 | case TARGET_NR_vm86: |
3256 | 3257 | ret = do_vm86(cpu_env, arg1, arg2); |
3257 | 3258 | break; |
3258 | 3259 | #endif |
3260 | +#endif | |
3259 | 3261 | case TARGET_NR_adjtimex: |
3260 | 3262 | goto unimplemented; |
3261 | 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 | 3277 | case TARGET_NR_fchdir: |
3276 | 3278 | ret = get_errno(fchdir(arg1)); |
3277 | 3279 | break; |
3280 | +#ifdef TARGET_NR_bdflush /* not on x86_64 */ | |
3278 | 3281 | case TARGET_NR_bdflush: |
3279 | 3282 | goto unimplemented; |
3283 | +#endif | |
3280 | 3284 | #ifdef TARGET_NR_sysfs |
3281 | 3285 | case TARGET_NR_sysfs: |
3282 | 3286 | goto unimplemented; | ... | ... |