[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] x86/vmx: Fold VMCS logic in vmx_{get,set}_segment_register()
Xen's segment enumeration almost matches the VMCS encoding order, while the VMCS encoding order has the system segments immediately following the user segments for all relevant attributes. Use a sneaky xor to hide the difference in encoding order to fold the switch statements, dropping 10 __vmread() and 10 __vmwrite() calls. Bloat-o-meter reports: add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-433 (-433) Function old new delta vmx_set_segment_register 804 593 -211 vmx_get_segment_register 778 556 -222 showing that these wrappers aren't trivial. In addition, 20 BUGs worth of metadata are dropped. No functional change. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx> CC: Wei Liu <wl@xxxxxxx> CC: Jun Nakajima <jun.nakajima@xxxxxxxxx> CC: Kevin Tian <kevin.tian@xxxxxxxxx> We could make x86_seg_* match the VMCS encoding order if we're willing to make v->arch.hvm.vmx.vm86_saved_seg[] one entry longer, but I don't think the added complexity to the vmx_realmode logic is worth it. --- xen/arch/x86/hvm/vmx/vmx.c | 77 ++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index c44cf8f5d425..9765cfd90a0a 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -986,6 +986,7 @@ static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, struct segment_register *reg) { unsigned long attr = 0, sel = 0, limit; + unsigned int tmp_seg; /* * We may get here in the context of dump_execstate(), which may have @@ -1009,34 +1010,34 @@ static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, return; } - switch ( seg ) + /* + * Xen's x86_seg_* enumeration *almost* matches the VMCS encoding order. + * + * tr and ldtr are reversed, and other areas of code rely on this, so we + * can't just re-enumerate. + */ + BUILD_BUG_ON(x86_seg_tr != 6); + BUILD_BUG_ON(x86_seg_ldtr != 7); + BUILD_BUG_ON(x86_seg_gdtr != 8); + BUILD_BUG_ON(x86_seg_idtr != 9); + switch ( tmp_seg = seg ) { - case x86_seg_es ... x86_seg_gs: - __vmread(GUEST_SEG_SELECTOR(seg), &sel); - __vmread(GUEST_SEG_LIMIT(seg), &limit); - __vmread(GUEST_SEG_BASE(seg), ®->base); - __vmread(GUEST_SEG_AR_BYTES(seg), &attr); - break; case x86_seg_tr: - __vmread(GUEST_TR_SELECTOR, &sel); - __vmread(GUEST_TR_LIMIT, &limit); - __vmread(GUEST_TR_BASE, ®->base); - __vmread(GUEST_TR_AR_BYTES, &attr); - break; + case x86_seg_ldtr: + tmp_seg ^= 1; /* Flip tr and ldtr so GUEST_SEG_*() works. */ + fallthrough; + + case x86_seg_es ... x86_seg_gs: + __vmread(GUEST_SEG_SELECTOR(tmp_seg), &sel); + __vmread(GUEST_SEG_AR_BYTES(tmp_seg), &attr); + fallthrough; + case x86_seg_gdtr: - __vmread(GUEST_GDTR_LIMIT, &limit); - __vmread(GUEST_GDTR_BASE, ®->base); - break; case x86_seg_idtr: - __vmread(GUEST_IDTR_LIMIT, &limit); - __vmread(GUEST_IDTR_BASE, ®->base); - break; - case x86_seg_ldtr: - __vmread(GUEST_LDTR_SELECTOR, &sel); - __vmread(GUEST_LDTR_LIMIT, &limit); - __vmread(GUEST_LDTR_BASE, ®->base); - __vmread(GUEST_LDTR_AR_BYTES, &attr); + __vmread(GUEST_SEG_LIMIT(tmp_seg), &limit); + __vmread(GUEST_SEG_BASE(tmp_seg), ®->base); break; + default: BUG(); return; @@ -1150,32 +1151,22 @@ static void vmx_set_segment_register(struct vcpu *v, enum x86_segment seg, switch ( seg ) { + case x86_seg_tr: + case x86_seg_ldtr: + seg ^= 1; /* Flip tr and ldtr so GUEST_SEG_*() works. */ + fallthrough; + case x86_seg_es ... x86_seg_gs: __vmwrite(GUEST_SEG_SELECTOR(seg), sel); - __vmwrite(GUEST_SEG_LIMIT(seg), limit); - __vmwrite(GUEST_SEG_BASE(seg), base); __vmwrite(GUEST_SEG_AR_BYTES(seg), attr); - break; - case x86_seg_tr: - __vmwrite(GUEST_TR_SELECTOR, sel); - __vmwrite(GUEST_TR_LIMIT, limit); - __vmwrite(GUEST_TR_BASE, base); - __vmwrite(GUEST_TR_AR_BYTES, attr); - break; + fallthrough; + case x86_seg_gdtr: - __vmwrite(GUEST_GDTR_LIMIT, limit); - __vmwrite(GUEST_GDTR_BASE, base); - break; case x86_seg_idtr: - __vmwrite(GUEST_IDTR_LIMIT, limit); - __vmwrite(GUEST_IDTR_BASE, base); - break; - case x86_seg_ldtr: - __vmwrite(GUEST_LDTR_SELECTOR, sel); - __vmwrite(GUEST_LDTR_LIMIT, limit); - __vmwrite(GUEST_LDTR_BASE, base); - __vmwrite(GUEST_LDTR_AR_BYTES, attr); + __vmwrite(GUEST_SEG_LIMIT(seg), limit); + __vmwrite(GUEST_SEG_BASE(seg), base); break; + default: BUG(); } -- 2.11.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |