From 5a1ef100bef2a10f484412cb2c74a582171ae32c Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Tue, 16 Jan 2007 10:40:37 -0700 Subject: [PATCH] [IA64] Change vCPU initialization to avoid domVTi privregs memory leak 1) This patch moved some processing from vcpu_initialise() and added a new function vcpu_late_initialise(). It executes the following initializations for VCPU of dom0/domU. - Allocate the VHPT - Allocate the privregs area and assign these pages into guest pseudo physical address space. - Set the tlbflush_timestamp. It is executed in the following sequence. dom0: start_kernel() ->domain_create() ->alloc_vcpu(VCPU0) ->alloc_vcpu_struct(VCPU0) ->vcpu_initialise(VCPU0) ->vcpu_late_initialise(VCPU0) ->construct_dom0 ->alloc_vcpu(othe VCPUs) ->alloc_vcpu_struct(other VCPUs) ->vcpu_initialise(other VCPUs) ia64_hypercall(FW_HYPERCALL_IPI) ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC) ->arch_set_info_guest(other VCPUs) ->vcpu_late_initialise(other VCPUs) domU: do_domctl(XEN_DOMCTL_createdomain) ->domain_create() do_domctl(XEN_DOMCTL_max_vcpus) ->alloc_vcpu(all VCPUs) ->alloc_vcpu_struct(all VCPUs) ->vcpu_initialise(all VCPUs) do_domctl(XEN_DOMCTL_setvcpucontext) ->set_info_guest(VCPU0) ->arch_set_info_guest(VCPU0) ->vcpu_late_initialise(VCPU0) ia64_hypercall(FW_HYPERCALL_IPI) ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC) ->arch_set_info_guest(other VCPUs) ->vcpu_late_initialise(other VCPUs) 2) This patch modified the domain_set_shared_info_va(). Currently, initialization of arch.privregs->interrupt_mask_addr of all VCPUs is executed in domain_set_shared_info_va(). However, allocation of privregs area is late by modified of 1). Therefore, this patch modified initialization of arch.privregs->interrupt_mask_addr to the following sequence. dom0 and domU: ia64_hypercall(FW_HYPERCALL_SET_SHARED_INFO_VA) ->domain_set_shared_info_va() Initialize interrupt_mask_addr of VCPU0 ia64_hypercall(FW_HYPERCALL_IPI) ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC) ->arch_set_info_guest(other VCPUs) ->vcpu_late_initialise(other VCPUs) Initialize interrupt_mask_addr of other VCPUs Signed-off-by: Masaki Kanno --- xen/arch/ia64/xen/dom0_ops.c | 10 --- xen/arch/ia64/xen/domain.c | 128 ++++++++++++++++++---------------- xen/arch/ia64/xen/xensetup.c | 6 +- xen/include/asm-ia64/domain.h | 1 + 4 files changed, 72 insertions(+), 73 deletions(-) diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 2ee0a935a9..a2c0903ed6 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -103,16 +103,6 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = -EINVAL; break; } - if (!d->arch.is_vti) { - struct vcpu *v; - for_each_vcpu(d, v) { - BUG_ON(v->arch.privregs == NULL); - free_domheap_pages(virt_to_page(v->arch.privregs), - get_order_from_shift(XMAPPEDREGS_SHIFT)); - v->arch.privregs = NULL; - relinquish_vcpu_resources(v); - } - } d->arch.is_vti = 1; vmx_setup_platform(d); } diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index ed1a6519a0..f28d2040e0 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -305,24 +305,14 @@ void hlt_timer_fn(void *data) void relinquish_vcpu_resources(struct vcpu *v) { - if (HAS_PERVCPU_VHPT(v->domain)) - pervcpu_vhpt_free(v); - if (v->arch.privregs != NULL) { - // this might be called by arch_do_domctl() with XEN_DOMCTL_arch_setup() - // for domVTi. - if (!(atomic_read(&v->domain->refcnt) & DOMAIN_DESTROYED)) { - unsigned long i; - for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE) - guest_physmap_remove_page(v->domain, - IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i, - virt_to_maddr(v->arch.privregs + i)); - } - - free_xenheap_pages(v->arch.privregs, - get_order_from_shift(XMAPPEDREGS_SHIFT)); - v->arch.privregs = NULL; - } - kill_timer(&v->arch.hlt_timer); + if (HAS_PERVCPU_VHPT(v->domain)) + pervcpu_vhpt_free(v); + if (v->arch.privregs != NULL) { + free_xenheap_pages(v->arch.privregs, + get_order_from_shift(XMAPPEDREGS_SHIFT)); + v->arch.privregs = NULL; + } + kill_timer(&v->arch.hlt_timer); } struct vcpu *alloc_vcpu_struct(void) @@ -361,36 +351,8 @@ void free_vcpu_struct(struct vcpu *v) int vcpu_initialise(struct vcpu *v) { struct domain *d = v->domain; - int rc, order, i; if (!is_idle_domain(d)) { - if (!d->arch.is_vti) { - if (HAS_PERVCPU_VHPT(d)) - if ((rc = pervcpu_vhpt_alloc(v)) != 0) - return rc; - - /* Create privregs page only if not VTi. */ - order = get_order_from_shift(XMAPPEDREGS_SHIFT); - v->arch.privregs = alloc_xenheap_pages(order); - BUG_ON(v->arch.privregs == NULL); - memset(v->arch.privregs, 0, 1 << XMAPPEDREGS_SHIFT); - for (i = 0; i < (1 << order); i++) - share_xen_page_with_guest(virt_to_page(v->arch.privregs) + - i, d, XENSHARE_writable); - /* - * XXX IA64_XMAPPEDREGS_PADDR - * assign these pages into guest pseudo physical address - * space for dom0 to map this page by gmfn. - * this is necessary for domain save, restore and dump-core. - */ - for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE) - assign_domain_page(d, IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i, - virt_to_maddr(v->arch.privregs + i)); - - tlbflush_update_time(&v->arch.tlbflush_timestamp, - tlbflush_current_time()); - } - v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0; v->arch.metaphysical_rr4 = d->arch.metaphysical_rr4; v->arch.metaphysical_saved_rr0 = d->arch.metaphysical_rr0; @@ -420,6 +382,41 @@ int vcpu_initialise(struct vcpu *v) return 0; } +int vcpu_late_initialise(struct vcpu *v) +{ + struct domain *d = v->domain; + int rc, order, i; + + if (HAS_PERVCPU_VHPT(d)) { + rc = pervcpu_vhpt_alloc(v); + if (rc != 0) + return rc; + } + + /* Create privregs page. */ + order = get_order_from_shift(XMAPPEDREGS_SHIFT); + v->arch.privregs = alloc_xenheap_pages(order); + BUG_ON(v->arch.privregs == NULL); + memset(v->arch.privregs, 0, 1 << XMAPPEDREGS_SHIFT); + for (i = 0; i < (1 << order); i++) + share_xen_page_with_guest(virt_to_page(v->arch.privregs) + i, + d, XENSHARE_writable); + /* + * XXX IA64_XMAPPEDREGS_PADDR + * assign these pages into guest pseudo physical address + * space for dom0 to map this page by gmfn. + * this is necessary for domain save, restore and dump-core. + */ + for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE) + assign_domain_page(d, IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i, + virt_to_maddr(v->arch.privregs + i)); + + tlbflush_update_time(&v->arch.tlbflush_timestamp, + tlbflush_current_time()); + + return 0; +} + void vcpu_destroy(struct vcpu *v) { if (v->domain->arch.is_vti) @@ -553,6 +550,7 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c) { struct pt_regs *regs = vcpu_regs (v); struct domain *d = v->domain; + int rc; *regs = c.nat->user_regs; @@ -582,16 +580,25 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c) v->arch.event_callback_ip = er->event_callback_ip; v->arch.dcr = er->dcr; v->arch.iva = er->iva; - } - - if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) - return 0; - if (d->arch.is_vti) - vmx_final_setup_guest(v); - - /* This overrides some registers. */ - vcpu_init_regs(v); - + } + + if (test_bit(_VCPUF_initialised, &v->vcpu_flags)) + return 0; + + if (d->arch.is_vti) + vmx_final_setup_guest(v); + else { + rc = vcpu_late_initialise(v); + if (rc != 0) + return rc; + VCPU(v, interrupt_mask_addr) = + (unsigned char *) d->arch.shared_info_va + + INT_ENABLE_OFFSET(v); + } + + /* This overrides some registers. */ + vcpu_init_regs(v); + /* Don't redo final setup */ set_bit(_VCPUF_initialised, &v->vcpu_flags); return 0; @@ -683,7 +690,6 @@ domain_set_shared_info_va (unsigned long va) { struct vcpu *v = current; struct domain *d = v->domain; - struct vcpu *v1; /* Check virtual address: must belong to region 7, @@ -699,10 +705,8 @@ domain_set_shared_info_va (unsigned long va) printk ("Domain set shared_info_va to 0x%016lx\n", va); d->arch.shared_info_va = va; - for_each_vcpu (d, v1) { - VCPU(v1, interrupt_mask_addr) = - (unsigned char *)va + INT_ENABLE_OFFSET(v1); - } + VCPU(v, interrupt_mask_addr) = (unsigned char *)va + + INT_ENABLE_OFFSET(v); __ia64_per_cpu_var(current_psr_ic_addr) = (int *)(va + XSI_PSR_IC_OFS); @@ -1106,7 +1110,7 @@ int construct_dom0(struct domain *d, printk ("Dom0 max_vcpus=%d\n", dom0_max_vcpus); for ( i = 1; i < dom0_max_vcpus; i++ ) if (alloc_vcpu(d, i, i) == NULL) - printk ("Cannot allocate dom0 vcpu %d\n", i); + panic("Cannot allocate dom0 vcpu %d\n", i); /* Copy the OS image. */ loaddomainelfimage(d,image_start); diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index 7833642fb4..0d1eaf23dd 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -249,6 +249,7 @@ void start_kernel(void) unsigned long dom0_initrd_start, dom0_initrd_size; unsigned long md_end, relo_start, relo_end, relo_size = 0; struct domain *idle_domain; + struct vcpu *dom0_vcpu0; efi_memory_desc_t *kern_md, *last_md, *md; #ifdef CONFIG_SMP int i; @@ -503,8 +504,11 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); /* Create initial domain 0. */ dom0 = domain_create(0, 0); - if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) ) + if (dom0 == NULL) panic("Error creating domain 0\n"); + dom0_vcpu0 = alloc_vcpu(dom0, 0, 0); + if (dom0_vcpu0 == NULL || vcpu_late_initialise(dom0_vcpu0) != 0) + panic("Cannot allocate dom0 vcpu 0\n"); dom0->is_privileged = 1; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index a09446d6b1..2090908bf2 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -21,6 +21,7 @@ struct tlb_track; extern void domain_relinquish_resources(struct domain *); struct vcpu; extern void relinquish_vcpu_resources(struct vcpu *v); +extern int vcpu_late_initialise(struct vcpu *v); /* given a current domain metaphysical address, return the physical address */ extern unsigned long translate_domain_mpaddr(unsigned long mpaddr, -- 2.30.2