aboutsummaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2007-11-14 18:08:56 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2007-11-14 18:08:56 +0000
commitd2fd1af76777687697674e7a49eeceac83907f3e (patch)
tree8756f0eaf173b4e8e5f14992371cbd30e80d153e /linux-user/main.c
parent6b23f777223166d99e88402ddcf3583c3dda9b4c (diff)
x86_64 linux user emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3646 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c73
1 files changed, 65 insertions, 8 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index ac7a174d97..cfe2a0e369 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -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;