diff -r 2e522b843a21 xen/arch/x86/boot/wakeup.S --- a/xen/arch/x86/boot/wakeup.S Wed Jun 03 18:27:05 2009 +0100 +++ b/xen/arch/x86/boot/wakeup.S Fri Jun 05 08:32:21 2009 +0200 @@ -4,6 +4,7 @@ .align 16 ENTRY(wakeup_start) + nop cli cld @@ -105,11 +106,14 @@ video_mode: .long 0 video_flags: .long 0 .code32 + .align 16 # Now in protect mode, with paging disabled # Add offset for any reference to xen specific symbols wakeup_32: + nop + /* Set up segment registers and initial stack for protected mode */ mov $BOOT_DS, %eax mov %eax, %ds mov %eax, %ss @@ -128,35 +132,55 @@ wakeup_32: mov $X86_CR4_PAE, %ecx mov %ecx, %cr4 - /* Load pagetable base register */ - mov $sym_phys(idle_pg_table),%eax - add bootsym_phys(trampoline_xen_phys_start),%eax - mov %eax,%cr3 - - /* Will cpuid feature change after resume? */ - /* Set up EFER (Extended Feature Enable Register). */ + /* + * First switch to Long Mode. Do not restore the original + * MSR EFER value directly as enabling the NX bit without + * paging will result in a #GPF on AMD CPUs. + */ mov bootsym_phys(cpuid_ext_features),%edi test $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */ - jz .Lskip_eferw + jz .Lskip_efer1 movl $MSR_EFER,%ecx rdmsr #if CONFIG_PAGING_LEVELS == 4 btsl $_EFER_LME,%eax /* Long Mode */ - btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */ + wrmsr #endif - btl $20,%edi /* No Execute? */ + +.Lskip_efer1: + /* Load pagetable base register */ + movl $sym_phys(idle_pg_table),%eax + addl bootsym_phys(trampoline_xen_phys_start),%eax + movl %eax,%cr3 + + /* Enable paging */ + movl %cr0,%eax + orl $(X86_CR0_PG|X86_CR0_AM|X86_CR0_WP|X86_CR0_NE|X86_CR0_ET|X86_CR0_TS|X86_CR0_MP|X86_CR0_PE),%eax + movl %eax,%cr0 + /* Flush prefetch queue */ + jmp 1f +1: jmp 1f +1: + + /* + * Load the normal system of MSR EFER. This includes + * enabling the SYSCALL extension and NXE (if supported). + */ + testl $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */ + jz .Lskip_efer2 + movl $MSR_EFER, %ecx + rdmsr +#if CONFIG_PAGING_LEVELS == 4 + btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */ +#endif + btl $20,%edi /* No Execute? */ jnc 1f - btsl $_EFER_NX,%eax /* No Execute */ + btsl $_EFER_NX,%eax /* No Execute */ 1: wrmsr -.Lskip_eferw: +.Lskip_efer2: wbinvd - mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */ - mov %eax,%cr0 - jmp 1f -1: - #if defined(__x86_64__) /* Now in compatibility mode. Long-jump to 64-bit mode */ @@ -174,8 +198,9 @@ wakeup_64: mov $(__HYPERVISOR_DS64), %eax mov %eax, %ds - # long jump to return point, with cs reload - rex64 ljmp *ret_point(%rip) + /* long jump to return point, with cs reload */ + movq ret_point(%rip), %rbx + jmp *%rbx .align 8 ret_point: