x86: fix FS/GS base handling when using the fsgsbase feature

In that case, due to the respective instructions not being privileged,
we can't rely on our in-memory data to always be correct: While the
guest is running, it may change without us knowing about it. Therefore
we need to
- read the correct values from hardware during context switch out
  (save_segments())
- read the correct values from hardware during RDMSR emulation
- update in-memory values during guest mode change
  (toggle_guest_mode())

For completeness/consistency, WRMSR emulation is also being switched
to use wr[fg]sbase().

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-acked-by: George Dunlap <george.dunlap@eu.citrix.com>
This commit is contained in:
Jan Beulich committed 2014-02-06 12:19:06 +01:00
1 parent ff1745d588
commit c42494acb2
4 files changed
+55 -24

No files matched your search

+9
View File
@@ -1251,6 +1251,15 @@ static void save_segments(struct vcpu *v)
regs->fs = read_segment_register(fs);
regs->gs = read_segment_register(gs);
if ( cpu_has_fsgsbase && !is_pv_32bit_vcpu(v) )
{
v->arch.pv_vcpu.fs_base = __rdfsbase();
if ( v->arch.flags & TF_kernel_mode )
v->arch.pv_vcpu.gs_base_kernel = __rdgsbase();
else
v->arch.pv_vcpu.gs_base_user = __rdgsbase();
}
if ( regs->ds )
dirty_segment_mask |= DIRTY_DS;
+7 -10
View File
@@ -2382,15 +2382,13 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case MSR_FS_BASE:
if ( is_pv_32on64_vcpu(v) )
goto fail;
if ( wrmsr_safe(MSR_FS_BASE, msr_content) )
goto fail;
wrfsbase(msr_content);
v->arch.pv_vcpu.fs_base = msr_content;
break;
case MSR_GS_BASE:
if ( is_pv_32on64_vcpu(v) )
goto fail;
if ( wrmsr_safe(MSR_GS_BASE, msr_content) )
goto fail;
wrgsbase(msr_content);
v->arch.pv_vcpu.gs_base_kernel = msr_content;
break;
case MSR_SHADOW_GS_BASE:
@@ -2535,15 +2533,14 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case MSR_FS_BASE:
if ( is_pv_32on64_vcpu(v) )
goto fail;
regs->eax = v->arch.pv_vcpu.fs_base & 0xFFFFFFFFUL;
regs->edx = v->arch.pv_vcpu.fs_base >> 32;
break;
val = cpu_has_fsgsbase ? __rdfsbase() : v->arch.pv_vcpu.fs_base;
goto rdmsr_writeback;
case MSR_GS_BASE:
if ( is_pv_32on64_vcpu(v) )
goto fail;
regs->eax = v->arch.pv_vcpu.gs_base_kernel & 0xFFFFFFFFUL;
regs->edx = v->arch.pv_vcpu.gs_base_kernel >> 32;
break;
val = cpu_has_fsgsbase ? __rdgsbase()
: v->arch.pv_vcpu.gs_base_kernel;
goto rdmsr_writeback;
case MSR_SHADOW_GS_BASE:
if ( is_pv_32on64_vcpu(v) )
goto fail;
+7
View File
@@ -257,6 +257,13 @@ void toggle_guest_mode(struct vcpu *v)
{
if ( is_pv_32bit_vcpu(v) )
return;
if ( cpu_has_fsgsbase )
{
if ( v->arch.flags & TF_kernel_mode )
v->arch.pv_vcpu.gs_base_kernel = __rdgsbase();
else
v->arch.pv_vcpu.gs_base_user = __rdgsbase();
}
v->arch.flags ^= TF_kernel_mode;
asm volatile ( "swapgs" );
update_cr3(v);
+32 -14
View File
@@ -98,18 +98,40 @@ static inline int wrmsr_safe(unsigned int msr, uint64_t val)
: "=a" (low), "=d" (high) \
: "c" (counter))
static inline unsigned long __rdfsbase(void)
{
unsigned long base;
#ifdef HAVE_GAS_FSGSBASE
asm volatile ( "rdfsbase %0" : "=r" (base) );
#else
asm volatile ( ".byte 0xf3, 0x48, 0x0f, 0xae, 0xc0" : "=a" (base) );
#endif
return base;
}
static inline unsigned long __rdgsbase(void)
{
unsigned long base;
#ifdef HAVE_GAS_FSGSBASE
asm volatile ( "rdgsbase %0" : "=r" (base) );
#else
asm volatile ( ".byte 0xf3, 0x48, 0x0f, 0xae, 0xc8" : "=a" (base) );
#endif
return base;
}
static inline unsigned long rdfsbase(void)
{
unsigned long base;
if ( cpu_has_fsgsbase )
#ifdef HAVE_GAS_FSGSBASE
asm volatile ( "rdfsbase %0" : "=r" (base) );
#else
asm volatile ( ".byte 0xf3, 0x48, 0x0f, 0xae, 0xc0" : "=a" (base) );
#endif
else
rdmsrl(MSR_FS_BASE, base);
return __rdfsbase();
rdmsrl(MSR_FS_BASE, base);
return base;
}
@@ -119,13 +141,9 @@ static inline unsigned long rdgsbase(void)
unsigned long base;
if ( cpu_has_fsgsbase )
#ifdef HAVE_GAS_FSGSBASE
asm volatile ( "rdgsbase %0" : "=r" (base) );
#else
asm volatile ( ".byte 0xf3, 0x48, 0x0f, 0xae, 0xc8" : "=a" (base) );
#endif
else
rdmsrl(MSR_GS_BASE, base);
return __rdgsbase();
rdmsrl(MSR_GS_BASE, base);
return base;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.