From c671da80d229f26c86ee96edccfb6678fcc1d948 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 23 Mar 2006 15:30:00 +0100 Subject: [PATCH 1/4] Rename generic_page_range as apply_to_page_range, export the symbol to GPL modules. Rename pte_page parameter to pmd_page (following the Linux idiom). apply_to_pte_range() should take the pte spinlock. Signed-off-by: Keir Fraser --- .../arch/i386/mm/ioremap-xen.c | 26 ++++++------ .../drivers/xen/balloon/balloon.c | 6 +-- .../drivers/xen/core/gnttab.c | 22 +++++----- linux-2.6-xen-sparse/drivers/xen/util.c | 8 ++-- linux-2.6-xen-sparse/include/linux/mm.h | 8 ++-- linux-2.6-xen-sparse/mm/memory.c | 42 ++++++++++--------- 6 files changed, 60 insertions(+), 52 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c index a9a32ba8fb..05f3daab98 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c @@ -32,13 +32,13 @@ #endif static int direct_remap_area_pte_fn(pte_t *pte, - struct page *pte_page, + struct page *pmd_page, unsigned long address, void *data) { mmu_update_t **v = (mmu_update_t **)data; - (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pte_page)) << + (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) << PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK); (*v)++; @@ -67,9 +67,9 @@ static int __direct_remap_pfn_range(struct mm_struct *mm, for (i = 0; i < size; i += PAGE_SIZE) { if ((v - u) == (PAGE_SIZE / sizeof(mmu_update_t))) { /* Fill in the PTE pointers. */ - rc = generic_page_range(mm, start_address, - address - start_address, - direct_remap_area_pte_fn, &w); + rc = apply_to_page_range(mm, start_address, + address - start_address, + direct_remap_area_pte_fn, &w); if (rc) goto out; w = u; @@ -93,8 +93,9 @@ static int __direct_remap_pfn_range(struct mm_struct *mm, if (v != u) { /* get the ptep's filled in */ - rc = generic_page_range(mm, start_address, address - start_address, - direct_remap_area_pte_fn, &w); + rc = apply_to_page_range(mm, start_address, + address - start_address, + direct_remap_area_pte_fn, &w); if (rc) goto out; rc = -EFAULT; @@ -142,11 +143,11 @@ int direct_kernel_remap_pfn_range(unsigned long address, EXPORT_SYMBOL(direct_kernel_remap_pfn_range); static int lookup_pte_fn( - pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { uint64_t *ptep = (uint64_t *)data; if (ptep) - *ptep = ((uint64_t)pfn_to_mfn(page_to_pfn(pte_page)) << + *ptep = ((uint64_t)pfn_to_mfn(page_to_pfn(pmd_page)) << PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK); return 0; } @@ -155,13 +156,14 @@ int create_lookup_pte_addr(struct mm_struct *mm, unsigned long address, uint64_t *ptep) { - return generic_page_range(mm, address, PAGE_SIZE, lookup_pte_fn, ptep); + return apply_to_page_range(mm, address, PAGE_SIZE, + lookup_pte_fn, ptep); } EXPORT_SYMBOL(create_lookup_pte_addr); static int noop_fn( - pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { return 0; } @@ -170,7 +172,7 @@ int touch_pte_range(struct mm_struct *mm, unsigned long address, unsigned long size) { - return generic_page_range(mm, address, size, noop_fn, NULL); + return apply_to_page_range(mm, address, size, noop_fn, NULL); } EXPORT_SYMBOL(touch_pte_range); diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c index d8327b0707..6f8039a0c0 100644 --- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c +++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c @@ -517,7 +517,7 @@ void balloon_update_driver_allowance(long delta) } static int dealloc_pte_fn( - pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { unsigned long mfn = pte_mfn(*pte); int ret; @@ -547,8 +547,8 @@ struct page *balloon_alloc_empty_page_range(unsigned long nr_pages) scrub_pages(vstart, 1 << order); balloon_lock(flags); - ret = generic_page_range( - &init_mm, vstart, PAGE_SIZE << order, dealloc_pte_fn, NULL); + ret = apply_to_page_range(&init_mm, vstart, + PAGE_SIZE << order, dealloc_pte_fn, NULL); BUG_ON(ret); current_pages -= 1UL << order; totalram_pages = current_pages; diff --git a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c index 31b57d4dac..1049934008 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c @@ -360,7 +360,7 @@ gnttab_request_free_callback(struct gnttab_free_callback *callback, } #ifndef __ia64__ -static int map_pte_fn(pte_t *pte, struct page *pte_page, +static int map_pte_fn(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { unsigned long **frames = (unsigned long **)data; @@ -370,7 +370,7 @@ static int map_pte_fn(pte_t *pte, struct page *pte_page, return 0; } -static int unmap_pte_fn(pte_t *pte, struct page *pte_page, +static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { @@ -384,6 +384,7 @@ gnttab_resume(void) { gnttab_setup_table_t setup; unsigned long frames[NR_GRANT_FRAMES]; + int rc; #ifndef __ia64__ void *pframes = frames; struct vm_struct *area; @@ -393,8 +394,8 @@ gnttab_resume(void) setup.nr_frames = NR_GRANT_FRAMES; setup.frame_list = frames; - BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1)); - BUG_ON(setup.status != 0); + rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); + BUG_ON(rc || setup.status); #ifndef __ia64__ if (shared == NULL) { @@ -402,9 +403,10 @@ gnttab_resume(void) BUG_ON(area == NULL); shared = area->addr; } - BUG_ON(generic_page_range(&init_mm, (unsigned long)shared, - PAGE_SIZE * NR_GRANT_FRAMES, - map_pte_fn, &pframes)); + rc = apply_to_page_range(&init_mm, (unsigned long)shared, + PAGE_SIZE * NR_GRANT_FRAMES, + map_pte_fn, &pframes); + BUG_ON(rc); #else shared = __va(frames[0] << PAGE_SHIFT); printk("grant table at %p\n", shared); @@ -418,9 +420,9 @@ gnttab_suspend(void) { #ifndef __ia64__ - generic_page_range(&init_mm, (unsigned long)shared, - PAGE_SIZE * NR_GRANT_FRAMES, - unmap_pte_fn, NULL); + apply_to_page_range(&init_mm, (unsigned long)shared, + PAGE_SIZE * NR_GRANT_FRAMES, + unmap_pte_fn, NULL); #endif return 0; diff --git a/linux-2.6-xen-sparse/drivers/xen/util.c b/linux-2.6-xen-sparse/drivers/xen/util.c index 7f76a3903f..d7980f1a1a 100644 --- a/linux-2.6-xen-sparse/drivers/xen/util.c +++ b/linux-2.6-xen-sparse/drivers/xen/util.c @@ -6,9 +6,9 @@ #include #include -static int f(pte_t *pte, struct page *pte_page, unsigned long addr, void *data) +static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) { - /* generic_page_range() does all the hard work. */ + /* apply_to_page_range() does all the hard work. */ return 0; } @@ -24,8 +24,8 @@ struct vm_struct *alloc_vm_area(unsigned long size) * This ensures that page tables are constructed for this region * of kernel virtual address space and mapped into init_mm. */ - if (generic_page_range(&init_mm, (unsigned long)area->addr, - area->size, f, NULL)) { + if (apply_to_page_range(&init_mm, (unsigned long)area->addr, + area->size, f, NULL)) { free_vm_area(area); return NULL; } diff --git a/linux-2.6-xen-sparse/include/linux/mm.h b/linux-2.6-xen-sparse/include/linux/mm.h index 4a05b8db0d..946f3e52a5 100644 --- a/linux-2.6-xen-sparse/include/linux/mm.h +++ b/linux-2.6-xen-sparse/include/linux/mm.h @@ -1020,10 +1020,10 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address, #define FOLL_ANON 0x08 /* give ZERO_PAGE if no pgtable */ #ifdef CONFIG_XEN -typedef int (*pte_fn_t)(pte_t *pte, struct page *pte_page, unsigned long addr, - void *data); -extern int generic_page_range(struct mm_struct *mm, unsigned long address, - unsigned long size, pte_fn_t fn, void *data); +typedef int (*pte_fn_t)(pte_t *pte, struct page *pmd_page, unsigned long addr, + void *data); +extern int apply_to_page_range(struct mm_struct *mm, unsigned long address, + unsigned long size, pte_fn_t fn, void *data); #endif #ifdef CONFIG_PROC_FS diff --git a/linux-2.6-xen-sparse/mm/memory.c b/linux-2.6-xen-sparse/mm/memory.c index 103c724be1..f91d3bab09 100644 --- a/linux-2.6-xen-sparse/mm/memory.c +++ b/linux-2.6-xen-sparse/mm/memory.c @@ -1378,36 +1378,39 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, EXPORT_SYMBOL(remap_pfn_range); #ifdef CONFIG_XEN -static inline int generic_pte_range(struct mm_struct *mm, pmd_t *pmd, - unsigned long addr, unsigned long end, - pte_fn_t fn, void *data) +static inline int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pte_t *pte; int err; - struct page *pte_page; + struct page *pmd_page; + spinlock_t *ptl; pte = (mm == &init_mm) ? pte_alloc_kernel(pmd, addr) : - pte_alloc_map(mm, pmd, addr); + pte_alloc_map_lock(mm, pmd, addr, &ptl); if (!pte) return -ENOMEM; - pte_page = pmd_page(*pmd); + BUG_ON(pmd_huge(*pmd)); + + pmd_page = pmd_page(*pmd); do { - err = fn(pte, pte_page, addr, data); + err = fn(pte, pmd_page, addr, data); if (err) break; } while (pte++, addr += PAGE_SIZE, addr != end); if (mm != &init_mm) - pte_unmap(pte-1); + pte_unmap_unlock(pte-1, ptl); return err; } -static inline int generic_pmd_range(struct mm_struct *mm, pud_t *pud, - unsigned long addr, unsigned long end, - pte_fn_t fn, void *data) +static inline int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pmd_t *pmd; unsigned long next; @@ -1418,16 +1421,16 @@ static inline int generic_pmd_range(struct mm_struct *mm, pud_t *pud, return -ENOMEM; do { next = pmd_addr_end(addr, end); - err = generic_pte_range(mm, pmd, addr, next, fn, data); + err = apply_to_pte_range(mm, pmd, addr, next, fn, data); if (err) break; } while (pmd++, addr = next, addr != end); return err; } -static inline int generic_pud_range(struct mm_struct *mm, pgd_t *pgd, - unsigned long addr, unsigned long end, - pte_fn_t fn, void *data) +static inline int apply_to_pud_range(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, + pte_fn_t fn, void *data) { pud_t *pud; unsigned long next; @@ -1438,7 +1441,7 @@ static inline int generic_pud_range(struct mm_struct *mm, pgd_t *pgd, return -ENOMEM; do { next = pud_addr_end(addr, end); - err = generic_pmd_range(mm, pud, addr, next, fn, data); + err = apply_to_pmd_range(mm, pud, addr, next, fn, data); if (err) break; } while (pud++, addr = next, addr != end); @@ -1449,8 +1452,8 @@ static inline int generic_pud_range(struct mm_struct *mm, pgd_t *pgd, * Scan a region of virtual memory, filling in page tables as necessary * and calling a provided function on each leaf page table. */ -int generic_page_range(struct mm_struct *mm, unsigned long addr, - unsigned long size, pte_fn_t fn, void *data) +int apply_to_page_range(struct mm_struct *mm, unsigned long addr, + unsigned long size, pte_fn_t fn, void *data) { pgd_t *pgd; unsigned long next; @@ -1461,12 +1464,13 @@ int generic_page_range(struct mm_struct *mm, unsigned long addr, pgd = pgd_offset(mm, addr); do { next = pgd_addr_end(addr, end); - err = generic_pud_range(mm, pgd, addr, next, fn, data); + err = apply_to_pud_range(mm, pgd, addr, next, fn, data); if (err) break; } while (pgd++, addr = next, addr != end); return err; } +EXPORT_SYMBOL_GPL(apply_to_page_range); #endif /* From 3b214d9b38158d1cd18790b67b5a27fd57cb9955 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 23 Mar 2006 15:53:52 +0100 Subject: [PATCH 2/4] Merge hvm_store_cpu_guest_regs() and hvm_store_cpu_guest_ctrl_regs() into a single function. On VMX, make the function work even when the passed VCPU is not the currently-executing VCPU. This allows gdbserver-xen to get correct cpu register context for VMX guests. Signed-off-by: Keir Fraser Signed-off-by: Nitin A Kamble --- xen/arch/x86/dom0_ops.c | 3 +- xen/arch/x86/hvm/platform.c | 2 +- xen/arch/x86/hvm/svm/svm.c | 58 ++++++++++---------- xen/arch/x86/hvm/vmx/vmx.c | 100 ++++++++++++++++++++++++---------- xen/arch/x86/x86_32/traps.c | 3 +- xen/arch/x86/x86_64/traps.c | 3 +- xen/include/asm-x86/hvm/hvm.h | 21 +++---- 7 files changed, 112 insertions(+), 78 deletions(-) diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index cfb8eba348..ab76b4e9f5 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -460,8 +460,7 @@ void arch_getdomaininfo_ctxt( if ( hvm_guest(v) ) { - hvm_store_cpu_guest_regs(v, &c->user_regs); - hvm_store_cpu_guest_ctrl_regs(v, c->ctrlreg); + hvm_store_cpu_guest_regs(v, &c->user_regs, c->ctrlreg); } else { diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 4ae448ba39..94eb1fb13f 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -773,7 +773,7 @@ void handle_mmio(unsigned long va, unsigned long gpa) mmio_opp = &v->arch.hvm_vcpu.mmio_op; regs = mmio_opp->inst_decoder_regs; - hvm_store_cpu_guest_regs(v, regs); + hvm_store_cpu_guest_regs(v, regs, NULL); if ((inst_len = hvm_instruction_length(v)) <= 0) { printf("handle_mmio: failed to get instruction length\n"); diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 42bda15b38..22a5bcb418 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -201,31 +201,41 @@ int svm_initialize_guest_resources(struct vcpu *v) } static void svm_store_cpu_guest_regs( - struct vcpu *v, struct cpu_user_regs *regs) + struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + if ( regs != NULL ) + { #if defined (__x86_64__) - regs->rip = vmcb->rip; - regs->rsp = vmcb->rsp; - regs->rflags = vmcb->rflags; - regs->cs = vmcb->cs.sel; - regs->ds = vmcb->ds.sel; - regs->es = vmcb->es.sel; - regs->ss = vmcb->ss.sel; - regs->gs = vmcb->gs.sel; - regs->fs = vmcb->fs.sel; + regs->rip = vmcb->rip; + regs->rsp = vmcb->rsp; + regs->rflags = vmcb->rflags; + regs->cs = vmcb->cs.sel; + regs->ds = vmcb->ds.sel; + regs->es = vmcb->es.sel; + regs->ss = vmcb->ss.sel; + regs->gs = vmcb->gs.sel; + regs->fs = vmcb->fs.sel; #elif defined (__i386__) - regs->eip = vmcb->rip; - regs->esp = vmcb->rsp; - regs->eflags = vmcb->rflags; - regs->cs = vmcb->cs.sel; - regs->ds = vmcb->ds.sel; - regs->es = vmcb->es.sel; - regs->ss = vmcb->ss.sel; - regs->gs = vmcb->gs.sel; - regs->fs = vmcb->fs.sel; + regs->eip = vmcb->rip; + regs->esp = vmcb->rsp; + regs->eflags = vmcb->rflags; + regs->cs = vmcb->cs.sel; + regs->ds = vmcb->ds.sel; + regs->es = vmcb->es.sel; + regs->ss = vmcb->ss.sel; + regs->gs = vmcb->gs.sel; + regs->fs = vmcb->fs.sel; #endif + } + + if ( crs != NULL ) + { + crs[0] = vmcb->cr0; + crs[3] = vmcb->cr3; + crs[4] = vmcb->cr4; + } } static void svm_load_cpu_guest_regs( @@ -372,15 +382,6 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) return 1; } -void svm_store_cpu_guest_ctrl_regs(struct vcpu *v, unsigned long crs[8]) -{ - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - - crs[0] = vmcb->cr0; - crs[3] = vmcb->cr3; - crs[4] = vmcb->cr4; -} - void svm_modify_guest_state(struct vcpu *v) { svm_modify_vmcb(v, &v->arch.guest_context.user_regs); @@ -448,7 +449,6 @@ int start_svm(void) hvm_funcs.store_cpu_guest_regs = svm_store_cpu_guest_regs; hvm_funcs.load_cpu_guest_regs = svm_load_cpu_guest_regs; - hvm_funcs.store_cpu_guest_ctrl_regs = svm_store_cpu_guest_ctrl_regs; hvm_funcs.modify_guest_state = svm_modify_guest_state; hvm_funcs.realmode = svm_realmode; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index fcca96efdb..69af5901dc 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -398,31 +398,81 @@ void vmx_migrate_timers(struct vcpu *v) migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor); } -void vmx_store_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) +struct vmx_store_cpu_guest_regs_callback_info { + struct vcpu *v; + struct cpu_user_regs *regs; + unsigned long *crs; +}; + +static void vmx_store_cpu_guest_regs( + struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs); + +static void vmx_store_cpu_guest_regs_callback(void *data) { + struct vmx_store_cpu_guest_regs_callback_info *info = data; + vmx_store_cpu_guest_regs(info->v, info->regs, info->crs); +} + +static void vmx_store_cpu_guest_regs( + struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs) +{ + if ( v != current ) + { + /* Non-current VCPUs must be paused to get a register snapshot. */ + ASSERT(atomic_read(&v->pausecnt) != 0); + + if ( v->arch.hvm_vmx.launch_cpu != smp_processor_id() ) + { + /* Get register details from remote CPU. */ + struct vmx_store_cpu_guest_regs_callback_info info = { + .v = v, .regs = regs, .crs = crs }; + cpumask_t cpumask = cpumask_of_cpu(v->arch.hvm_vmx.launch_cpu); + on_selected_cpus(cpumask, vmx_store_cpu_guest_regs_callback, + &info, 1, 1); + return; + } + + /* Register details are on this CPU. Load the correct VMCS. */ + __vmptrld(virt_to_maddr(v->arch.hvm_vmx.vmcs)); + } + + ASSERT(v->arch.hvm_vmx.launch_cpu == smp_processor_id()); + + if ( regs != NULL ) + { #if defined (__x86_64__) - __vmread(GUEST_RFLAGS, ®s->rflags); - __vmread(GUEST_SS_SELECTOR, ®s->ss); - __vmread(GUEST_CS_SELECTOR, ®s->cs); - __vmread(GUEST_DS_SELECTOR, ®s->ds); - __vmread(GUEST_ES_SELECTOR, ®s->es); - __vmread(GUEST_GS_SELECTOR, ®s->gs); - __vmread(GUEST_FS_SELECTOR, ®s->fs); - __vmread(GUEST_RIP, ®s->rip); - __vmread(GUEST_RSP, ®s->rsp); + __vmread(GUEST_RFLAGS, ®s->rflags); + __vmread(GUEST_SS_SELECTOR, ®s->ss); + __vmread(GUEST_CS_SELECTOR, ®s->cs); + __vmread(GUEST_DS_SELECTOR, ®s->ds); + __vmread(GUEST_ES_SELECTOR, ®s->es); + __vmread(GUEST_GS_SELECTOR, ®s->gs); + __vmread(GUEST_FS_SELECTOR, ®s->fs); + __vmread(GUEST_RIP, ®s->rip); + __vmread(GUEST_RSP, ®s->rsp); #elif defined (__i386__) - __vmread(GUEST_RFLAGS, ®s->eflags); - __vmread(GUEST_SS_SELECTOR, ®s->ss); - __vmread(GUEST_CS_SELECTOR, ®s->cs); - __vmread(GUEST_DS_SELECTOR, ®s->ds); - __vmread(GUEST_ES_SELECTOR, ®s->es); - __vmread(GUEST_GS_SELECTOR, ®s->gs); - __vmread(GUEST_FS_SELECTOR, ®s->fs); - __vmread(GUEST_RIP, ®s->eip); - __vmread(GUEST_RSP, ®s->esp); -#else -#error Unsupported architecture + __vmread(GUEST_RFLAGS, ®s->eflags); + __vmread(GUEST_SS_SELECTOR, ®s->ss); + __vmread(GUEST_CS_SELECTOR, ®s->cs); + __vmread(GUEST_DS_SELECTOR, ®s->ds); + __vmread(GUEST_ES_SELECTOR, ®s->es); + __vmread(GUEST_GS_SELECTOR, ®s->gs); + __vmread(GUEST_FS_SELECTOR, ®s->fs); + __vmread(GUEST_RIP, ®s->eip); + __vmread(GUEST_RSP, ®s->esp); #endif + } + + if ( crs != NULL ) + { + __vmread(CR0_READ_SHADOW, &crs[0]); + __vmread(GUEST_CR3, &crs[3]); + __vmread(CR4_READ_SHADOW, &crs[4]); + } + + /* Reload current VCPU's VMCS if it was temporarily unloaded. */ + if ( (v != current) && hvm_guest(current) ) + __vmptrld(virt_to_maddr(current->arch.hvm_vmx.vmcs)); } void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) @@ -456,13 +506,6 @@ void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) #endif } -void vmx_store_cpu_guest_ctrl_regs(struct vcpu *v, unsigned long crs[8]) -{ - __vmread(CR0_READ_SHADOW, &crs[0]); - __vmread(GUEST_CR3, &crs[3]); - __vmread(CR4_READ_SHADOW, &crs[4]); -} - void vmx_modify_guest_state(struct vcpu *v) { modify_vmcs(&v->arch.hvm_vmx, &v->arch.guest_context.user_regs); @@ -616,7 +659,6 @@ int start_vmx(void) hvm_funcs.store_cpu_guest_regs = vmx_store_cpu_guest_regs; hvm_funcs.load_cpu_guest_regs = vmx_load_cpu_guest_regs; - hvm_funcs.store_cpu_guest_ctrl_regs = vmx_store_cpu_guest_ctrl_regs; hvm_funcs.modify_guest_state = vmx_modify_guest_state; hvm_funcs.realmode = vmx_realmode; diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 6fc271867c..1c570dad29 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -27,8 +27,7 @@ void show_registers(struct cpu_user_regs *regs) if ( hvm_guest(current) && guest_mode(regs) ) { context = "hvm"; - hvm_store_cpu_guest_regs(current, &fault_regs); - hvm_store_cpu_guest_ctrl_regs(current, fault_crs); + hvm_store_cpu_guest_regs(current, &fault_regs, fault_crs); } else { diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index ef1f21cb09..e78c8f9453 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -27,8 +27,7 @@ void show_registers(struct cpu_user_regs *regs) if ( hvm_guest(current) && guest_mode(regs) ) { context = "hvm"; - hvm_store_cpu_guest_regs(current, &fault_regs); - hvm_store_cpu_guest_ctrl_regs(current, fault_crs); + hvm_store_cpu_guest_regs(current, &fault_regs, fault_crs); } else { diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 70af33035b..eff373996c 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -41,12 +41,12 @@ struct hvm_function_table { /* * Store and load guest state: * 1) load/store guest register state, - * 2) store guest control register state (used for panic dumps), - * 3) modify guest state (e.g., set debug flags). + * 2) modify guest state (e.g., set debug flags). */ - void (*store_cpu_guest_regs)(struct vcpu *v, struct cpu_user_regs *r); - void (*load_cpu_guest_regs)(struct vcpu *v, struct cpu_user_regs *r); - void (*store_cpu_guest_ctrl_regs)(struct vcpu *v, unsigned long crs[8]); + void (*store_cpu_guest_regs)( + struct vcpu *v, struct cpu_user_regs *r, unsigned long *crs); + void (*load_cpu_guest_regs)( + struct vcpu *v, struct cpu_user_regs *r); void (*modify_guest_state)(struct vcpu *v); /* @@ -93,9 +93,10 @@ hvm_relinquish_guest_resources(struct domain *d) } static inline void -hvm_store_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *r) +hvm_store_cpu_guest_regs( + struct vcpu *v, struct cpu_user_regs *r, unsigned long *crs) { - hvm_funcs.store_cpu_guest_regs(v, r); + hvm_funcs.store_cpu_guest_regs(v, r, crs); } static inline void @@ -104,12 +105,6 @@ hvm_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *r) hvm_funcs.load_cpu_guest_regs(v, r); } -static inline void -hvm_store_cpu_guest_ctrl_regs(struct vcpu *v, unsigned long crs[8]) -{ - hvm_funcs.store_cpu_guest_ctrl_regs(v, crs); -} - static inline void hvm_modify_guest_state(struct vcpu *v) { From a220cd9bebd1249df1708716995a4e95e142392a Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 23 Mar 2006 17:17:08 +0100 Subject: [PATCH 3/4] Reduce spin-waiting in Xen serial driver: 1. Split the serial port lock into receiver and transmitter locks. 2. In the ns16550 interrupt, only call the generic serial service routines if there is receive (or transmit) work to do. 3. In the generic transmit ISR, avoid long spin-waits by *trying* to take the transmitter lock and, if that fails, check again whether the transmitter is empty. This will allow us to bail bail quickly if there is a long-term lock holder stuffing lots of bytes. Also, gdbstub should be setting its serial handle in synchronous mode, just for sanity. Signed-off-by: Keir Fraser --- xen/common/gdbstub.c | 1 + xen/drivers/char/ns16550.c | 7 ++-- xen/drivers/char/serial.c | 67 ++++++++++++++++++++++++-------------- xen/include/xen/serial.h | 2 +- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c index fe51f79d35..8934122925 100644 --- a/xen/common/gdbstub.c +++ b/xen/common/gdbstub.c @@ -562,6 +562,7 @@ initialise_gdb(void) gdb_ctx->serhnd = serial_parse_handle(opt_gdb); if ( gdb_ctx->serhnd != -1 ) printk("GDB stub initialised.\n"); + serial_start_sync(gdb_ctx->serhnd); } /* diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index 9476f473a2..f1ad820f0d 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -121,8 +121,11 @@ static void ns16550_interrupt( while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) ) { - serial_tx_interrupt(port, regs); - serial_rx_interrupt(port, regs); + char lsr = ns_read_reg(uart, LSR); + if ( lsr & LSR_THRE ) + serial_tx_interrupt(port, regs); + if ( lsr & LSR_DR ) + serial_rx_interrupt(port, regs); } } diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 5eb0589443..1cb50c0d94 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -15,8 +16,8 @@ #include static struct serial_port com[2] = { - { .lock = SPIN_LOCK_UNLOCKED }, - { .lock = SPIN_LOCK_UNLOCKED } + { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }, + { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED } }; void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) @@ -25,7 +26,7 @@ void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) serial_rx_fn fn = NULL; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->rx_lock, flags); if ( port->driver->getc(port, &c) ) { @@ -39,7 +40,7 @@ void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c; } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); if ( fn != NULL ) (*fn)(c & 0x7f, regs); @@ -50,7 +51,19 @@ void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) int i; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + local_irq_save(flags); + + /* + * Avoid spinning for a long time: if there is a long-term lock holder + * then we know that they'll be stuffing bytes into the transmitter which + * will therefore not be empty for long. + */ + while ( !spin_trylock(&port->tx_lock) ) + { + if ( !port->driver->tx_empty(port) ) + return; + cpu_relax(); + } if ( port->driver->tx_empty(port) ) { @@ -63,7 +76,7 @@ void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) } } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->tx_lock, flags); } static void __serial_putc(struct serial_port *port, char c) @@ -117,7 +130,7 @@ void serial_putc(int handle, char c) if ( (handle == -1) || !port->driver || !port->driver->putc ) return; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->tx_lock, flags); if ( (c == '\n') && (handle & SERHND_COOKED) ) __serial_putc(port, '\r'); @@ -129,7 +142,7 @@ void serial_putc(int handle, char c) __serial_putc(port, c); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->tx_lock, flags); } void serial_puts(int handle, const char *s) @@ -141,7 +154,7 @@ void serial_puts(int handle, const char *s) if ( (handle == -1) || !port->driver || !port->driver->putc ) return; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->tx_lock, flags); while ( (c = *s++) != '\0' ) { @@ -156,7 +169,7 @@ void serial_puts(int handle, const char *s) __serial_putc(port, c); } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->tx_lock, flags); } char serial_getc(int handle) @@ -168,27 +181,28 @@ char serial_getc(int handle) if ( (handle == -1) || !port->driver || !port->driver->getc ) return '\0'; - do { + do { for ( ; ; ) { - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->rx_lock, flags); if ( port->rxbufp != port->rxbufc ) { c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)]; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); break; } if ( port->driver->getc(port, &c) ) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); break; } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); cpu_relax(); + udelay(100); } } while ( ((handle & SERHND_LO) && (c & 0x80)) || ((handle & SERHND_HI) && !(c & 0x80)) ); @@ -241,7 +255,7 @@ void serial_set_rx_handler(int handle, serial_rx_fn fn) if ( handle == -1 ) return; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->rx_lock, flags); if ( port->rx != NULL ) goto fail; @@ -265,11 +279,11 @@ void serial_set_rx_handler(int handle, serial_rx_fn fn) port->rx = fn; } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); return; fail: - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->rx_lock, flags); printk("ERROR: Conflicting receive handlers for COM%d\n", handle & SERHND_IDX); } @@ -277,8 +291,13 @@ void serial_set_rx_handler(int handle, serial_rx_fn fn) void serial_force_unlock(int handle) { struct serial_port *port = &com[handle & SERHND_IDX]; - if ( handle != -1 ) - port->lock = SPIN_LOCK_UNLOCKED; + + if ( handle == -1 ) + return; + + port->rx_lock = SPIN_LOCK_UNLOCKED; + port->tx_lock = SPIN_LOCK_UNLOCKED; + serial_start_sync(handle); } @@ -290,7 +309,7 @@ void serial_start_sync(int handle) if ( handle == -1 ) return; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->tx_lock, flags); if ( port->sync++ == 0 ) { @@ -303,7 +322,7 @@ void serial_start_sync(int handle) } } - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->tx_lock, flags); } void serial_end_sync(int handle) @@ -314,11 +333,11 @@ void serial_end_sync(int handle) if ( handle == -1 ) return; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->tx_lock, flags); port->sync--; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->tx_lock, flags); } int serial_tx_space(int handle) diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 28f11f4677..d8426630fc 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -42,7 +42,7 @@ struct serial_port { char rxbuf[SERIAL_RXBUFSZ]; unsigned int rxbufp, rxbufc; /* Serial I/O is concurrency-safe. */ - spinlock_t lock; + spinlock_t rx_lock, tx_lock; }; struct uart_driver { From 34951546524eb0d6328ffd205f88d48420c7ad2d Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 23 Mar 2006 16:21:05 +0000 Subject: [PATCH 4/4] Remove unused variable. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/arch/x86_64/kernel/apic-xen.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/apic-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/apic-xen.c index f27b0e3842..3152b914f9 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/apic-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/apic-xen.c @@ -114,8 +114,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) irq_exit(); } -int __initdata unsync_tsc_on_multicluster; - /* * This interrupt should _never_ happen with our APIC/SMP architecture */