diff options
-rw-r--r-- | linux-user/i386/cpu_loop.c | 57 | ||||
-rw-r--r-- | target/i386/cpu.c | 15 | ||||
-rw-r--r-- | target/i386/tcg/translate.c | 6 |
3 files changed, 44 insertions, 34 deletions
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 9eeda551ea..ef2dcb3d76 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -47,7 +47,7 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit, } static uint64_t *idt_table; -#ifdef TARGET_X86_64 + static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, uint64_t addr, unsigned int sel) { @@ -60,8 +60,10 @@ static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, p[2] = tswap32(addr >> 32); p[3] = 0; } + +#ifdef TARGET_X86_64 /* only dpl matters as we do only user space emulation */ -static void set_idt(int n, unsigned int dpl) +static void set_idt(int n, unsigned int dpl, bool is64) { set_gate64(idt_table + n * 2, 0, dpl, 0, 0); } @@ -78,9 +80,13 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl, } /* only dpl matters as we do only user space emulation */ -static void set_idt(int n, unsigned int dpl) +static void set_idt(int n, unsigned int dpl, bool is64) { - set_gate(idt_table + n, 0, dpl, 0, 0); + if (is64) { + set_gate64(idt_table + n * 2, 0, dpl, 0, 0); + } else { + set_gate(idt_table + n, 0, dpl, 0, 0); + } } #endif @@ -325,6 +331,9 @@ static void target_cpu_free(void *obj) void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { CPUState *cpu = env_cpu(env); + bool is64 = (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) != 0; + int i; + OBJECT(cpu)->free = target_cpu_free; env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; env->hflags |= HF_PE_MASK | HF_CPL_MASK; @@ -332,15 +341,18 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) env->cr[4] |= CR4_OSFXSR_MASK; env->hflags |= HF_OSFXSR_MASK; } -#ifndef TARGET_ABI32 + /* enable 64 bit mode if possible */ - if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { + if (is64) { + env->cr[4] |= CR4_PAE_MASK; + env->efer |= MSR_EFER_LMA | MSR_EFER_LME; + env->hflags |= HF_LMA_MASK; + } +#ifndef TARGET_ABI32 + else { fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); exit(EXIT_FAILURE); } - env->cr[4] |= CR4_PAE_MASK; - env->efer |= MSR_EFER_LMA | MSR_EFER_LME; - env->hflags |= HF_LMA_MASK; #endif /* flags setup : we activate the IRQs by default as in user mode */ @@ -379,27 +391,12 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); idt_table = g2h_untagged(env->idt.base); - set_idt(0, 0); - set_idt(1, 0); - set_idt(2, 0); - set_idt(3, 3); - set_idt(4, 3); - set_idt(5, 0); - set_idt(6, 0); - set_idt(7, 0); - set_idt(8, 0); - set_idt(9, 0); - set_idt(10, 0); - set_idt(11, 0); - set_idt(12, 0); - set_idt(13, 0); - set_idt(14, 0); - set_idt(15, 0); - set_idt(16, 0); - set_idt(17, 0); - set_idt(18, 0); - set_idt(19, 0); - set_idt(0x80, 3); + for (i = 0; i < 20; i++) { + set_idt(i, 0, is64); + } + set_idt(3, 3, is64); + set_idt(4, 3, is64); + set_idt(0x80, 3, is64); /* linux segment setup */ { diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a3ddd1b613..b5688cabb4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -666,7 +666,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, * and therefore using the 32-bit ABI; the CPU itself might be 64-bit * but again the difference is only visible in kernel mode. */ -#if defined CONFIG_USER_ONLY +#if defined CONFIG_LINUX_USER +#define CPUID_EXT2_KERNEL_FEATURES (CPUID_EXT2_LM | CPUID_EXT2_FFXSR) +#elif defined CONFIG_USER_ONLY +/* FIXME: Long mode not yet supported for i386 bsd-user */ #define CPUID_EXT2_KERNEL_FEATURES CPUID_EXT2_FFXSR #else #define CPUID_EXT2_KERNEL_FEATURES 0 @@ -5539,7 +5542,15 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, } #ifndef TARGET_X86_64 if (w == FEAT_8000_0001_EDX) { - r &= ~CPUID_EXT2_LM; + /* + * 32-bit TCG can emulate 64-bit compatibility mode. If there is no + * way for userspace to get out of its 32-bit jail, we can leave + * the LM bit set. + */ + uint32_t unavail = tcg_enabled() + ? CPUID_EXT2_LM & ~CPUID_EXT2_KERNEL_FEATURES + : CPUID_EXT2_LM; + r &= ~unavail; } #endif if (migratable_only) { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 28cb3fb7f4..90c7b32f36 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -173,12 +173,14 @@ typedef struct DisasContext { #endif #if !defined(TARGET_X86_64) #define CODE64(S) false -#define LMA(S) false #elif defined(CONFIG_USER_ONLY) #define CODE64(S) true -#define LMA(S) true #else #define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0) +#endif +#if defined(CONFIG_SOFTMMU) && !defined(TARGET_X86_64) +#define LMA(S) false +#else #define LMA(S) (((S)->flags & HF_LMA_MASK) != 0) #endif |