# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1212162483 -3600
# Node ID 27351129428a63b0b4ed6e96255af18806b3d9f9
# Parent 89193df0ec1ca2b94bef17152db0c3e9da15f8d6
x86 hvm: Support task switch when task state segments straddle page
boundaries. Also improve error diagnostics from hvm_map().
Fixes multi-processor shutdown for some types of Windows OS.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
xen-unstable changeset: 17758:9c14ba60616d63ff849067dda9958c798f3f838b
xen-unstable date: Fri May 30 16:30:40 2008 +0100
x86 hvm: Fix task-switch operation ordering.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
xen-unstable changeset: 17759:487dc63f95ff433eabb132253c5ff31cc178c00a
xen-unstable date: Fri May 30 16:44:13 2008 +0100
---
xen/arch/x86/hvm/hvm.c | 137 +++++++++++++++++++++++++------------------------
1 files changed, 70 insertions(+), 67 deletions(-)
diff -r 89193df0ec1c -r 27351129428a xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Fri May 30 16:36:05 2008 +0100
+++ b/xen/arch/x86/hvm/hvm.c Fri May 30 16:48:03 2008 +0100
@@ -927,16 +927,17 @@ int hvm_virtual_to_linear_addr(
return 0;
}
-static void *hvm_map(unsigned long va, int size)
+static void *hvm_map_entry(unsigned long va)
{
unsigned long gfn, mfn;
p2m_type_t p2mt;
uint32_t pfec;
- if ( ((va & ~PAGE_MASK) + size) > PAGE_SIZE )
- {
- hvm_inject_exception(TRAP_page_fault, PFEC_write_access,
- (va + PAGE_SIZE - 1) & PAGE_MASK);
+ if ( ((va & ~PAGE_MASK) + 8) > PAGE_SIZE )
+ {
+ gdprintk(XENLOG_ERR, "Descriptor table entry "
+ "straddles page boundary\n");
+ domain_crash(current->domain);
return NULL;
}
@@ -948,7 +949,8 @@ static void *hvm_map(unsigned long va, i
mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
if ( !p2m_is_ram(p2mt) )
{
- hvm_inject_exception(TRAP_page_fault, pfec, va);
+ gdprintk(XENLOG_ERR, "Failed to look up descriptor table entry\n");
+ domain_crash(current->domain);
return NULL;
}
@@ -959,7 +961,7 @@ static void *hvm_map(unsigned long va, i
return (char *)map_domain_page(mfn) + (va & ~PAGE_MASK);
}
-static void hvm_unmap(void *p)
+static void hvm_unmap_entry(void *p)
{
if ( p )
unmap_domain_page(p);
@@ -995,7 +997,7 @@ static int hvm_load_segment_selector(
if ( ((sel & 0xfff8) + 7) > desctab.limit )
goto fail;
- pdesc = hvm_map(desctab.base + (sel & 0xfff8), 8);
+ pdesc = hvm_map_entry(desctab.base + (sel & 0xfff8));
if ( pdesc == NULL )
goto hvm_map_fail;
@@ -1055,7 +1057,7 @@ static int hvm_load_segment_selector(
desc.b |= 0x100;
skip_accessed_flag:
- hvm_unmap(pdesc);
+ hvm_unmap_entry(pdesc);
segr.base = (((desc.b << 0) & 0xff000000u) |
((desc.b << 16) & 0x00ff0000u) |
@@ -1071,7 +1073,7 @@ static int hvm_load_segment_selector(
return 0;
unmap_and_fail:
- hvm_unmap(pdesc);
+ hvm_unmap_entry(pdesc);
fail:
hvm_inject_exception(fault_type, sel & 0xfffc, 0);
hvm_map_fail:
@@ -1087,7 +1089,7 @@ void hvm_task_switch(
struct segment_register gdt, tr, prev_tr, segr;
struct desc_struct *optss_desc = NULL, *nptss_desc = NULL, tss_desc;
unsigned long eflags;
- int exn_raised;
+ int exn_raised, rc;
struct {
u16 back_link,__blh;
u32 esp0;
@@ -1099,7 +1101,7 @@ void hvm_task_switch(
u32 cr3, eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
u16 es, _3, cs, _4, ss, _5, ds, _6, fs, _7, gs, _8, ldt, _9;
u16 trace, iomap;
- } *ptss, tss;
+ } tss = { 0 };
hvm_get_segment_register(v, x86_seg_gdtr, &gdt);
hvm_get_segment_register(v, x86_seg_tr, &prev_tr);
@@ -1112,11 +1114,11 @@ void hvm_task_switch(
goto out;
}
- optss_desc = hvm_map(gdt.base + (prev_tr.sel & 0xfff8), 8);
+ optss_desc = hvm_map_entry(gdt.base + (prev_tr.sel & 0xfff8));
if ( optss_desc == NULL )
goto out;
- nptss_desc = hvm_map(gdt.base + (tss_sel & 0xfff8), 8);
+ nptss_desc = hvm_map_entry(gdt.base + (tss_sel & 0xfff8));
if ( nptss_desc == NULL )
goto out;
@@ -1151,84 +1153,85 @@ void hvm_task_switch(
goto out;
}
- ptss = hvm_map(prev_tr.base, sizeof(tss));
- if ( ptss == NULL )
+ rc = hvm_copy_from_guest_virt(&tss, prev_tr.base, sizeof(tss));
+ if ( rc == HVMCOPY_bad_gva_to_gfn )
goto out;
eflags = regs->eflags;
if ( taskswitch_reason == TSW_iret )
eflags &= ~X86_EFLAGS_NT;
- ptss->cr3 = v->arch.hvm_vcpu.guest_cr[3];
- ptss->eip = regs->eip;
- ptss->eflags = eflags;
- ptss->eax = regs->eax;
- ptss->ecx = regs->ecx;
- ptss->edx = regs->edx;
- ptss->ebx = regs->ebx;
- ptss->esp = regs->esp;
- ptss->ebp = regs->ebp;
- ptss->esi = regs->esi;
- ptss->edi = regs->edi;
+ tss.cr3 = v->arch.hvm_vcpu.guest_cr[3];
+ tss.eip = regs->eip;
+ tss.eflags = eflags;
+ tss.eax = regs->eax;
+ tss.ecx = regs->ecx;
+ tss.edx = regs->edx;
+ tss.ebx = regs->ebx;
+ tss.esp = regs->esp;
+ tss.ebp = regs->ebp;
+ tss.esi = regs->esi;
+ tss.edi = regs->edi;
hvm_get_segment_register(v, x86_seg_es, &segr);
- ptss->es = segr.sel;
+ tss.es = segr.sel;
hvm_get_segment_register(v, x86_seg_cs, &segr);
- ptss->cs = segr.sel;
+ tss.cs = segr.sel;
hvm_get_segment_register(v, x86_seg_ss, &segr);
- ptss->ss = segr.sel;
+ tss.ss = segr.sel;
hvm_get_segment_register(v, x86_seg_ds, &segr);
- ptss->ds = segr.sel;
+ tss.ds = segr.sel;
hvm_get_segment_register(v, x86_seg_fs, &segr);
- ptss->fs = segr.sel;
+ tss.fs = segr.sel;
hvm_get_segment_register(v, x86_seg_gs, &segr);
- ptss->gs = segr.sel;
+ tss.gs = segr.sel;
hvm_get_segment_register(v, x86_seg_ldtr, &segr);
- ptss->ldt = segr.sel;
-
- hvm_unmap(ptss);
-
- ptss = hvm_map(tr.base, sizeof(tss));
- if ( ptss == NULL )
+ tss.ldt = segr.sel;
+
+ rc = hvm_copy_to_guest_virt(prev_tr.base, &tss, sizeof(tss));
+ if ( rc == HVMCOPY_bad_gva_to_gfn )
goto out;
- if ( !hvm_set_cr3(ptss->cr3) )
- {
- hvm_unmap(ptss);
+ rc = hvm_copy_from_guest_virt(&tss, tr.base, sizeof(tss));
+ if ( rc == HVMCOPY_bad_gva_to_gfn )
goto out;
- }
-
- regs->eip = ptss->eip;
- regs->eflags = ptss->eflags | 2;
- regs->eax = ptss->eax;
- regs->ecx = ptss->ecx;
- regs->edx = ptss->edx;
- regs->ebx = ptss->ebx;
- regs->esp = ptss->esp;
- regs->ebp = ptss->ebp;
- regs->esi = ptss->esi;
- regs->edi = ptss->edi;
+
+ if ( !hvm_set_cr3(tss.cr3) )
+ goto out;
+
+ regs->eip = tss.eip;
+ regs->eflags = tss.eflags | 2;
+ regs->eax = tss.eax;
+ regs->ecx = tss.ecx;
+ regs->edx = tss.edx;
+ regs->ebx = tss.ebx;
+ regs->esp = tss.esp;
+ regs->ebp = tss.ebp;
+ regs->esi = tss.esi;
+ regs->edi = tss.edi;
if ( (taskswitch_reason == TSW_call_or_int) )
{
regs->eflags |= X86_EFLAGS_NT;
- ptss->back_link = prev_tr.sel;
+ tss.back_link = prev_tr.sel;
}
exn_raised = 0;
- if ( hvm_load_segment_selector(v, x86_seg_es, ptss->es) ||
- hvm_load_segment_selector(v, x86_seg_cs, ptss->cs) ||
- hvm_load_segment_selector(v, x86_seg_ss, ptss->ss) ||
- hvm_load_segment_selector(v, x86_seg_ds, ptss->ds) ||
- hvm_load_segment_selector(v, x86_seg_fs, ptss->fs) ||
- hvm_load_segment_selector(v, x86_seg_gs, ptss->gs) ||
- hvm_load_segment_selector(v, x86_seg_ldtr, ptss->ldt) )
+ if ( hvm_load_segment_selector(v, x86_seg_es, tss.es) ||
+ hvm_load_segment_selector(v, x86_seg_cs, tss.cs) ||
+ hvm_load_segment_selector(v, x86_seg_ss, tss.ss) ||
+ hvm_load_segment_selector(v, x86_seg_ds, tss.ds) ||
+ hvm_load_segment_selector(v, x86_seg_fs, tss.fs) ||
+ hvm_load_segment_selector(v, x86_seg_gs, tss.gs) ||
+ hvm_load_segment_selector(v, x86_seg_ldtr, tss.ldt) )
exn_raised = 1;
- if ( (ptss->trace & 1) && !exn_raised )
+ rc = hvm_copy_to_guest_virt(tr.base, &tss, sizeof(tss));
+ if ( rc == HVMCOPY_bad_gva_to_gfn )
+ exn_raised = 1;
+
+ if ( (tss.trace & 1) && !exn_raised )
hvm_inject_exception(TRAP_debug, tss_sel & 0xfff8, 0);
-
- hvm_unmap(ptss);
tr.attr.fields.type = 0xb; /* busy 32-bit tss */
hvm_set_segment_register(v, x86_seg_tr, &tr);
@@ -1257,8 +1260,8 @@ void hvm_task_switch(
}
out:
- hvm_unmap(optss_desc);
- hvm_unmap(nptss_desc);
+ hvm_unmap_entry(optss_desc);
+ hvm_unmap_entry(nptss_desc);
}
/*
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|