]> git.proxmox.com Git - mirror_qemu.git/blobdiff - linux-user/main.c
x86_64 linux user emulation
[mirror_qemu.git] / linux-user / main.c
index ac7a174d97a430f7ad13af1f056983f6e7b5bffe..cfe2a0e369cb2beae47d31ddc404fd970edb3494 100644 (file)
@@ -147,8 +147,11 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
     p[1] = tswapl(e2);
 }
 
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
-                     unsigned long addr, unsigned int sel)
+#if TARGET_X86_64
+uint64_t idt_table[512];
+
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+                       uint64_t addr, unsigned int sel)
 {
     unsigned int e1, e2;
     uint32_t *p;
@@ -157,15 +160,34 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
     p = ptr;
     p[0] = tswapl(e1);
     p[1] = tswapl(e2);
+    p[2] = addr >> 32;
 }
-
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
 uint64_t idt_table[256];
 
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswapl(e1);
+    p[1] = tswapl(e2);
+}
+
 /* only dpl matters as we do only user space emulation */
 static void set_idt(int n, unsigned int dpl)
 {
     set_gate(idt_table + n, 0, dpl, 0, 0);
 }
+#endif
 
 void cpu_loop(CPUX86State *env)
 {
@@ -177,7 +199,7 @@ void cpu_loop(CPUX86State *env)
         trapnr = cpu_x86_exec(env);
         switch(trapnr) {
         case 0x80:
-            /* linux syscall */
+            /* linux syscall from int $0x80 */
             env->regs[R_EAX] = do_syscall(env,
                                           env->regs[R_EAX],
                                           env->regs[R_EBX],
@@ -187,6 +209,20 @@ void cpu_loop(CPUX86State *env)
                                           env->regs[R_EDI],
                                           env->regs[R_EBP]);
             break;
+#ifndef TARGET_ABI32
+        case EXCP_SYSCALL:
+            /* linux syscall from syscall intruction */
+            env->regs[R_EAX] = do_syscall(env,
+                                          env->regs[R_EAX],
+                                          env->regs[R_EDI],
+                                          env->regs[R_ESI],
+                                          env->regs[R_EDX],
+                                          env->regs[10],
+                                          env->regs[8],
+                                          env->regs[9]);
+            env->eip = env->exception_next_eip;
+            break;
+#endif
         case EXCP0B_NOSEG:
         case EXCP0C_STACK:
             info.si_signo = SIGBUS;
@@ -196,6 +232,7 @@ void cpu_loop(CPUX86State *env)
             queue_signal(info.si_signo, &info);
             break;
         case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
 #ifndef TARGET_X86_64
             if (env->eflags & VM_MASK) {
                 handle_vm86_fault(env);
@@ -2075,12 +2112,18 @@ int main(int argc, char **argv)
         env->cr[4] |= CR4_OSFXSR_MASK;
         env->hflags |= HF_OSFXSR_MASK;
     }
+#ifndef TARGET_ABI32
+    /* enable 64 bit mode */
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA;
+    env->hflags |= HF_LMA_MASK;
+#endif
 
     /* flags setup : we activate the IRQs by default as in user mode */
     env->eflags |= IF_MASK;
 
     /* linux register setup */
-#if defined(TARGET_X86_64)
+#ifndef TARGET_ABI32
     env->regs[R_EAX] = regs->rax;
     env->regs[R_EBX] = regs->rbx;
     env->regs[R_ECX] = regs->rcx;
@@ -2131,24 +2174,38 @@ int main(int argc, char **argv)
     {
         uint64_t *gdt_table;
         gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES);
-        env->gdt.base = h2g(gdt_table);
+        env->gdt.base = h2g((unsigned long)gdt_table);
         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+#ifdef TARGET_ABI32
         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+        /* 64 bit code segment */
+        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 DESC_L_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
     }
     cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
     cpu_x86_load_seg(env, R_DS, __USER_DS);
     cpu_x86_load_seg(env, R_ES, __USER_DS);
-    cpu_x86_load_seg(env, R_SS, __USER_DS);
     cpu_x86_load_seg(env, R_FS, __USER_DS);
     cpu_x86_load_seg(env, R_GS, __USER_DS);
-
     /* This hack makes Wine work... */
     env->segs[R_FS].selector = 0;
+#else
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+#endif
 #elif defined(TARGET_ARM)
     {
         int i;