Commit d2fd1af76777687697674e7a49eeceac83907f3e

Authored by bellard
1 parent 6b23f777

x86_64 linux user emulation


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3646 c046a42c-6fe2-441c-8c8c-71466251a162
linux-user/main.c
... ... @@ -147,8 +147,11 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
147 147 p[1] = tswapl(e2);
148 148 }
149 149  
150   -static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
151   - unsigned long addr, unsigned int sel)
  150 +#if TARGET_X86_64
  151 +uint64_t idt_table[512];
  152 +
  153 +static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
  154 + uint64_t addr, unsigned int sel)
152 155 {
153 156 unsigned int e1, e2;
154 157 uint32_t *p;
... ... @@ -157,15 +160,34 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
157 160 p = ptr;
158 161 p[0] = tswapl(e1);
159 162 p[1] = tswapl(e2);
  163 + p[2] = addr >> 32;
160 164 }
161   -
  165 +/* only dpl matters as we do only user space emulation */
  166 +static void set_idt(int n, unsigned int dpl)
  167 +{
  168 + set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
  169 +}
  170 +#else
162 171 uint64_t idt_table[256];
163 172  
  173 +static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
  174 + uint32_t addr, unsigned int sel)
  175 +{
  176 + unsigned int e1, e2;
  177 + uint32_t *p;
  178 + e1 = (addr & 0xffff) | (sel << 16);
  179 + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
  180 + p = ptr;
  181 + p[0] = tswapl(e1);
  182 + p[1] = tswapl(e2);
  183 +}
  184 +
164 185 /* only dpl matters as we do only user space emulation */
165 186 static void set_idt(int n, unsigned int dpl)
166 187 {
167 188 set_gate(idt_table + n, 0, dpl, 0, 0);
168 189 }
  190 +#endif
169 191  
170 192 void cpu_loop(CPUX86State *env)
171 193 {
... ... @@ -177,7 +199,7 @@ void cpu_loop(CPUX86State *env)
177 199 trapnr = cpu_x86_exec(env);
178 200 switch(trapnr) {
179 201 case 0x80:
180   - /* linux syscall */
  202 + /* linux syscall from int $0x80 */
181 203 env->regs[R_EAX] = do_syscall(env,
182 204 env->regs[R_EAX],
183 205 env->regs[R_EBX],
... ... @@ -187,6 +209,20 @@ void cpu_loop(CPUX86State *env)
187 209 env->regs[R_EDI],
188 210 env->regs[R_EBP]);
189 211 break;
  212 +#ifndef TARGET_ABI32
  213 + case EXCP_SYSCALL:
  214 + /* linux syscall from syscall intruction */
  215 + env->regs[R_EAX] = do_syscall(env,
  216 + env->regs[R_EAX],
  217 + env->regs[R_EDI],
  218 + env->regs[R_ESI],
  219 + env->regs[R_EDX],
  220 + env->regs[10],
  221 + env->regs[8],
  222 + env->regs[9]);
  223 + env->eip = env->exception_next_eip;
  224 + break;
  225 +#endif
190 226 case EXCP0B_NOSEG:
191 227 case EXCP0C_STACK:
192 228 info.si_signo = SIGBUS;
... ... @@ -196,6 +232,7 @@ void cpu_loop(CPUX86State *env)
196 232 queue_signal(info.si_signo, &info);
197 233 break;
198 234 case EXCP0D_GPF:
  235 + /* XXX: potential problem if ABI32 */
199 236 #ifndef TARGET_X86_64
200 237 if (env->eflags & VM_MASK) {
201 238 handle_vm86_fault(env);
... ... @@ -2075,12 +2112,18 @@ int main(int argc, char **argv)
2075 2112 env->cr[4] |= CR4_OSFXSR_MASK;
2076 2113 env->hflags |= HF_OSFXSR_MASK;
2077 2114 }
  2115 +#ifndef TARGET_ABI32
  2116 + /* enable 64 bit mode */
  2117 + env->cr[4] |= CR4_PAE_MASK;
  2118 + env->efer |= MSR_EFER_LMA;
  2119 + env->hflags |= HF_LMA_MASK;
  2120 +#endif
2078 2121  
2079 2122 /* flags setup : we activate the IRQs by default as in user mode */
2080 2123 env->eflags |= IF_MASK;
2081 2124  
2082 2125 /* linux register setup */
2083   -#if defined(TARGET_X86_64)
  2126 +#ifndef TARGET_ABI32
2084 2127 env->regs[R_EAX] = regs->rax;
2085 2128 env->regs[R_EBX] = regs->rbx;
2086 2129 env->regs[R_ECX] = regs->rcx;
... ... @@ -2131,24 +2174,38 @@ int main(int argc, char **argv)
2131 2174 {
2132 2175 uint64_t *gdt_table;
2133 2176 gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES);
2134   - env->gdt.base = h2g(gdt_table);
  2177 + env->gdt.base = h2g((unsigned long)gdt_table);
2135 2178 env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
  2179 +#ifdef TARGET_ABI32
2136 2180 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
2137 2181 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
2138 2182 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
  2183 +#else
  2184 + /* 64 bit code segment */
  2185 + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
  2186 + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
  2187 + DESC_L_MASK |
  2188 + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
  2189 +#endif
2139 2190 write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
2140 2191 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
2141 2192 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
2142 2193 }
2143 2194 cpu_x86_load_seg(env, R_CS, __USER_CS);
  2195 + cpu_x86_load_seg(env, R_SS, __USER_DS);
  2196 +#ifdef TARGET_ABI32
2144 2197 cpu_x86_load_seg(env, R_DS, __USER_DS);
2145 2198 cpu_x86_load_seg(env, R_ES, __USER_DS);
2146   - cpu_x86_load_seg(env, R_SS, __USER_DS);
2147 2199 cpu_x86_load_seg(env, R_FS, __USER_DS);
2148 2200 cpu_x86_load_seg(env, R_GS, __USER_DS);
2149   -
2150 2201 /* This hack makes Wine work... */
2151 2202 env->segs[R_FS].selector = 0;
  2203 +#else
  2204 + cpu_x86_load_seg(env, R_DS, 0);
  2205 + cpu_x86_load_seg(env, R_ES, 0);
  2206 + cpu_x86_load_seg(env, R_FS, 0);
  2207 + cpu_x86_load_seg(env, R_GS, 0);
  2208 +#endif
2152 2209 #elif defined(TARGET_ARM)
2153 2210 {
2154 2211 int i;
... ...
linux-user/syscall.c
... ... @@ -2521,6 +2521,41 @@ abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
2521 2521 return 0;
2522 2522 }
2523 2523  
  2524 +#ifndef TARGET_ABI32
  2525 +abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
  2526 +{
  2527 + abi_long ret;
  2528 + abi_ulong val;
  2529 + int idx;
  2530 +
  2531 + switch(code) {
  2532 + case TARGET_ARCH_SET_GS:
  2533 + case TARGET_ARCH_SET_FS:
  2534 + if (code == TARGET_ARCH_SET_GS)
  2535 + idx = R_GS;
  2536 + else
  2537 + idx = R_FS;
  2538 + cpu_x86_load_seg(env, idx, 0);
  2539 + env->segs[idx].base = addr;
  2540 + break;
  2541 + case TARGET_ARCH_GET_GS:
  2542 + case TARGET_ARCH_GET_FS:
  2543 + if (code == TARGET_ARCH_GET_GS)
  2544 + idx = R_GS;
  2545 + else
  2546 + idx = R_FS;
  2547 + val = env->segs[idx].base;
  2548 + if (put_user(val, addr, abi_ulong))
  2549 + return -TARGET_EFAULT;
  2550 + break;
  2551 + default:
  2552 + ret = -TARGET_EINVAL;
  2553 + break;
  2554 + }
  2555 + return 0;
  2556 +}
  2557 +#endif
  2558 +
2524 2559 #endif /* defined(TARGET_I386) */
2525 2560  
2526 2561 /* this stack is the equivalent of the kernel stack associated with a
... ... @@ -2797,7 +2832,7 @@ void syscall_init(void)
2797 2832 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
2798 2833  
2799 2834 /* automatic consistency check if same arch */
2800   -#if defined(__i386__) && defined(TARGET_I386)
  2835 +#if defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)
2801 2836 if (ie->target_cmd != ie->host_cmd) {
2802 2837 fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
2803 2838 ie->target_cmd, ie->host_cmd);
... ... @@ -3861,7 +3896,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
3861 3896 #endif
3862 3897 #ifdef TARGET_NR_mmap
3863 3898 case TARGET_NR_mmap:
3864   -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
  3899 +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
3865 3900 {
3866 3901 abi_ulong *v;
3867 3902 abi_ulong v1, v2, v3, v4, v5, v6;
... ... @@ -4183,42 +4218,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4183 4218  
4184 4219 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
4185 4220 goto efault;
4186   -#if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32))
4187   - target_st->st_dev = tswap32(st.st_dev);
4188   -#else
4189   - target_st->st_dev = tswap16(st.st_dev);
4190   -#endif
4191   - target_st->st_ino = tswapl(st.st_ino);
4192   -#if defined(TARGET_PPC) || defined(TARGET_MIPS)
4193   - target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
4194   - target_st->st_uid = tswap32(st.st_uid);
4195   - target_st->st_gid = tswap32(st.st_gid);
4196   -#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
4197   - target_st->st_mode = tswap32(st.st_mode);
4198   - target_st->st_uid = tswap32(st.st_uid);
4199   - target_st->st_gid = tswap32(st.st_gid);
4200   -#else
4201   - target_st->st_mode = tswap16(st.st_mode);
4202   - target_st->st_uid = tswap16(st.st_uid);
4203   - target_st->st_gid = tswap16(st.st_gid);
4204   -#endif
4205   -#if defined(TARGET_MIPS)
4206   - /* If this is the same on PPC, then just merge w/ the above ifdef */
4207   - target_st->st_nlink = tswapl(st.st_nlink);
4208   - target_st->st_rdev = tswapl(st.st_rdev);
4209   -#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
4210   - target_st->st_nlink = tswap32(st.st_nlink);
4211   - target_st->st_rdev = tswap32(st.st_rdev);
4212   -#else
4213   - target_st->st_nlink = tswap16(st.st_nlink);
4214   - target_st->st_rdev = tswap16(st.st_rdev);
4215   -#endif
4216   - target_st->st_size = tswapl(st.st_size);
4217   - target_st->st_blksize = tswapl(st.st_blksize);
4218   - target_st->st_blocks = tswapl(st.st_blocks);
4219   - target_st->target_st_atime = tswapl(st.st_atime);
4220   - target_st->target_st_mtime = tswapl(st.st_mtime);
4221   - target_st->target_st_ctime = tswapl(st.st_ctime);
  4221 + __put_user(st.st_dev, &target_st->st_dev);
  4222 + __put_user(st.st_ino, &target_st->st_ino);
  4223 + __put_user(st.st_mode, &target_st->st_mode);
  4224 + __put_user(st.st_uid, &target_st->st_uid);
  4225 + __put_user(st.st_gid, &target_st->st_gid);
  4226 + __put_user(st.st_nlink, &target_st->st_nlink);
  4227 + __put_user(st.st_rdev, &target_st->st_rdev);
  4228 + __put_user(st.st_size, &target_st->st_size);
  4229 + __put_user(st.st_blksize, &target_st->st_blksize);
  4230 + __put_user(st.st_blocks, &target_st->st_blocks);
  4231 + __put_user(st.st_atime, &target_st->target_st_atime);
  4232 + __put_user(st.st_mtime, &target_st->target_st_mtime);
  4233 + __put_user(st.st_ctime, &target_st->target_st_ctime);
4222 4234 unlock_user_struct(target_st, arg2, 1);
4223 4235 }
4224 4236 }
... ... @@ -4671,6 +4683,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4671 4683 break;
4672 4684 }
4673 4685 break;
  4686 +#ifdef TARGET_NR_arch_prctl
  4687 + case TARGET_NR_arch_prctl:
  4688 +#if defined(TARGET_I386) && !defined(TARGET_ABI32)
  4689 + ret = do_arch_prctl(cpu_env, arg1, arg2);
  4690 + break;
  4691 +#else
  4692 + goto unimplemented;
  4693 +#endif
  4694 +#endif
4674 4695 #ifdef TARGET_NR_pread
4675 4696 case TARGET_NR_pread:
4676 4697 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
... ...
linux-user/syscall_defs.h
... ... @@ -881,7 +881,7 @@ struct target_winsize {
881 881 #define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */
882 882 #endif
883 883  
884   -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_CRIS)
  884 +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS)
885 885 struct target_stat {
886 886 unsigned short st_dev;
887 887 unsigned short __pad1;
... ... @@ -1474,6 +1474,30 @@ struct target_stat64 {
1474 1474 unsigned long long st_ino;
1475 1475 };
1476 1476  
  1477 +#elif defined(TARGET_I386) && !defined(TARGET_ABI32)
  1478 +struct target_stat {
  1479 + abi_ulong st_dev;
  1480 + abi_ulong st_ino;
  1481 + abi_ulong st_nlink;
  1482 +
  1483 + unsigned int st_mode;
  1484 + unsigned int st_uid;
  1485 + unsigned int st_gid;
  1486 + unsigned int __pad0;
  1487 + abi_ulong st_rdev;
  1488 + abi_long st_size;
  1489 + abi_long st_blksize;
  1490 + abi_long st_blocks; /* Number 512-byte blocks allocated. */
  1491 +
  1492 + abi_ulong target_st_atime;
  1493 + abi_ulong target_st_atime_nsec;
  1494 + abi_ulong target_st_mtime;
  1495 + abi_ulong target_st_mtime_nsec;
  1496 + abi_ulong target_st_ctime;
  1497 + abi_ulong target_st_ctime_nsec;
  1498 +
  1499 + abi_long __unused[3];
  1500 +};
1477 1501 #else
1478 1502 #error unsupported CPU
1479 1503 #endif
... ...
linux-user/x86_64/syscall.h
... ... @@ -91,3 +91,8 @@ struct target_msqid64_ds {
91 91 };
92 92  
93 93 #define UNAME_MACHINE "x86_64"
  94 +
  95 +#define TARGET_ARCH_SET_GS 0x1001
  96 +#define TARGET_ARCH_SET_FS 0x1002
  97 +#define TARGET_ARCH_GET_FS 0x1003
  98 +#define TARGET_ARCH_GET_GS 0x1004
... ...
target-i386/cpu.h
... ... @@ -340,6 +340,9 @@
340 340 #define EXCP11_ALGN 17
341 341 #define EXCP12_MCHK 18
342 342  
  343 +#define EXCP_SYSCALL 0x100 /* only happens in user only emulation
  344 + for syscall instruction */
  345 +
343 346 enum {
344 347 CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
345 348 CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
... ...
target-i386/helper.c
... ... @@ -971,6 +971,14 @@ static void do_interrupt64(int intno, int is_int, int error_code,
971 971 }
972 972 #endif
973 973  
  974 +#if defined(CONFIG_USER_ONLY)
  975 +void helper_syscall(int next_eip_addend)
  976 +{
  977 + env->exception_index = EXCP_SYSCALL;
  978 + env->exception_next_eip = env->eip + next_eip_addend;
  979 + cpu_loop_exit();
  980 +}
  981 +#else
974 982 void helper_syscall(int next_eip_addend)
975 983 {
976 984 int selector;
... ... @@ -1024,6 +1032,7 @@ void helper_syscall(int next_eip_addend)
1024 1032 env->eip = (uint32_t)env->star;
1025 1033 }
1026 1034 }
  1035 +#endif
1027 1036  
1028 1037 void helper_sysret(int dflag)
1029 1038 {
... ... @@ -1143,18 +1152,23 @@ void do_interrupt_user(int intno, int is_int, int error_code,
1143 1152 {
1144 1153 SegmentCache *dt;
1145 1154 target_ulong ptr;
1146   - int dpl, cpl;
  1155 + int dpl, cpl, shift;
1147 1156 uint32_t e2;
1148 1157  
1149 1158 dt = &env->idt;
1150   - ptr = dt->base + (intno * 8);
  1159 + if (env->hflags & HF_LMA_MASK) {
  1160 + shift = 4;
  1161 + } else {
  1162 + shift = 3;
  1163 + }
  1164 + ptr = dt->base + (intno << shift);
1151 1165 e2 = ldl_kernel(ptr + 4);
1152 1166  
1153 1167 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1154 1168 cpl = env->hflags & HF_CPL_MASK;
1155 1169 /* check privledge if software int */
1156 1170 if (is_int && dpl < cpl)
1157   - raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
  1171 + raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1158 1172  
1159 1173 /* Since we emulate only user space, we cannot do more than
1160 1174 exiting the emulation with the suitable exception and error
... ...