|
@@ -1840,6 +1840,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
|
|
|
*/
|
|
|
if (var->unusable)
|
|
|
var->db = 0;
|
|
|
+ /* This is symmetric with svm_set_segment() */
|
|
|
var->dpl = to_svm(vcpu)->vmcb->save.cpl;
|
|
|
break;
|
|
|
}
|
|
@@ -1980,18 +1981,14 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
|
|
|
s->base = var->base;
|
|
|
s->limit = var->limit;
|
|
|
s->selector = var->selector;
|
|
|
- if (var->unusable)
|
|
|
- s->attrib = 0;
|
|
|
- else {
|
|
|
- s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
|
|
|
- s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
|
|
|
- s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
|
|
|
- s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
|
|
|
- s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
|
|
|
- s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
|
|
|
- s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
|
|
|
- s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
|
|
|
- }
|
|
|
+ s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
|
|
|
+ s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
|
|
|
+ s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
|
|
|
+ s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT;
|
|
|
+ s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
|
|
|
+ s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
|
|
|
+ s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
|
|
|
+ s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
|
|
|
|
|
|
/*
|
|
|
* This is always accurate, except if SYSRET returned to a segment
|
|
@@ -2000,7 +1997,8 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
|
|
|
* would entail passing the CPL to userspace and back.
|
|
|
*/
|
|
|
if (seg == VCPU_SREG_SS)
|
|
|
- svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
|
|
|
+ /* This is symmetric with svm_get_segment() */
|
|
|
+ svm->vmcb->save.cpl = (var->dpl & 3);
|
|
|
|
|
|
mark_dirty(svm->vmcb, VMCB_SEG);
|
|
|
}
|