* [PATCH 1/4] Fix handling of a fault during NMI unblocked due to IRET
@ 2009-03-29 14:12 Gleb Natapov
2009-03-29 14:12 ` [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch() Gleb Natapov
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: Gleb Natapov @ 2009-03-29 14:12 UTC (permalink / raw)
To: avi; +Cc: kvm
Bit 12 is undefined in any of the following cases:
If the VM exit sets the valid bit in the IDT-vectoring information field.
If the VM exit is due to a double fault.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/vmx.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 37ae13d..14e3f48 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3259,36 +3259,41 @@ static void update_tpr_threshold(struct kvm_vcpu *vcpu)
static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
{
u32 exit_intr_info;
- u32 idt_vectoring_info;
+ u32 idt_vectoring_info = vmx->idt_vectoring_info;
bool unblock_nmi;
u8 vector;
int type;
bool idtv_info_valid;
u32 error;
+ idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
if (cpu_has_virtual_nmis()) {
unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
/*
- * SDM 3: 25.7.1.2
+ * SDM 3: 27.7.1.2 (September 2008)
* Re-set bit "block by NMI" before VM entry if vmexit caused by
* a guest IRET fault.
+ * SDM 3: 23.2.2 (September 2008)
+ * Bit 12 is undefined in any of the following cases:
+ * If the VM exit sets the valid bit in the IDT-vectoring
+ * information field.
+ * If the VM exit is due to a double fault.
*/
- if (unblock_nmi && vector != DF_VECTOR)
+ if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi &&
+ vector != DF_VECTOR && !idtv_info_valid)
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
GUEST_INTR_STATE_NMI);
} else if (unlikely(vmx->soft_vnmi_blocked))
vmx->vnmi_blocked_time +=
ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
- idt_vectoring_info = vmx->idt_vectoring_info;
- idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
if (vmx->vcpu.arch.nmi_injected) {
/*
- * SDM 3: 25.7.1.2
+ * SDM 3: 27.7.1.2 (September 2008)
* Clear bit "block by NMI" before VM entry if a NMI delivery
* faulted.
*/
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch()
2009-03-29 14:12 [PATCH 1/4] Fix handling of a fault during NMI unblocked due to IRET Gleb Natapov
@ 2009-03-29 14:12 ` Gleb Natapov
2009-03-30 7:35 ` Avi Kivity
2009-03-29 14:12 ` [PATCH 3/4] Do not zero idt_vectoring_info in vmx_complete_interrupts() Gleb Natapov
2009-03-29 14:12 ` [PATCH 4/4] Fix task switching Gleb Natapov
2 siblings, 1 reply; 18+ messages in thread
From: Gleb Natapov @ 2009-03-29 14:12 UTC (permalink / raw)
To: avi; +Cc: kvm
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/vmx.c | 43 +++++++++++++++++++++++++------------------
1 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 14e3f48..1017544 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3264,7 +3264,6 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
u8 vector;
int type;
bool idtv_info_valid;
- u32 error;
idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
@@ -3289,34 +3288,42 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
vmx->vnmi_blocked_time +=
ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
+ vmx->vcpu.arch.nmi_injected = false;
+ kvm_clear_exception_queue(&vmx->vcpu);
+ kvm_clear_interrupt_queue(&vmx->vcpu);
+
+ if (!idtv_info_valid)
+ return;
+
vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
- if (vmx->vcpu.arch.nmi_injected) {
+
+ switch(type) {
+ case INTR_TYPE_NMI_INTR:
+ vmx->vcpu.arch.nmi_injected = true;
/*
* SDM 3: 27.7.1.2 (September 2008)
- * Clear bit "block by NMI" before VM entry if a NMI delivery
- * faulted.
+ * Clear bit "block by NMI" before VM entry if a NMI
+ * delivery faulted.
*/
- if (idtv_info_valid && type == INTR_TYPE_NMI_INTR)
- vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
- GUEST_INTR_STATE_NMI);
- else
- vmx->vcpu.arch.nmi_injected = false;
- }
- kvm_clear_exception_queue(&vmx->vcpu);
- if (idtv_info_valid && (type == INTR_TYPE_HARD_EXCEPTION ||
- type == INTR_TYPE_SOFT_EXCEPTION)) {
+ vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
+ GUEST_INTR_STATE_NMI);
+ break;
+ case INTR_TYPE_HARD_EXCEPTION:
+ case INTR_TYPE_SOFT_EXCEPTION:
if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
- error = vmcs_read32(IDT_VECTORING_ERROR_CODE);
- kvm_queue_exception_e(&vmx->vcpu, vector, error);
+ u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE);
+ kvm_queue_exception_e(&vmx->vcpu, vector, err);
} else
kvm_queue_exception(&vmx->vcpu, vector);
vmx->idt_vectoring_info = 0;
- }
- kvm_clear_interrupt_queue(&vmx->vcpu);
- if (idtv_info_valid && type == INTR_TYPE_EXT_INTR) {
+ break;
+ case INTR_TYPE_EXT_INTR:
kvm_queue_interrupt(&vmx->vcpu, vector);
vmx->idt_vectoring_info = 0;
+ break;
+ default:
+ break;
}
}
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 3/4] Do not zero idt_vectoring_info in vmx_complete_interrupts().
2009-03-29 14:12 [PATCH 1/4] Fix handling of a fault during NMI unblocked due to IRET Gleb Natapov
2009-03-29 14:12 ` [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch() Gleb Natapov
@ 2009-03-29 14:12 ` Gleb Natapov
2009-03-29 14:12 ` [PATCH 4/4] Fix task switching Gleb Natapov
2 siblings, 0 replies; 18+ messages in thread
From: Gleb Natapov @ 2009-03-29 14:12 UTC (permalink / raw)
To: avi; +Cc: kvm
We will need it later in task_switch().
Code in handle_exception() is dead. is_external_interrupt(vect_info)
will always be false since idt_vectoring_info is zeroed in
vmx_complete_interrupts().
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/kvm/vmx.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1017544..0da7a9e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2613,11 +2613,6 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
"intr info 0x%x\n", __func__, vect_info, intr_info);
- if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
- int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
- kvm_push_irq(vcpu, irq);
- }
-
if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
return 1; /* already handled by vmx_vcpu_run() */
@@ -3316,11 +3311,9 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
kvm_queue_exception_e(&vmx->vcpu, vector, err);
} else
kvm_queue_exception(&vmx->vcpu, vector);
- vmx->idt_vectoring_info = 0;
break;
case INTR_TYPE_EXT_INTR:
kvm_queue_interrupt(&vmx->vcpu, vector);
- vmx->idt_vectoring_info = 0;
break;
default:
break;
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 4/4] Fix task switching.
2009-03-29 14:12 [PATCH 1/4] Fix handling of a fault during NMI unblocked due to IRET Gleb Natapov
2009-03-29 14:12 ` [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch() Gleb Natapov
2009-03-29 14:12 ` [PATCH 3/4] Do not zero idt_vectoring_info in vmx_complete_interrupts() Gleb Natapov
@ 2009-03-29 14:12 ` Gleb Natapov
2009-03-30 7:39 ` Avi Kivity
2009-03-30 16:04 ` Jan Kiszka
2 siblings, 2 replies; 18+ messages in thread
From: Gleb Natapov @ 2009-03-29 14:12 UTC (permalink / raw)
To: avi; +Cc: kvm
The patch fixes two problems with task switching.
1. Back link is written to a wrong TSS.
2. Instruction emulation is not needed if the reason for task switch
is a task gate in IDT and access to it is caused by an external even.
2 is currently solved only for VMX since there is not reliable way to
skip an instruction in SVM. We should emulate it instead.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
---
arch/x86/include/asm/svm.h | 1 +
arch/x86/kvm/svm.c | 25 ++++++++++++++++++-------
arch/x86/kvm/vmx.c | 40 +++++++++++++++++++++++++++++-----------
arch/x86/kvm/x86.c | 40 +++++++++++++++++++++++++++++++---------
4 files changed, 79 insertions(+), 27 deletions(-)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 82ada75..85574b7 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -225,6 +225,7 @@ struct __attribute__ ((__packed__)) vmcb {
#define SVM_EVTINJ_VALID_ERR (1 << 11)
#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1fcbc17..3ffb695 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1823,17 +1823,28 @@ static int task_switch_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
u16 tss_selector;
+ int reason;
+ int int_type = svm->vmcb->control.exit_int_info &
+ SVM_EXITINTINFO_TYPE_MASK;
tss_selector = (u16)svm->vmcb->control.exit_info_1;
+
if (svm->vmcb->control.exit_info_2 &
(1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
- return kvm_task_switch(&svm->vcpu, tss_selector,
- TASK_SWITCH_IRET);
- if (svm->vmcb->control.exit_info_2 &
- (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
- return kvm_task_switch(&svm->vcpu, tss_selector,
- TASK_SWITCH_JMP);
- return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL);
+ reason = TASK_SWITCH_IRET;
+ else if (svm->vmcb->control.exit_info_2 &
+ (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
+ reason = TASK_SWITCH_JMP;
+ else if (svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID)
+ reason = TASK_SWITCH_GATE;
+ else
+ reason = TASK_SWITCH_CALL;
+
+
+ if (reason != TASK_SWITCH_GATE || int_type == SVM_EXITINTINFO_TYPE_SOFT)
+ skip_emulated_instruction(&svm->vcpu);
+
+ return kvm_task_switch(&svm->vcpu, tss_selector, reason);
}
static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 0da7a9e..01db958 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3025,22 +3025,40 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long exit_qualification;
u16 tss_selector;
- int reason;
+ int reason, type, idt_v;
+
+ idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+ type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
reason = (u32)exit_qualification >> 30;
- if (reason == TASK_SWITCH_GATE && vmx->vcpu.arch.nmi_injected &&
- (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) &&
- (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK)
- == INTR_TYPE_NMI_INTR) {
- vcpu->arch.nmi_injected = false;
- if (cpu_has_virtual_nmis())
- vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
- GUEST_INTR_STATE_NMI);
+ if (reason == TASK_SWITCH_GATE && idt_v) {
+ switch (type) {
+ case INTR_TYPE_NMI_INTR:
+ vcpu->arch.nmi_injected = false;
+ if (cpu_has_virtual_nmis())
+ vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
+ GUEST_INTR_STATE_NMI);
+ break;
+ case INTR_TYPE_EXT_INTR:
+ kvm_clear_interrupt_queue(vcpu);
+ break;
+ case INTR_TYPE_HARD_EXCEPTION:
+ case INTR_TYPE_SOFT_EXCEPTION:
+ kvm_clear_exception_queue(vcpu);
+ break;
+ default:
+ break;
+ }
}
tss_selector = exit_qualification;
+ if (!idt_v || (type != INTR_TYPE_HARD_EXCEPTION &&
+ type != INTR_TYPE_EXT_INTR &&
+ type != INTR_TYPE_NMI_INTR))
+ skip_emulated_instruction(vcpu);
+
if (!kvm_task_switch(vcpu, tss_selector, reason))
return 0;
@@ -3292,8 +3310,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
-
- switch(type) {
+
+ switch (type) {
case INTR_TYPE_NMI_INTR:
vmx->vcpu.arch.nmi_injected = true;
/*
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ae4918c..573bb3f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3697,7 +3697,6 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
- tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
}
static int load_state_from_tss32(struct kvm_vcpu *vcpu,
@@ -3794,8 +3793,8 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
}
static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
- u32 old_tss_base,
- struct desc_struct *nseg_desc)
+ u16 old_tss_sel, u32 old_tss_base,
+ struct desc_struct *nseg_desc)
{
struct tss_segment_16 tss_segment_16;
int ret = 0;
@@ -3814,6 +3813,16 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
&tss_segment_16, sizeof tss_segment_16))
goto out;
+ if (old_tss_sel != 0xffff) {
+ tss_segment_16.prev_task_link = old_tss_sel;
+
+ if (kvm_write_guest(vcpu->kvm,
+ get_tss_base_addr(vcpu, nseg_desc),
+ &tss_segment_16.prev_task_link,
+ sizeof tss_segment_16.prev_task_link))
+ goto out;
+ }
+
if (load_state_from_tss16(vcpu, &tss_segment_16))
goto out;
@@ -3823,7 +3832,7 @@ out:
}
static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
- u32 old_tss_base,
+ u16 old_tss_sel, u32 old_tss_base,
struct desc_struct *nseg_desc)
{
struct tss_segment_32 tss_segment_32;
@@ -3843,6 +3852,16 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
&tss_segment_32, sizeof tss_segment_32))
goto out;
+ if (old_tss_sel != 0xffff) {
+ tss_segment_32.prev_task_link = old_tss_sel;
+
+ if (kvm_write_guest(vcpu->kvm,
+ get_tss_base_addr(vcpu, nseg_desc),
+ &tss_segment_32.prev_task_link,
+ sizeof tss_segment_32.prev_task_link))
+ goto out;
+ }
+
if (load_state_from_tss32(vcpu, &tss_segment_32))
goto out;
@@ -3896,14 +3915,17 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
}
- kvm_x86_ops->skip_emulated_instruction(vcpu);
+ /* set back link to prev task only if NT bit is set in eflags
+ note that old_tss_sel is not used afetr this point */
+ if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
+ old_tss_sel = 0xffff;
if (nseg_desc.type & 8)
- ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
- &nseg_desc);
+ ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
+ old_tss_base, &nseg_desc);
else
- ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
- &nseg_desc);
+ ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
+ old_tss_base, &nseg_desc);
if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
u32 eflags = kvm_x86_ops->get_rflags(vcpu);
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch()
2009-03-29 14:12 ` [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch() Gleb Natapov
@ 2009-03-30 7:35 ` Avi Kivity
2009-03-30 16:03 ` Jan Kiszka
0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2009-03-30 7:35 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm
Gleb Natapov wrote:
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
>
This is actually not just a rewrite, but also a bugfix:
> INTR_INFO);
> @@ -3289,34 +3288,42 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
> vmx->vnmi_blocked_time +=
> ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
>
> + vmx->vcpu.arch.nmi_injected = false;
> + kvm_clear_exception_queue(&vmx->vcpu);
> + kvm_clear_interrupt_queue(&vmx->vcpu);
> +
> + if (!idtv_info_valid)
> + return;
> +
> vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
> type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
> - if (vmx->vcpu.arch.nmi_injected) {
> +
> + switch(type) {
> + case INTR_TYPE_NMI_INTR:
> + vmx->vcpu.arch.nmi_injected = true;
> /*
>
The existing code would leave nmi_injected == false if we exit on
NMI_INTR, so we drop an NMI here.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-29 14:12 ` [PATCH 4/4] Fix task switching Gleb Natapov
@ 2009-03-30 7:39 ` Avi Kivity
2009-03-30 13:06 ` Gleb Natapov
2009-03-30 16:04 ` Jan Kiszka
1 sibling, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2009-03-30 7:39 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm
Gleb Natapov wrote:
> The patch fixes two problems with task switching.
> 1. Back link is written to a wrong TSS.
> 2. Instruction emulation is not needed if the reason for task switch
> is a task gate in IDT and access to it is caused by an external even.
>
> 2 is currently solved only for VMX since there is not reliable way to
> skip an instruction in SVM. We should emulate it instead.
>
>
Looks good, but please split into (at least) two patches. Also please
provide a test case so we don't regress again.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 7:39 ` Avi Kivity
@ 2009-03-30 13:06 ` Gleb Natapov
0 siblings, 0 replies; 18+ messages in thread
From: Gleb Natapov @ 2009-03-30 13:06 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm
On Mon, Mar 30, 2009 at 10:39:21AM +0300, Avi Kivity wrote:
> Gleb Natapov wrote:
>> The patch fixes two problems with task switching.
>> 1. Back link is written to a wrong TSS.
>> 2. Instruction emulation is not needed if the reason for task switch
>> is a task gate in IDT and access to it is caused by an external even.
>>
>> 2 is currently solved only for VMX since there is not reliable way to
>> skip an instruction in SVM. We should emulate it instead.
>>
>>
>
> Looks good, but please split into (at least) two patches. Also please
> provide a test case so we don't regress again.
>
This what I am using for testing. After running make you should get
kernel.bin that can be booted from grub. Runs on real HW too. I am
planing to add more test.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
diff --git a/user/test/x86/kvmtest/Makefile b/user/test/x86/kvmtest/Makefile
new file mode 100644
index 0000000..b93935f
--- /dev/null
+++ b/user/test/x86/kvmtest/Makefile
@@ -0,0 +1,33 @@
+CC=gcc
+AS=gcc
+CFLAGS=-m32 -I. -O2 -Wall
+ASFLAGS=-m32 -I.
+OBJS=kernel.o lib.o boot.o memory.o gdt.o idt.o isrs.o tss.o uart.o
+ALLOBJS=$(OBJS) tests/tests.o
+
+PHONY := all
+all: kernel.bin
+ $(MAKE) -C tests
+
+kernel.bin: $(ALLOBJS) kernel.ld
+ ld -T kernel.ld $(ALLOBJS) -o $@
+
+install: kernel.bin
+ cp $< /boot/
+
+tests/tests.o:
+ $(MAKE) -C tests
+
+-include $(OBJS:.o=.d)
+
+# compile and generate dependency info
+%.o: %.c
+ gcc -c $(CFLAGS) $*.c -o $*.o
+ gcc -MM $(CFLAGS) $*.c > $*.d
+
+PHONY += clean
+clean:
+ $(MAKE) -C tests
+ -rm *.o *~ *.d kernel.bin
+
+.PHONY: $(PHONY)
diff --git a/user/test/x86/kvmtest/boot.S b/user/test/x86/kvmtest/boot.S
new file mode 100644
index 0000000..f74015c
--- /dev/null
+++ b/user/test/x86/kvmtest/boot.S
@@ -0,0 +1,357 @@
+/* boot.S - bootstrap the kernel */
+/* Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define ASM 1
+#include <multiboot.h>
+#include <kernel.h>
+
+.text
+
+.globl start, _start
+start:
+_start:
+jmp multiboot_entry
+
+/* Align 32 bits boundary. */
+.align 4
+
+/* Multiboot header. */
+multiboot_header:
+/* magic */
+.long MULTIBOOT_HEADER_MAGIC
+/* flags */
+.long MULTIBOOT_HEADER_FLAGS
+/* checksum */
+.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+#ifndef __ELF__
+ /* header_addr */
+ .long multiboot_header
+ /* load_addr */
+ .long _start
+ /* load_end_addr */
+ .long _edata
+ /* bss_end_addr */
+ .long _end
+ /* entry_addr */
+ .long multiboot_entry
+#endif /* ! __ELF__ */
+
+ multiboot_entry:
+ /* Initialize the stack pointer. */
+ movl $(STACK_START), %esp
+
+ /* Reset EFLAGS. */
+ pushl $0
+ popf
+
+ /* Push the pointer to the Multiboot information structure. */
+ pushl %ebx
+ /* Push the magic value. */
+ pushl %eax
+
+ /* Now enter the C main function... */
+ call cmain
+
+ /* Halt. */
+ pushl $halt_message
+ pushl $0
+ call printk
+
+ loop: hlt
+ jmp loop
+
+.globl isr0
+.globl isr1
+.globl isr2
+.globl isr3
+.globl isr4
+.globl isr5
+.globl isr6
+.globl isr7
+.globl isr8
+.globl isr9
+.globl isr10
+.globl isr11
+.globl isr12
+.globl isr13
+.globl isr14
+.globl isr15
+.globl isr16
+.globl isr17
+.globl isr18
+.globl isr19
+.globl isr20
+.globl isr21
+.globl isr22
+.globl isr23
+.globl isr24
+.globl isr25
+.globl isr26
+.globl isr27
+.globl isr28
+.globl isr29
+.globl isr30
+.globl isr31
+
+/* 0: Divide By Zero Exception */
+isr0:
+ cli
+ pushl $0
+ pushl $0
+ jmp isr_common_stub
+
+/* 1: Debug Exception */
+isr1:
+ cli
+ pushl $0
+ pushl $1
+ jmp isr_common_stub
+
+/* 2: Non Maskable Interrupt Exception */
+isr2:
+ cli
+ pushl $0
+ pushl $2
+ jmp isr_common_stub
+
+/* 3: Int 3 Exception */
+isr3:
+ cli
+ pushl $0
+ pushl $3
+ jmp isr_common_stub
+
+/* 4: INTO Exception */
+isr4:
+ cli
+ pushl $0
+ pushl $4
+ jmp isr_common_stub
+
+/* 5: Out of Bounds Exception */
+isr5:
+ cli
+ pushl $0
+ pushl $5
+ jmp isr_common_stub
+
+/* 6: Invalid Opcode Exception */
+isr6:
+ cli
+ pushl $0
+ pushl $6
+ jmp isr_common_stub
+
+/* 7: Coprocessor Not Available Exception */
+isr7:
+ cli
+ pushl $0
+ pushl $7
+ jmp isr_common_stub
+
+/* 8: Double Fault Exception (With Error Code!) */
+isr8:
+ cli
+ pushl $8
+ jmp isr_common_stub
+
+/* 9: Coprocessor Segment Overrun Exception */
+isr9:
+ cli
+ pushl $0
+ pushl $9
+ jmp isr_common_stub
+
+/* 10: Bad TSS Exception (With Error Code!) */
+isr10:
+ cli
+ pushl $10
+ jmp isr_common_stub
+
+/* 11: Segment Not Present Exception (With Error Code!) */
+isr11:
+ cli
+ pushl $11
+ jmp isr_common_stub
+
+/* 12: Stack Fault Exception (With Error Code!) */
+isr12:
+ cli
+ pushl $12
+ jmp isr_common_stub
+
+/* 13: General Protection Fault Exception (With Error Code!) */
+isr13:
+ cli
+ pushl $13
+ jmp isr_common_stub
+
+/* 14: Page Fault Exception (With Error Code!) */
+isr14:
+ cli
+ pushl $14
+ jmp isr_common_stub
+
+/* 15: Reserved Exception */
+isr15:
+ cli
+ pushl $0
+ pushl $15
+ jmp isr_common_stub
+
+/* 16: Floating Point Exception */
+isr16:
+ cli
+ pushl $0
+ pushl $16
+ jmp isr_common_stub
+
+/* 17: Alignment Check Exception */
+isr17:
+ cli
+ pushl $0
+ pushl $17
+ jmp isr_common_stub
+
+/* 18: Machine Check Exception */
+isr18:
+ cli
+ pushl $0
+ pushl $18
+ jmp isr_common_stub
+
+/* 19: Reserved */
+isr19:
+ cli
+ pushl $0
+ pushl $19
+ jmp isr_common_stub
+
+/* 20: Reserved */
+isr20:
+ cli
+ pushl $0
+ pushl $20
+ jmp isr_common_stub
+
+/* 21: Reserved */
+isr21:
+ cli
+ pushl $0
+ pushl $21
+ jmp isr_common_stub
+
+/* 22: Reserved */
+isr22:
+ cli
+ pushl $0
+ pushl $22
+ jmp isr_common_stub
+
+/* 23: Reserved */
+isr23:
+ cli
+ pushl $0
+ pushl $23
+ jmp isr_common_stub
+
+/* 24: Reserved */
+isr24:
+ cli
+ pushl $0
+ pushl $24
+ jmp isr_common_stub
+
+/* 25: Reserved */
+isr25:
+ cli
+ pushl $0
+ pushl $25
+ jmp isr_common_stub
+
+/* 26: Reserved */
+isr26:
+ cli
+ pushl $0
+ pushl $26
+ jmp isr_common_stub
+
+/* 27: Reserved */
+isr27:
+ cli
+ pushl $0
+ pushl $27
+ jmp isr_common_stub
+
+/* 28: Reserved */
+isr28:
+ cli
+ pushl $0
+ pushl $28
+ jmp isr_common_stub
+
+/* 29: Reserved */
+isr29:
+ cli
+ pushl $0
+ pushl $29
+ jmp isr_common_stub
+
+/* 30: Reserved */
+isr30:
+ cli
+ pushl $0
+ pushl $30
+ jmp isr_common_stub
+
+/* 31: Reserved */
+isr31:
+ cli
+ pushl $0
+ pushl $31
+ jmp isr_common_stub
+
+
+/* This is our common ISR stub. It saves the processor state, sets
+ up for kernel mode segments, calls the C-level fault handler,
+ and finally restores the stack frame. */
+isr_common_stub:
+ pusha
+ pushl %ds
+ pushl %es
+ pushl %fs
+ pushl %gs
+ mov $0x10, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %esp, %eax
+ pushl %eax
+ call fault_handler
+ popl %eax
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ popa
+ add $8, %esp
+ iret
+
+.data
+ halt_message:
+ .asciz "Halted.\n"
diff --git a/user/test/x86/kvmtest/gdt.c b/user/test/x86/kvmtest/gdt.c
new file mode 100644
index 0000000..38e5735
--- /dev/null
+++ b/user/test/x86/kvmtest/gdt.c
@@ -0,0 +1,84 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Defines a GDT entry */
+struct gdt_entry
+{
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t granularity;
+ uint8_t base_high;
+} __attribute__((packed));
+
+struct gdt_ptr
+{
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+/* GDT, with 5 entries:
+ * 0x00 - NULL descriptor
+ * 0x08 - Code segment
+ * 0x10 - Data segment
+ * 0x18 - Primery task
+ * 0x20 - Interrupt task */
+static struct gdt_entry gdt[3 + TSS_COUNT];
+static struct gdt_ptr gp;
+
+static void gdt_flush(const struct gdt_ptr *gp_ptr)
+{
+ asm volatile ("lgdt %0\n\t"
+ "mov $0x10, %%ax\n\t"
+ "mov %%ax, %%ds\n\t"
+ "mov %%ax, %%es\n\t"
+ "mov %%ax, %%fs\n\t"
+ "mov %%ax, %%gs\n\t"
+ "mov %%ax, %%ss\n\t"
+ "jmp $0x08, $.Lflush2\n\t"
+ ".Lflush2: "::"m"(*gp_ptr));
+}
+
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
+{
+ /* Setup the descriptor base address */
+ gdt[num].base_low = (base & 0xFFFF);
+ gdt[num].base_middle = (base >> 16) & 0xFF;
+ gdt[num].base_high = (base >> 24) & 0xFF;
+
+ /* Setup the descriptor limits */
+ gdt[num].limit_low = (limit & 0xFFFF);
+ gdt[num].granularity = ((limit >> 16) & 0x0F);
+
+ /* Finally, set up the granularity and access flags */
+ gdt[num].granularity |= (gran & 0xF0);
+ gdt[num].access = access;
+}
+
+void gdt_install(void)
+{
+ /* Setup the GDT pointer and limit */
+ gp.limit = sizeof(gdt) - 1;
+ gp.base = (uint32_t)&gdt;
+
+ memset(gdt, 0, sizeof(gdt));
+
+ /* Our NULL descriptor */
+ gdt_set_gate(0, 0, 0, 0, 0);
+
+ /* The second entry is our Code Segment. The base address
+ * is 0, the limit is 4GBytes, it uses 4KByte granularity,
+ * uses 32-bit opcodes, and is a Code Segment descriptor.
+ * Please check the table above in the tutorial in order
+ * to see exactly what each value means */
+ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xcf);
+
+ /* The third entry is our Data Segment. It's EXACTLY the
+ * same as our code segment, but the descriptor type in
+ * this entry's access byte says it's a Data Segment */
+ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xcf);
+
+ /* Flush out the old GDT and install the new changes! */
+ gdt_flush(&gp);
+}
diff --git a/user/test/x86/kvmtest/idt.c b/user/test/x86/kvmtest/idt.c
new file mode 100644
index 0000000..f2d9de7
--- /dev/null
+++ b/user/test/x86/kvmtest/idt.c
@@ -0,0 +1,47 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Defines an IDT entry */
+struct idt_entry {
+ uint16_t base_lo;
+ uint16_t sel;
+ uint8_t always0;
+ uint8_t flags;
+ uint16_t base_hi;
+} __attribute__((packed));
+
+struct idt_ptr
+{
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+struct idt_entry idt[256];
+struct idt_ptr idtp;
+
+
+static void idt_load(const struct idt_ptr *idtptr)
+{
+ asm volatile("lidt %0"::"m" (*idtptr));
+}
+
+void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
+{
+ /* The interrupt routine's base address */
+ idt[num].base_lo = (base & 0xFFFF);
+ idt[num].base_hi = (base >> 16) & 0xFFFF;
+
+ idt[num].sel = sel;
+ idt[num].always0 = 0;
+ idt[num].flags = flags;
+}
+
+void idt_install()
+{
+ idtp.limit = sizeof(idt) - 1;
+ idtp.base = (uint32_t)&idt;
+
+ memset(&idt, 0, sizeof(idt));
+
+ idt_load(&idtp);
+}
diff --git a/user/test/x86/kvmtest/isrs.c b/user/test/x86/kvmtest/isrs.c
new file mode 100644
index 0000000..3dcfe59
--- /dev/null
+++ b/user/test/x86/kvmtest/isrs.c
@@ -0,0 +1,112 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* This defines what the stack looks like after an ISR was running */
+struct regs
+{
+ unsigned int gs, fs, es, ds; /* pushed the segs last */
+ unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */
+ unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */
+ unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */
+};
+
+extern void isr0();
+extern void isr1();
+extern void isr2();
+extern void isr3();
+extern void isr4();
+extern void isr5();
+extern void isr6();
+extern void isr7();
+extern void isr8();
+extern void isr9();
+extern void isr10();
+extern void isr11();
+extern void isr12();
+extern void isr13();
+extern void isr14();
+extern void isr15();
+extern void isr16();
+extern void isr17();
+extern void isr18();
+extern void isr19();
+extern void isr20();
+extern void isr21();
+extern void isr22();
+extern void isr23();
+extern void isr24();
+extern void isr25();
+extern void isr26();
+extern void isr27();
+extern void isr28();
+extern void isr29();
+extern void isr30();
+extern void isr31();
+
+void (*isrs[32])() = {isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8,
+ isr9, isr10, isr11, isr12, isr13, isr14, isr15, isr16,
+ isr17, isr18, isr19, isr20, isr21, isr22, isr23, isr24,
+ isr25, isr26, isr27, isr28, isr29, isr30, isr31};
+
+void isrs_install_one(uint8_t isr)
+{
+ idt_set_gate(isr, (uint32_t)isrs[isr], 0x08, 0x8E);
+}
+
+void isrs_install(void)
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ isrs_install_one(i);
+}
+
+char *exception_messages[] =
+{
+ "Division By Zero",
+ "Debug",
+ "Non Maskable Interrupt",
+ "Breakpoint",
+ "Into Detected Overflow",
+ "Out of Bounds",
+ "Invalid Opcode",
+ "No Coprocessor",
+
+ "Double Fault",
+ "Coprocessor Segment Overrun",
+ "Bad TSS",
+ "Segment Not Present",
+ "Stack Fault",
+ "General Protection Fault",
+ "Page Fault",
+ "Unknown Interrupt",
+
+ "Coprocessor Fault",
+ "Alignment Check",
+ "Machine Check",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved"
+};
+
+void fault_handler(struct regs *r)
+{
+ if (r->int_no < 32)
+ {
+ printk(0, exception_messages[r->int_no]);
+ printk(0, "Exception. System Halted!\n");
+ for (;;)
+ asm volatile ("hlt");
+ }
+}
diff --git a/user/test/x86/kvmtest/kernel.c b/user/test/x86/kvmtest/kernel.c
new file mode 100644
index 0000000..1920af7
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.c
@@ -0,0 +1,194 @@
+/* kernel.c - the C part of the kernel */
+/* Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <kernel.h>
+#include <multiboot.h>
+#include <lib.h>
+#include <memory.h>
+
+/* Macros. */
+
+/* Check if the bit BIT in FLAGS is set. */
+#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit)))
+
+/* Forward declarations. */
+void cmain (unsigned long magic, unsigned long addr);
+
+#if 0
+/* Check if MAGIC is valid and print the Multiboot information structure
+ pointed by ADDR. */
+static void print_boot_info(unsigned long magic, unsigned long addr)
+{
+ multiboot_info_t *mbi;
+
+ /* Am I booted by a Multiboot-compliant boot loader? */
+ if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
+ {
+ printk ("Invalid magic number: 0x%x\n", (unsigned) magic);
+ return;
+ }
+
+ /* Set MBI to the address of the Multiboot information structure. */
+ mbi = (multiboot_info_t *) addr;
+
+ /* Print out the flags. */
+ printk ("flags = 0x%x\n", (unsigned) mbi->flags);
+
+ /* Are mem_* valid? */
+ if (CHECK_FLAG (mbi->flags, 0))
+ printk ("mem_lower = %uKB, mem_upper = %uKB\n",
+ (unsigned) mbi->mem_lower, (unsigned) mbi->mem_upper);
+
+ /* Is boot_device valid? */
+ if (CHECK_FLAG (mbi->flags, 1))
+ printk ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
+
+ /* Is the command line passed? */
+ if (CHECK_FLAG (mbi->flags, 2))
+ printk ("cmdline = %s\n", (char *) mbi->cmdline);
+
+ /* Are mods_* valid? */
+ if (CHECK_FLAG (mbi->flags, 3))
+ {
+ module_t *mod;
+ int i;
+
+ printk ("mods_count = %d, mods_addr = 0x%x\n",
+ (int) mbi->mods_count, (int) mbi->mods_addr);
+ for (i = 0, mod = (module_t *) mbi->mods_addr;
+ i < mbi->mods_count;
+ i++, mod++)
+ printk (" mod_start = 0x%x, mod_end = 0x%x, string = %s\n",
+ (unsigned) mod->mod_start,
+ (unsigned) mod->mod_end,
+ (char *) mod->string);
+ }
+
+ /* Bits 4 and 5 are mutually exclusive! */
+ if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5))
+ {
+ printk ("Both bits 4 and 5 are set.\n");
+ return;
+ }
+
+ /* Is the symbol table of a.out valid? */
+ if (CHECK_FLAG (mbi->flags, 4))
+ {
+ aout_symbol_table_t *aout_sym = &(mbi->u.aout_sym);
+
+ printk ("aout_symbol_table: tabsize = 0x%0x, "
+ "strsize = 0x%x, addr = 0x%x\n",
+ (unsigned) aout_sym->tabsize,
+ (unsigned) aout_sym->strsize,
+ (unsigned) aout_sym->addr);
+ }
+
+ /* Is the section header table of ELF valid? */
+ if (CHECK_FLAG (mbi->flags, 5))
+ {
+ elf_section_header_table_t *elf_sec = &(mbi->u.elf_sec);
+
+ printk ("elf_sec: num = %u, size = 0x%x,"
+ " addr = 0x%x, shndx = 0x%x\n",
+ (unsigned) elf_sec->num, (unsigned) elf_sec->size,
+ (unsigned) elf_sec->addr, (unsigned) elf_sec->shndx);
+ }
+
+ /* Are mmap_* valid? */
+ if (CHECK_FLAG (mbi->flags, 6))
+ {
+ memory_map_t *mmap;
+
+ printk ("mmap_addr = 0x%x, mmap_length = 0x%x\n",
+ (unsigned) mbi->mmap_addr, (unsigned) mbi->mmap_length);
+ for (mmap = (memory_map_t *) mbi->mmap_addr;
+ (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
+ mmap = (memory_map_t *) ((unsigned long) mmap
+ + mmap->size + sizeof (mmap->size)))
+ printk (" size = 0x%x, base_addr = 0x%x%x,"
+ " length = 0x%x%x, type = 0x%x\n",
+ (unsigned) mmap->size,
+ (unsigned) mmap->base_addr_high,
+ (unsigned) mmap->base_addr_low,
+ (unsigned) mmap->length_high,
+ (unsigned) mmap->length_low,
+ (unsigned) mmap->type);
+ }
+}
+#endif
+
+uint16_t verbosity;
+
+static void cmd_parse(multiboot_info_t *mbi)
+{
+ char *v;
+
+ if (!CHECK_FLAG (mbi->flags, 2))
+ return;
+
+ v = strstr((char*)mbi->cmdline, "v=");
+
+ if (!v)
+ return;
+
+ verbosity = atoi(v + 2);
+ printk(3, "cmdline = %s\n", (char *) mbi->cmdline);
+}
+
+extern struct test_desc __tests_start[], __tests_end[];
+
+static void run_tests(void)
+{
+ struct test_desc *test;
+
+ for (test = __tests_start; test < __tests_end; test++) {
+ int r;
+ printk(0, "Start test: %s\n", test->name);
+ r = test->fn();
+ if (r < 0) {
+ printk(0, "Critical failure. Exiting.\n");
+ return;
+ } else if (r == TEST_FAIL)
+ printk(0, "Test fails\n");
+ else
+ printk(0, "Test Succeeds\n");
+ }
+}
+
+void cmain(unsigned long magic, unsigned long addr)
+{
+ cmd_parse((multiboot_info_t*)addr);
+
+ gdt_install();
+ tss_install();
+ uart_init();
+
+ kalloc_init(_kernel_end, KALLOC_SIZE);
+
+ /* Clear the screen. */
+ cls ();
+
+ printk(3, "kernel start=0x%x end=0x%x\n", _kernel_start, _kernel_end);
+ printk(3, "kalloc_size=%d\n", KALLOC_SIZE);
+
+ idt_install();
+ isrs_install();
+
+ run_tests();
+/* print_boot_info(magic, addr); */
+}
+
diff --git a/user/test/x86/kvmtest/kernel.h b/user/test/x86/kvmtest/kernel.h
new file mode 100644
index 0000000..a2df4a2
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.h
@@ -0,0 +1,68 @@
+#ifndef _KERNEL_H
+#define _KERNEL_H
+#ifndef ASM
+#include <stdint.h>
+
+
+typedef uint32_t size_t;
+#define NULL ((void*)0)
+
+/* 1M for dynamic memory management */
+#define KALLOC_SIZE (1024*1024 - (_kernel_end - _kernel_start))
+#define TSS_COUNT 4
+#define TSS_GDT_OFFSET 3
+
+extern char _kernel_start[], _kernel_end[];
+
+static inline void outb(int addr, int val)
+{
+ asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline uint8_t inb(int addr)
+{
+ uint8_t val;
+ asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr));
+ return val;
+}
+
+void gdt_install(void);
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access,
+ uint8_t gran);
+void idt_install(void);
+void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags);
+
+void isrs_install(void);
+void isrs_install_one(uint8_t isr);
+
+void tss_install(void);
+void tss_setup(uint8_t gate, uint8_t desc, void (*fn)(void));
+void tss_info(void);
+
+void uart_init(void);
+void serial_outch(char c);
+char serial_inch(void);
+
+#define TEST_FAIL 0
+#define TEST_SUCCEED 1
+#define TEST_FAIL_EXIT -1
+typedef int (*testfn_t)(void);
+
+struct test_desc {
+ char *name;
+ testfn_t fn;
+};
+
+#define define_test(_fn, _name) \
+ static struct test_desc __test_##fn __attribute__((__used__)) \
+ __attribute__((__section__(".tests"))) = {.name = _name, .fn = _fn}
+
+extern uint16_t verbosity;
+
+#endif /* ASM */
+
+/* put stack somewhere in low memory */
+#define STACK_START 0x80000
+#define INT_STACK_START 0x70000
+
+#endif
diff --git a/user/test/x86/kvmtest/kernel.ld b/user/test/x86/kvmtest/kernel.ld
new file mode 100644
index 0000000..4be48e3
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.ld
@@ -0,0 +1,28 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(start)
+SECTIONS
+{
+ . = 0x100000;
+ _kernel_start = .;
+ .text : {
+ *(.text)
+ }
+ .rodata : {
+ *(.rodata)
+ }
+ .data : {
+ *(.data)
+ }
+ .bss : {
+ *(.bss)
+ }
+ __tests_start = .;
+ .tests : {
+ *(.tests)
+ }
+ __tests_end = .;
+ . = ALIGN(4096);
+ _kernel_end = .;
+ /DISCARD/ : { *(.comment) }
+}
\ No newline at end of file
diff --git a/user/test/x86/kvmtest/lib.c b/user/test/x86/kvmtest/lib.c
new file mode 100644
index 0000000..e9a86ca
--- /dev/null
+++ b/user/test/x86/kvmtest/lib.c
@@ -0,0 +1,296 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Some screen stuff. */
+/* The number of columns. */
+#define COLUMNS 80
+/* The number of lines. */
+#define LINES 24
+/* The attribute of an character. */
+#define ATTRIBUTE 7
+/* The video memory address. */
+#define VIDEO 0xB8000
+
+/* Variables. */
+/* Save the X position. */
+static int xpos;
+/* Save the Y position. */
+static int ypos;
+/* Point to the video memory. */
+static volatile unsigned char *video;
+
+/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
+void cls (void)
+{
+ int i;
+
+ video = (unsigned char *) VIDEO;
+
+ for (i = 0; i < COLUMNS * LINES * 2; i++)
+ *(video + i) = 0;
+
+ xpos = 0;
+ ypos = 0;
+}
+
+/* Convert the integer D to a string and save the string in BUF. If
+ BASE is equal to 'd', interpret that D is decimal, and if BASE is
+ equal to 'x', interpret that D is hexadecimal. */
+void itoa (char *buf, int base, int d)
+{
+ char *p = buf;
+ char *p1, *p2;
+ unsigned long ud = d;
+ int divisor = 10;
+
+ /* If %d is specified and D is minus, put `-' in the head. */
+ if (base == 'd' && d < 0)
+ {
+ *p++ = '-';
+ buf++;
+ ud = -d;
+ }
+ else if (base == 'x')
+ divisor = 16;
+
+ /* Divide UD by DIVISOR until UD == 0. */
+ do
+ {
+ int remainder = ud % divisor;
+
+ *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
+ }
+ while (ud /= divisor);
+
+ /* Terminate BUF. */
+ *p = 0;
+
+ /* Reverse BUF. */
+ p1 = buf;
+ p2 = p - 1;
+ while (p1 < p2)
+ {
+ char tmp = *p1;
+ *p1 = *p2;
+ *p2 = tmp;
+ p1++;
+ p2--;
+ }
+}
+
+int isdigit(int c)
+{
+ return c >= '0' && c <='9';
+}
+
+int isupper(int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+int islower(int c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+int atoi_base(const char *buf, int base)
+{
+ int minus,val,digit,base_1;
+ char c;
+
+ base_1 = base - 1;
+
+ if((minus = *buf == '-'))
+ buf++;
+
+ val = 0;
+ while ((c = *buf++)) {
+ if (isdigit(c))
+ digit = c - 48;
+ else if (isupper(c))
+ digit = c - 'A' + 10;
+ else if (islower(c))
+ digit = c - 'a' + 10;
+ else
+ break;
+
+ if (digit < 0 || digit > base_1)
+ break;
+
+ val = base*val + digit;
+ }
+
+ return minus ? -val : val;
+}
+
+/* Put the character C on the screen. */
+static void kputchar (int c)
+{
+#ifdef QEMU
+ outb(0x504, c);
+#endif
+ serial_outch(c);
+
+ if (c == '\n' || c == '\r')
+ {
+newline:
+ xpos = 0;
+ ypos++;
+ if (ypos >= LINES)
+ ypos = 0;
+ return;
+ }
+
+ *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
+ *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
+
+ xpos++;
+ if (xpos >= COLUMNS)
+ goto newline;
+}
+
+/* Format a string and print it on the screen, just like the libc
+ function printf. */
+void printk (uint16_t level, const char *format, ...)
+{
+ char **arg = (char **) &format;
+ int c;
+ char buf[20];
+
+ if (level > verbosity)
+ return;
+
+ arg++;
+
+ while ((c = *format++) != 0)
+ {
+ if (c != '%')
+ kputchar (c);
+ else
+ {
+ char *p;
+
+ c = *format++;
+ switch (c)
+ {
+ case 'd':
+ case 'u':
+ case 'x':
+ itoa (buf, c, *((int *) arg++));
+ p = buf;
+ goto string;
+ break;
+
+ case 's':
+ p = *arg++;
+ if (! p)
+ p = "(null)";
+
+string:
+ while (*p)
+ kputchar (*p++);
+ break;
+
+ default:
+ kputchar (*((int *) arg++));
+ break;
+ }
+ }
+ }
+}
+
+void *memset(void *s, int c, size_t n)
+{
+ char *ss = s;
+ int i;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+
+ return s;
+}
+
+char *strstr(const char *phaystack, const char *pneedle)
+{
+ const unsigned char *haystack, *needle;
+ char b, c;
+
+ haystack = (const unsigned char *) phaystack;
+ needle = (const unsigned char *) pneedle;
+
+ b = *needle;
+ if (b != '\0')
+ {
+ haystack--; /* possible ANSI violation */
+ do
+ {
+ c = *++haystack;
+ if (c == '\0')
+ goto ret0;
+ }
+ while (c != b);
+
+ c = *++needle;
+ if (c == '\0')
+ goto foundneedle;
+ ++needle;
+ goto jin;
+
+ for (;;)
+ {
+ char a;
+ const unsigned char *rhaystack, *rneedle;
+
+ do
+ {
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+ if (a == b)
+ break;
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+ shloop:;
+ }
+ while (a != b);
+
+ jin:
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+
+ if (a != c)
+ goto shloop;
+
+ rhaystack = haystack-- + 1;
+ rneedle = needle;
+ a = *rneedle;
+
+ if (*rhaystack == a)
+ do
+ {
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ if (*rhaystack != a)
+ break;
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ }
+ while (*rhaystack == a);
+
+ needle = rneedle; /* took the register-poor approach */
+
+ if (a == '\0')
+ break;
+ }
+ }
+foundneedle:
+ return (char*) haystack;
+ret0:
+ return 0;
+}
diff --git a/user/test/x86/kvmtest/lib.h b/user/test/x86/kvmtest/lib.h
new file mode 100644
index 0000000..b00849c
--- /dev/null
+++ b/user/test/x86/kvmtest/lib.h
@@ -0,0 +1,13 @@
+#ifndef _LIB_H
+#define _LIB_H
+void cls(void);
+void itoa(char *buf, int base, int d);
+void printk(uint16_t level, const char *format, ...);
+void *memset(void *s, int c, size_t n);
+char *strstr(const char *phaystack, const char *pneedle);
+int atoi_base(const char *buf, int base);
+static inline int atoi(const char *buf)
+{
+ return atoi_base(buf, 10);
+}
+#endif
diff --git a/user/test/x86/kvmtest/memory.c b/user/test/x86/kvmtest/memory.c
new file mode 100644
index 0000000..1f0e7f2
--- /dev/null
+++ b/user/test/x86/kvmtest/memory.c
@@ -0,0 +1,100 @@
+#include <kernel.h>
+#include <memory.h>
+
+#define ALIGNMASK 1U
+#define ALIGN(s) (((s) + ALIGNMASK) & ~ALIGNMASK)
+#define POFF ALIGN(sizeof(size_t))
+#define MINSIZ ALIGN(sizeof(struct cell *))
+#define C2P(c) ((char *)(c) + POFF)
+#define P2C(p) ((struct cell *)((char *)(p) - POFF))
+#define ISADJ(c1,c2) ((struct cell *)(C2P(c1) + (c1)->size) == (struct cell *)(c2))
+
+struct cell {
+ size_t size;
+ struct cell *next;
+};
+
+static struct mem_pool {
+ struct cell *tail;
+} *kmem;
+
+void kalloc_init(void *mem, size_t size)
+{
+ kmem->tail = mem;
+ kmem->tail->size = size - POFF;
+ kmem->tail->next = kmem->tail;
+}
+
+void *kalloc(size_t size)
+{
+ struct cell *c1, *c2, *c3;
+
+ size = size < MINSIZ ? MINSIZ : ALIGN(size);
+
+ c1 = kmem->tail;
+ while (c1->next->size < size) {
+ if (c1->next == kmem->tail)
+ return NULL;
+ c1 = c1->next;
+ }
+ c2 = c1->next;
+ if (c2->size > (POFF + size)) { /* split new cell */
+ c3 = (struct cell *)(C2P(c2) + size);
+ c3->size = c2->size - (size + POFF);
+ c3->next = c2->next;
+ c2->size = size;
+ c1->next = c3;
+ } else { /* use the entire cell */
+ c1->next = c2->next;
+ if (c2 == kmem->tail) {
+ kmem->tail = c1;
+ }
+ }
+
+ return C2P(c2);
+}
+
+void kfree(void *ptr)
+{
+ struct cell *c1, *c2, *c3;
+ int j1, j2;
+
+/* splice the cell back into the list */
+ c1 = kmem->tail;
+ c2 = P2C(ptr);
+
+ if (c2 > c1) { /* append to end of list */
+ if (ISADJ(c1,c2)) { /* join with last cell */
+ c1->size += POFF + c2->size;
+ return;
+ }
+ c2->next = c1->next;
+ c1->next = c2;
+ kmem->tail = c2;
+ return;
+ }
+
+ while (c1->next < c2) { /* find insertion point */
+ c1 = c1->next;
+ }
+ c3 = c1->next;
+
+ j1 = ISADJ(c1,c2); /* c1 and c2 need to be joined */
+ j2 = ISADJ(c2,c3); /* c2 and c3 need to be joined */
+
+ if (j1) {
+ if (j2) { /* splice all three cells together */
+ c1->next = c3->next;
+ c1->size += POFF + c3->size;
+ }
+ c1->size += POFF + c2->size;
+ } else {
+ c1->next = c2;
+ if (j2) {
+ c2->next = c3->next;
+ c2->size += POFF + c3->size;
+ } else {
+ c2->next = c3;
+ }
+ }
+}
diff --git a/user/test/x86/kvmtest/memory.h b/user/test/x86/kvmtest/memory.h
new file mode 100644
index 0000000..9a0c984
--- /dev/null
+++ b/user/test/x86/kvmtest/memory.h
@@ -0,0 +1,6 @@
+#ifndef _MEMORY_H
+#define _MEMORY_H
+void kalloc_init(void *mem, size_t size);
+void *kalloc(size_t size);
+void kfree(void *ptr);
+#endif
diff --git a/user/test/x86/kvmtest/multiboot.h b/user/test/x86/kvmtest/multiboot.h
new file mode 100644
index 0000000..85a4605
--- /dev/null
+++ b/user/test/x86/kvmtest/multiboot.h
@@ -0,0 +1,109 @@
+/* multiboot.h - the header for Multiboot */
+/* Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Macros. */
+
+/* The magic number for the Multiboot header. */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* The flags for the Multiboot header. */
+#ifdef __ELF__
+# define MULTIBOOT_HEADER_FLAGS 0x00000003
+#else
+# define MULTIBOOT_HEADER_FLAGS 0x00010003
+#endif
+
+/* The magic number passed by a Multiboot-compliant boot loader. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+#ifndef ASM
+/* Do not include here in boot.S. */
+
+/* Types. */
+
+/* The Multiboot header. */
+typedef struct multiboot_header
+{
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+} multiboot_header_t;
+
+/* The symbol table for a.out. */
+typedef struct aout_symbol_table
+{
+ unsigned long tabsize;
+ unsigned long strsize;
+ unsigned long addr;
+ unsigned long reserved;
+} aout_symbol_table_t;
+
+/* The section header table for ELF. */
+typedef struct elf_section_header_table
+{
+ unsigned long num;
+ unsigned long size;
+ unsigned long addr;
+ unsigned long shndx;
+} elf_section_header_table_t;
+
+/* The Multiboot information. */
+typedef struct multiboot_info
+{
+ unsigned long flags;
+ unsigned long mem_lower;
+ unsigned long mem_upper;
+ unsigned long boot_device;
+ unsigned long cmdline;
+ unsigned long mods_count;
+ unsigned long mods_addr;
+ union
+ {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+ unsigned long mmap_length;
+ unsigned long mmap_addr;
+} multiboot_info_t;
+
+/* The module structure. */
+typedef struct module
+{
+ unsigned long mod_start;
+ unsigned long mod_end;
+ unsigned long string;
+ unsigned long reserved;
+} module_t;
+
+/* The memory map. Be careful that the offset 0 is base_addr_low
+ but no size. */
+typedef struct memory_map
+{
+ unsigned long size;
+ unsigned long base_addr_low;
+ unsigned long base_addr_high;
+ unsigned long length_low;
+ unsigned long length_high;
+ unsigned long type;
+} memory_map_t;
+
+#endif /* ! ASM */
diff --git a/user/test/x86/kvmtest/tests/Makefile b/user/test/x86/kvmtest/tests/Makefile
new file mode 100644
index 0000000..751d352
--- /dev/null
+++ b/user/test/x86/kvmtest/tests/Makefile
@@ -0,0 +1,22 @@
+CC=gcc
+AS=gcc
+CFLAGS=-m32 -I. -I.. -O2 -Wall
+ASFLAGS=-m32 -I. -I..
+OBJS=tss_test.o
+
+PHONY := all
+all: tests.o
+
+tests.o: $(OBJS)
+ ld -m elf_i386 -r $(OBJS) -o $@
+
+-include $(OBJS:.o=.d)
+
+# compile and generate dependency info
+%.o: %.c
+ gcc -c $(CFLAGS) $*.c -o $*.o
+ gcc -MM $(CFLAGS) $*.c > $*.d
+
+PHONY += clean
+clean:
+ -rm *.o *~ *.d
diff --git a/user/test/x86/kvmtest/tests/tss_test.c b/user/test/x86/kvmtest/tests/tss_test.c
new file mode 100644
index 0000000..835dc0b
--- /dev/null
+++ b/user/test/x86/kvmtest/tests/tss_test.c
@@ -0,0 +1,74 @@
+#include <kernel.h>
+#include <lib.h>
+
+
+static void nmi_tss(void)
+{
+start:
+ printk(0, "NMI task is running\n");
+ tss_info();
+ asm volatile ("iret");
+ printk(0, "NMI task restart after iret.\n");
+ goto start;
+}
+
+static int test_divider;
+
+static void de_tss(void)
+{
+start:
+ printk(0, "DE task is running\n");
+ tss_info();
+ test_divider = 10;
+ asm volatile ("iret");
+ goto start;
+}
+
+static void of_tss(void)
+{
+start:
+ printk(0, "OF task is running\n");
+ tss_info();
+ asm volatile ("iret");
+ goto start;
+}
+
+static int tss_test(void)
+{
+ int ret = TEST_SUCCEED, res;
+
+ tss_setup(2, 1, nmi_tss);
+ tss_setup(0, 2, de_tss);
+ tss_setup(4, 3, of_tss);
+
+ printk(0, "Triggering nmi\n");
+ asm volatile ("int $2");
+ printk(0, "Return from nmi 1\n");
+ asm volatile ("int $2");
+ printk(0, "Return from nmi 2\n");
+ printk(0, "Try to devide by 0\n");
+ res = 1500 / test_divider;
+ printk(0, "Result is %d\n", res);
+ if (res != 150) {
+ ret = TEST_FAIL;
+ goto restore_isrs;
+ }
+ printk(0, "Call int 0\n");
+ asm volatile ("int $0");
+ printk(0, "Return from int 0\n");
+ printk(0, "Call into\n");
+ asm volatile ("addb $127, %b0\ninto"::"a"(127));
+ printk(0, "Return from into\n");
+ printk(0, "Calling nmi task by lcall\n");
+ asm volatile("lcall $0x20, $0");
+ printk(0, "Return from call\n");
+
+restore_isrs:
+ isrs_install_one(0);
+ isrs_install_one(2);
+ isrs_install_one(4);
+
+ return ret;
+}
+
+define_test(tss_test, "TSS test");
diff --git a/user/test/x86/kvmtest/tss.c b/user/test/x86/kvmtest/tss.c
new file mode 100644
index 0000000..1d73531
--- /dev/null
+++ b/user/test/x86/kvmtest/tss.c
@@ -0,0 +1,108 @@
+#include <kernel.h>
+#include <lib.h>
+
+struct tss_desc {
+ uint16_t link;
+ uint16_t link_h;
+
+ uint32_t esp0;
+ uint16_t ss0;
+ uint16_t ss0_h;
+
+ uint32_t esp1;
+ uint16_t ss1;
+ uint16_t ss1_h;
+
+ uint32_t esp2;
+ uint16_t ss2;
+ uint16_t ss2_h;
+
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+
+ uint32_t esp;
+ uint32_t ebp;
+
+ uint32_t esi;
+ uint32_t edi;
+
+ uint16_t es;
+ uint16_t es_h;
+
+ uint16_t cs;
+ uint16_t cs_h;
+
+ uint16_t ss;
+ uint16_t ss_h;
+
+ uint16_t ds;
+ uint16_t ds_h;
+
+ uint16_t fs;
+ uint16_t fs_h;
+
+ uint16_t gs;
+ uint16_t gs_h;
+
+ uint16_t ldt;
+ uint16_t ldt_h;
+
+ uint16_t trap;
+ uint16_t iomap;
+} __attribute__ ((packed));
+
+static struct tss_desc tss[TSS_COUNT];
+
+void tss_install(void)
+{
+ uint16_t desc_size = sizeof(struct tss_desc);
+ int i;
+
+ for (i = 0; i < TSS_COUNT; i++) {
+ tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10;
+ tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = INT_STACK_START;
+ tss[i].cs = 0x08;
+ tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss =0x10;
+ tss[i].esp = INT_STACK_START;
+ tss[i].iomap = (uint16_t)desc_size;
+ gdt_set_gate(TSS_GDT_OFFSET + i, (uint32_t)&tss[i],
+ desc_size - 1, 0x89, 0x0f);
+ }
+
+ tss[0].esp0 = tss[0].esp1 = tss[0].esp2 = tss[0].esp = STACK_START;
+
+ asm volatile ( "ltr %%ax" : : "a" ( 0x18 ) );
+}
+
+void tss_setup(uint8_t gate, uint8_t i, void (*fn)(void))
+{
+ if (i >= TSS_COUNT) {
+ printk(0, "Try to setup TSS out if bound %d\n", tss);
+ return;
+ }
+ tss[i].eip = (uint32_t)fn;
+ printk(2, "TSS set gate %d to TSS %x\n", gate,
+ (i + TSS_GDT_OFFSET) << 3);
+ idt_set_gate(gate, 0, (i + TSS_GDT_OFFSET) << 3, 0x85);
+}
+
+void tss_info(void)
+{
+ uint16_t tr, i;
+
+ asm volatile ("str %0":"=r"(tr));
+
+ i = (tr >> 3) - TSS_GDT_OFFSET;
+
+ if (i >= TSS_COUNT)
+ printk(0, "Current TR %x is wrong!\n", tr);
+
+ printk(0, "TR=%x Main TSS back link %x. Current TSS back link %x\n",
+ tr, tss[0]. link, tss[i].link);
+}
diff --git a/user/test/x86/kvmtest/uart.c b/user/test/x86/kvmtest/uart.c
new file mode 100644
index 0000000..d9661d1
--- /dev/null
+++ b/user/test/x86/kvmtest/uart.c
@@ -0,0 +1,43 @@
+#include <kernel.h>
+
+#define PORT1 0x3F8
+#define PORT2 0x2F8
+#define PORT3 0x3E8
+#define PORT4 0x2E8
+
+#define BAUD38400 0x03
+#define BAUD115200 0x01
+#define BAUD57600 0x02
+#define BAUD19200 0x06
+#define BAUD9600 0x0C
+#define BAUD4800 0x18
+#define BAUD2400 0x30
+
+void uart_init(void)
+{
+ outb(PORT1 + 1 , 0); /* Turn off interrupts */
+
+ outb(PORT1 + 3 , 0x80); /* SET DLAB ON */
+ /* Set Baud rate - Divisor Latch Low Byte */
+ outb(PORT1 + 0 , BAUD38400);
+ /* Set Baud rate - Divisor Latch High Byte */
+ outb(PORT1 + 1 , 0x00);
+ outb(PORT1 + 3 , 0x03); /* 8 Bits, No Parity, 1 Stop Bit */
+ outb(PORT1 + 2 , 0xC7); /* FIFO Control Register */
+ outb(PORT1 + 4 , 0x0B); /* Turn on DTR, RTS, and OUT2 */
+}
+
+void serial_outch(char c)
+{
+ outb(PORT1, c);
+}
+
+char serial_inch(void)
+{
+ char c;
+ do {
+ c = inb(PORT1 + 5);
+ if (c & 1)
+ return inb(PORT1);
+ } while(1);
+}
--
Gleb.
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch()
2009-03-30 7:35 ` Avi Kivity
@ 2009-03-30 16:03 ` Jan Kiszka
0 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2009-03-30 16:03 UTC (permalink / raw)
To: Avi Kivity; +Cc: Gleb Natapov, kvm
[-- Attachment #1: Type: text/plain, Size: 1231 bytes --]
Avi Kivity wrote:
> Gleb Natapov wrote:
>> Signed-off-by: Gleb Natapov <gleb@redhat.com>
>>
>
> This is actually not just a rewrite, but also a bugfix:
>
>> INTR_INFO);
>> @@ -3289,34 +3288,42 @@ static void vmx_complete_interrupts(struct
>> vcpu_vmx *vmx)
>> vmx->vnmi_blocked_time +=
>> ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
>>
>> + vmx->vcpu.arch.nmi_injected = false;
>> + kvm_clear_exception_queue(&vmx->vcpu);
>> + kvm_clear_interrupt_queue(&vmx->vcpu);
>> +
>> + if (!idtv_info_valid)
>> + return;
>> +
>> vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
>> type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
>> - if (vmx->vcpu.arch.nmi_injected) {
>> +
>> + switch(type) {
>> + case INTR_TYPE_NMI_INTR:
>> + vmx->vcpu.arch.nmi_injected = true;
>> /*
>>
>
> The existing code would leave nmi_injected == false if we exit on
> NMI_INTR, so we drop an NMI here.
>
I think NMI_INTR and nmi_injected always go together. However, the
rework looks good and more logical to me, too. Will see that I can give
this (more precisely -v2) a try with our scenarios ASAP.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-29 14:12 ` [PATCH 4/4] Fix task switching Gleb Natapov
2009-03-30 7:39 ` Avi Kivity
@ 2009-03-30 16:04 ` Jan Kiszka
2009-03-30 16:21 ` Gleb Natapov
2009-03-31 9:03 ` Kohl, Bernhard (NSN - DE/Munich)
1 sibling, 2 replies; 18+ messages in thread
From: Jan Kiszka @ 2009-03-30 16:04 UTC (permalink / raw)
To: Gleb Natapov
Cc: avi, kvm, Bernhard Kohl, Ostler, Thomas (NSN - DE/Munich), bliitz
[-- Attachment #1: Type: text/plain, Size: 8674 bytes --]
Gleb Natapov wrote:
> The patch fixes two problems with task switching.
> 1. Back link is written to a wrong TSS.
> 2. Instruction emulation is not needed if the reason for task switch
> is a task gate in IDT and access to it is caused by an external even.
>
> 2 is currently solved only for VMX since there is not reliable way to
> skip an instruction in SVM. We should emulate it instead.
Does this series fix all issues Bernhard, Thomas and Julian stumbled over?
Jan
>
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
> ---
>
> arch/x86/include/asm/svm.h | 1 +
> arch/x86/kvm/svm.c | 25 ++++++++++++++++++-------
> arch/x86/kvm/vmx.c | 40 +++++++++++++++++++++++++++++-----------
> arch/x86/kvm/x86.c | 40 +++++++++++++++++++++++++++++++---------
> 4 files changed, 79 insertions(+), 27 deletions(-)
>
> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
> index 82ada75..85574b7 100644
> --- a/arch/x86/include/asm/svm.h
> +++ b/arch/x86/include/asm/svm.h
> @@ -225,6 +225,7 @@ struct __attribute__ ((__packed__)) vmcb {
> #define SVM_EVTINJ_VALID_ERR (1 << 11)
>
> #define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
> +#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
>
> #define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
> #define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 1fcbc17..3ffb695 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -1823,17 +1823,28 @@ static int task_switch_interception(struct vcpu_svm *svm,
> struct kvm_run *kvm_run)
> {
> u16 tss_selector;
> + int reason;
> + int int_type = svm->vmcb->control.exit_int_info &
> + SVM_EXITINTINFO_TYPE_MASK;
>
> tss_selector = (u16)svm->vmcb->control.exit_info_1;
> +
> if (svm->vmcb->control.exit_info_2 &
> (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
> - return kvm_task_switch(&svm->vcpu, tss_selector,
> - TASK_SWITCH_IRET);
> - if (svm->vmcb->control.exit_info_2 &
> - (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
> - return kvm_task_switch(&svm->vcpu, tss_selector,
> - TASK_SWITCH_JMP);
> - return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL);
> + reason = TASK_SWITCH_IRET;
> + else if (svm->vmcb->control.exit_info_2 &
> + (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
> + reason = TASK_SWITCH_JMP;
> + else if (svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID)
> + reason = TASK_SWITCH_GATE;
> + else
> + reason = TASK_SWITCH_CALL;
> +
> +
> + if (reason != TASK_SWITCH_GATE || int_type == SVM_EXITINTINFO_TYPE_SOFT)
> + skip_emulated_instruction(&svm->vcpu);
> +
> + return kvm_task_switch(&svm->vcpu, tss_selector, reason);
> }
>
> static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 0da7a9e..01db958 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -3025,22 +3025,40 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> unsigned long exit_qualification;
> u16 tss_selector;
> - int reason;
> + int reason, type, idt_v;
> +
> + idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
> + type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
>
> exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
>
> reason = (u32)exit_qualification >> 30;
> - if (reason == TASK_SWITCH_GATE && vmx->vcpu.arch.nmi_injected &&
> - (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) &&
> - (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK)
> - == INTR_TYPE_NMI_INTR) {
> - vcpu->arch.nmi_injected = false;
> - if (cpu_has_virtual_nmis())
> - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
> - GUEST_INTR_STATE_NMI);
> + if (reason == TASK_SWITCH_GATE && idt_v) {
> + switch (type) {
> + case INTR_TYPE_NMI_INTR:
> + vcpu->arch.nmi_injected = false;
> + if (cpu_has_virtual_nmis())
> + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
> + GUEST_INTR_STATE_NMI);
> + break;
> + case INTR_TYPE_EXT_INTR:
> + kvm_clear_interrupt_queue(vcpu);
> + break;
> + case INTR_TYPE_HARD_EXCEPTION:
> + case INTR_TYPE_SOFT_EXCEPTION:
> + kvm_clear_exception_queue(vcpu);
> + break;
> + default:
> + break;
> + }
> }
> tss_selector = exit_qualification;
>
> + if (!idt_v || (type != INTR_TYPE_HARD_EXCEPTION &&
> + type != INTR_TYPE_EXT_INTR &&
> + type != INTR_TYPE_NMI_INTR))
> + skip_emulated_instruction(vcpu);
> +
> if (!kvm_task_switch(vcpu, tss_selector, reason))
> return 0;
>
> @@ -3292,8 +3310,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
>
> vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
> type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
> -
> - switch(type) {
> +
> + switch (type) {
> case INTR_TYPE_NMI_INTR:
> vmx->vcpu.arch.nmi_injected = true;
> /*
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index ae4918c..573bb3f 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3697,7 +3697,6 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
> tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
> tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
> tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
> - tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
> }
>
> static int load_state_from_tss32(struct kvm_vcpu *vcpu,
> @@ -3794,8 +3793,8 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
> }
>
> static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
> - u32 old_tss_base,
> - struct desc_struct *nseg_desc)
> + u16 old_tss_sel, u32 old_tss_base,
> + struct desc_struct *nseg_desc)
> {
> struct tss_segment_16 tss_segment_16;
> int ret = 0;
> @@ -3814,6 +3813,16 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
> &tss_segment_16, sizeof tss_segment_16))
> goto out;
>
> + if (old_tss_sel != 0xffff) {
> + tss_segment_16.prev_task_link = old_tss_sel;
> +
> + if (kvm_write_guest(vcpu->kvm,
> + get_tss_base_addr(vcpu, nseg_desc),
> + &tss_segment_16.prev_task_link,
> + sizeof tss_segment_16.prev_task_link))
> + goto out;
> + }
> +
> if (load_state_from_tss16(vcpu, &tss_segment_16))
> goto out;
>
> @@ -3823,7 +3832,7 @@ out:
> }
>
> static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
> - u32 old_tss_base,
> + u16 old_tss_sel, u32 old_tss_base,
> struct desc_struct *nseg_desc)
> {
> struct tss_segment_32 tss_segment_32;
> @@ -3843,6 +3852,16 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
> &tss_segment_32, sizeof tss_segment_32))
> goto out;
>
> + if (old_tss_sel != 0xffff) {
> + tss_segment_32.prev_task_link = old_tss_sel;
> +
> + if (kvm_write_guest(vcpu->kvm,
> + get_tss_base_addr(vcpu, nseg_desc),
> + &tss_segment_32.prev_task_link,
> + sizeof tss_segment_32.prev_task_link))
> + goto out;
> + }
> +
> if (load_state_from_tss32(vcpu, &tss_segment_32))
> goto out;
>
> @@ -3896,14 +3915,17 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
> kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
> }
>
> - kvm_x86_ops->skip_emulated_instruction(vcpu);
> + /* set back link to prev task only if NT bit is set in eflags
> + note that old_tss_sel is not used afetr this point */
> + if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
> + old_tss_sel = 0xffff;
>
> if (nseg_desc.type & 8)
> - ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
> - &nseg_desc);
> + ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
> + old_tss_base, &nseg_desc);
> else
> - ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
> - &nseg_desc);
> + ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
> + old_tss_base, &nseg_desc);
>
> if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
> u32 eflags = kvm_x86_ops->get_rflags(vcpu);
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 16:04 ` Jan Kiszka
@ 2009-03-30 16:21 ` Gleb Natapov
2009-03-30 16:35 ` Jan Kiszka
2009-03-31 9:03 ` Kohl, Bernhard (NSN - DE/Munich)
1 sibling, 1 reply; 18+ messages in thread
From: Gleb Natapov @ 2009-03-30 16:21 UTC (permalink / raw)
To: Jan Kiszka
Cc: avi, kvm, Bernhard Kohl, Ostler, Thomas (NSN - DE/Munich), bliitz
On Mon, Mar 30, 2009 at 06:04:45PM +0200, Jan Kiszka wrote:
> Gleb Natapov wrote:
> > The patch fixes two problems with task switching.
> > 1. Back link is written to a wrong TSS.
> > 2. Instruction emulation is not needed if the reason for task switch
> > is a task gate in IDT and access to it is caused by an external even.
> >
> > 2 is currently solved only for VMX since there is not reliable way to
> > skip an instruction in SVM. We should emulate it instead.
>
> Does this series fix all issues Bernhard, Thomas and Julian stumbled over?
>
Haven't tried. I wrote my own tests for task switching. How can I check it?
--
Gleb.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 16:21 ` Gleb Natapov
@ 2009-03-30 16:35 ` Jan Kiszka
2009-03-30 16:39 ` Gleb Natapov
2009-03-30 16:46 ` Gleb Natapov
0 siblings, 2 replies; 18+ messages in thread
From: Jan Kiszka @ 2009-03-30 16:35 UTC (permalink / raw)
To: Gleb Natapov
Cc: avi, kvm, Bernhard Kohl, Ostler, Thomas (NSN - DE/Munich), bliitz
[-- Attachment #1: Type: text/plain, Size: 1318 bytes --]
Gleb Natapov wrote:
> On Mon, Mar 30, 2009 at 06:04:45PM +0200, Jan Kiszka wrote:
>> Gleb Natapov wrote:
>>> The patch fixes two problems with task switching.
>>> 1. Back link is written to a wrong TSS.
>>> 2. Instruction emulation is not needed if the reason for task switch
>>> is a task gate in IDT and access to it is caused by an external even.
>>>
>>> 2 is currently solved only for VMX since there is not reliable way to
>>> skip an instruction in SVM. We should emulate it instead.
>> Does this series fix all issues Bernhard, Thomas and Julian stumbled over?
>>
> Haven't tried. I wrote my own tests for task switching. How can I check it?
>
There is a test case attached to Julian's sourceforge-reported bug:
https://sourceforge.net/tracker/?func=detail&atid=893831&aid=2681442&group_id=180599
And I guess Thomas or Bernhard will be happy to give it a try, too... :)
There was one issue, the IRQ injection bug [1] which was related to IRQ
tasks IIRC. Thomas and I finally suspected after a private chat that
there is actually a different reason behind it, something like
interrupt.pending should be cleared when the injection took place via an
(emulated) task switch. Any news on this, Thomas?
Jan
[1] http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/29288
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 16:35 ` Jan Kiszka
@ 2009-03-30 16:39 ` Gleb Natapov
2009-03-30 16:46 ` Gleb Natapov
1 sibling, 0 replies; 18+ messages in thread
From: Gleb Natapov @ 2009-03-30 16:39 UTC (permalink / raw)
To: Jan Kiszka
Cc: avi, kvm, Bernhard Kohl, Ostler, Thomas (NSN - DE/Munich), bliitz
On Mon, Mar 30, 2009 at 06:35:05PM +0200, Jan Kiszka wrote:
> Gleb Natapov wrote:
> > On Mon, Mar 30, 2009 at 06:04:45PM +0200, Jan Kiszka wrote:
> >> Gleb Natapov wrote:
> >>> The patch fixes two problems with task switching.
> >>> 1. Back link is written to a wrong TSS.
> >>> 2. Instruction emulation is not needed if the reason for task switch
> >>> is a task gate in IDT and access to it is caused by an external even.
> >>>
> >>> 2 is currently solved only for VMX since there is not reliable way to
> >>> skip an instruction in SVM. We should emulate it instead.
> >> Does this series fix all issues Bernhard, Thomas and Julian stumbled over?
> >>
> > Haven't tried. I wrote my own tests for task switching. How can I check it?
> >
>
> There is a test case attached to Julian's sourceforge-reported bug:
>
> https://sourceforge.net/tracker/?func=detail&atid=893831&aid=2681442&group_id=180599
>
I'll try that.
> And I guess Thomas or Bernhard will be happy to give it a try, too... :)
>
> There was one issue, the IRQ injection bug [1] which was related to IRQ
> tasks IIRC. Thomas and I finally suspected after a private chat that
> there is actually a different reason behind it, something like
> interrupt.pending should be cleared when the injection took place via an
> (emulated) task switch. Any news on this, Thomas?
>
If this is the case then the patch series should fix it.
> Jan
>
> [1] http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/29288
>
--
Gleb.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 16:35 ` Jan Kiszka
2009-03-30 16:39 ` Gleb Natapov
@ 2009-03-30 16:46 ` Gleb Natapov
2009-03-30 23:54 ` Julian Stecklina
1 sibling, 1 reply; 18+ messages in thread
From: Gleb Natapov @ 2009-03-30 16:46 UTC (permalink / raw)
To: Jan Kiszka
Cc: avi, kvm, Bernhard Kohl, Ostler, Thomas (NSN - DE/Munich), bliitz
On Mon, Mar 30, 2009 at 06:35:05PM +0200, Jan Kiszka wrote:
> > Haven't tried. I wrote my own tests for task switching. How can I check it?
> >
>
> There is a test case attached to Julian's sourceforge-reported bug:
>
> https://sourceforge.net/tracker/?func=detail&atid=893831&aid=2681442&group_id=180599
>
Works for me.
--
Gleb.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-30 16:46 ` Gleb Natapov
@ 2009-03-30 23:54 ` Julian Stecklina
0 siblings, 0 replies; 18+ messages in thread
From: Julian Stecklina @ 2009-03-30 23:54 UTC (permalink / raw)
To: kvm-u79uwXL29TY76Z2rM5mHXA
Gleb Natapov <gleb-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> writes:
> On Mon, Mar 30, 2009 at 06:35:05PM +0200, Jan Kiszka wrote:
>> > Haven't tried. I wrote my own tests for task switching. How can I check it?
>> >
>>
>> There is a test case attached to Julian's sourceforge-reported bug:
>>
>> https://sourceforge.net/tracker/?func=detail&atid=893831&aid=2681442&group_id=180599
>>
> Works for me.
Then the patches should be fine (at least for me *g*).
Regards,
--
Julian Stecklina
The day Microsoft makes something that doesn't suck is probably the day
they start making vacuum cleaners - Ernst Jan Plugge
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH 4/4] Fix task switching.
2009-03-30 16:04 ` Jan Kiszka
2009-03-30 16:21 ` Gleb Natapov
@ 2009-03-31 9:03 ` Kohl, Bernhard (NSN - DE/Munich)
2009-03-31 15:21 ` Kohl, Bernhard (NSN - DE/Munich)
1 sibling, 1 reply; 18+ messages in thread
From: Kohl, Bernhard (NSN - DE/Munich) @ 2009-03-31 9:03 UTC (permalink / raw)
To: jan.kiszka, Gleb Natapov
Cc: avi, kvm, Ostler, Thomas (NSN - DE/Munich), bliitz
Jan Kiszka wrote:
>
> Gleb Natapov wrote:
> > The patch fixes two problems with task switching.
> > 1. Back link is written to a wrong TSS.
> > 2. Instruction emulation is not needed if the reason for task switch
> > is a task gate in IDT and access to it is caused by an
> external even.
> >
> > 2 is currently solved only for VMX since there is not
> reliable way to
> > skip an instruction in SVM. We should emulate it instead.
>
> Does this series fix all issues Bernhard, Thomas and Julian
> stumbled over?
>
> Jan
I will try this today. Thanks.
Bernhard
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH 4/4] Fix task switching.
2009-03-31 9:03 ` Kohl, Bernhard (NSN - DE/Munich)
@ 2009-03-31 15:21 ` Kohl, Bernhard (NSN - DE/Munich)
2009-03-31 15:22 ` Gleb Natapov
0 siblings, 1 reply; 18+ messages in thread
From: Kohl, Bernhard (NSN - DE/Munich) @ 2009-03-31 15:21 UTC (permalink / raw)
To: Kohl, Bernhard (NSN - DE/Munich), jan.kiszka, Gleb Natapov
Cc: avi, kvm, Ostler, Thomas (NSN - DE/Munich), bliitz
Bernhard Kohl wrote:
>
> Jan Kiszka wrote:
> >
> > Gleb Natapov wrote:
> > > The patch fixes two problems with task switching.
> > > 1. Back link is written to a wrong TSS.
> > > 2. Instruction emulation is not needed if the reason for
> task switch
> > > is a task gate in IDT and access to it is caused by an
> > external even.
> > >
> > > 2 is currently solved only for VMX since there is not
> > reliable way to
> > > skip an instruction in SVM. We should emulate it instead.
> >
> > Does this series fix all issues Bernhard, Thomas and Julian
> > stumbled over?
> >
> > Jan
>
> I will try this today. Thanks.
>
Yes, it works for us (Thomas + Bernhard).
Bernhard
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-31 15:21 ` Kohl, Bernhard (NSN - DE/Munich)
@ 2009-03-31 15:22 ` Gleb Natapov
2009-04-01 7:21 ` Jan Kiszka
0 siblings, 1 reply; 18+ messages in thread
From: Gleb Natapov @ 2009-03-31 15:22 UTC (permalink / raw)
To: Kohl, Bernhard (NSN - DE/Munich)
Cc: jan.kiszka, avi, kvm, Ostler, Thomas (NSN - DE/Munich), bliitz
On Tue, Mar 31, 2009 at 05:21:16PM +0200, Kohl, Bernhard (NSN - DE/Munich) wrote:
> Bernhard Kohl wrote:
> >
> > Jan Kiszka wrote:
> > >
> > > Gleb Natapov wrote:
> > > > The patch fixes two problems with task switching.
> > > > 1. Back link is written to a wrong TSS.
> > > > 2. Instruction emulation is not needed if the reason for
> > task switch
> > > > is a task gate in IDT and access to it is caused by an
> > > external even.
> > > >
> > > > 2 is currently solved only for VMX since there is not
> > > reliable way to
> > > > skip an instruction in SVM. We should emulate it instead.
> > >
> > > Does this series fix all issues Bernhard, Thomas and Julian
> > > stumbled over?
> > >
> > > Jan
> >
> > I will try this today. Thanks.
> >
> Yes, it works for us (Thomas + Bernhard).
>
Great. Thanks for testing.
--
Gleb.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/4] Fix task switching.
2009-03-31 15:22 ` Gleb Natapov
@ 2009-04-01 7:21 ` Jan Kiszka
0 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2009-04-01 7:21 UTC (permalink / raw)
To: Gleb Natapov
Cc: Kohl, Bernhard (NSN - DE/Munich),
avi, kvm, Ostler, Thomas (NSN - DE/Munich),
bliitz
[-- Attachment #1: Type: text/plain, Size: 920 bytes --]
Gleb Natapov wrote:
> On Tue, Mar 31, 2009 at 05:21:16PM +0200, Kohl, Bernhard (NSN - DE/Munich) wrote:
>> Bernhard Kohl wrote:
>>> Jan Kiszka wrote:
>>>> Gleb Natapov wrote:
>>>>> The patch fixes two problems with task switching.
>>>>> 1. Back link is written to a wrong TSS.
>>>>> 2. Instruction emulation is not needed if the reason for
>>> task switch
>>>>> is a task gate in IDT and access to it is caused by an
>>>> external even.
>>>>> 2 is currently solved only for VMX since there is not
>>>> reliable way to
>>>>> skip an instruction in SVM. We should emulate it instead.
>>>> Does this series fix all issues Bernhard, Thomas and Julian
>>>> stumbled over?
>>>>
>>>> Jan
>>> I will try this today. Thanks.
>>>
>> Yes, it works for us (Thomas + Bernhard).
>>
> Great. Thanks for testing.
>
Same here: No obvious regressions found while running various NMI/IRQ tests.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2009-04-01 7:21 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-29 14:12 [PATCH 1/4] Fix handling of a fault during NMI unblocked due to IRET Gleb Natapov
2009-03-29 14:12 ` [PATCH 2/4] Rewrite twisted maze of if() statements with more straightforward switch() Gleb Natapov
2009-03-30 7:35 ` Avi Kivity
2009-03-30 16:03 ` Jan Kiszka
2009-03-29 14:12 ` [PATCH 3/4] Do not zero idt_vectoring_info in vmx_complete_interrupts() Gleb Natapov
2009-03-29 14:12 ` [PATCH 4/4] Fix task switching Gleb Natapov
2009-03-30 7:39 ` Avi Kivity
2009-03-30 13:06 ` Gleb Natapov
2009-03-30 16:04 ` Jan Kiszka
2009-03-30 16:21 ` Gleb Natapov
2009-03-30 16:35 ` Jan Kiszka
2009-03-30 16:39 ` Gleb Natapov
2009-03-30 16:46 ` Gleb Natapov
2009-03-30 23:54 ` Julian Stecklina
2009-03-31 9:03 ` Kohl, Bernhard (NSN - DE/Munich)
2009-03-31 15:21 ` Kohl, Bernhard (NSN - DE/Munich)
2009-03-31 15:22 ` Gleb Natapov
2009-04-01 7:21 ` Jan Kiszka
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).