From a2388da52dd1e3fa9cba5fc87d70e02648371aa4 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 15 May 2008 09:36:38 +0100 Subject: [PATCH 1/8] ioemu: Fix PVFB backend to limit frame buffer size The recent fix to validate the frontend's frame buffer description neglected to limit the frame buffer size correctly. This lets a malicious frontend make the backend attempt to map an arbitrary amount of guest memory, which could be useful for a denial of service attack against dom0. Signed-off-by: Markus Armbruster --- tools/ioemu/hw/xenfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ioemu/hw/xenfb.c b/tools/ioemu/hw/xenfb.c index 32a94dced1..d1f34c4562 100644 --- a/tools/ioemu/hw/xenfb.c +++ b/tools/ioemu/hw/xenfb.c @@ -502,6 +502,7 @@ static int xenfb_configure_fb(struct xenfb *xenfb, size_t fb_len_lim, fprintf(stderr, "FB: frontend fb size %zu limited to %zu\n", fb_len, fb_len_lim); + fb_len = fb_len_lim; } if (depth != 8 && depth != 16 && depth != 24 && depth != 32) { fprintf(stderr, From 30193253a0c4ae2c9dfb29cd27c987d7b700f340 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 15 May 2008 09:38:00 +0100 Subject: [PATCH 2/8] x86: Fix an S3 bug caused by x_firmware_waking_vector According to ACPI spec., x_firmware_waking_vector in FACS is for waking up in protected mode and firmware_waking_vector is for in real mode. Xen once use x_firmware_waking_vector which can make S3 failed on some platform. This patch fixed the bug by using non-x one. Signed-off-by: Huacai Chen --- xen/arch/x86/acpi/boot.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 1cc148b2e3..c42c4338d0 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -441,17 +441,9 @@ acpi_fadt_parse_sleep_info(struct acpi_table_fadt *fadt) "FACS is shorter than ACPI spec allow: 0x%x", facs->length); - if ((rsdp->revision < 2) || (facs->length < 32)) { - acpi_sinfo.wakeup_vector = facs_pa + - offsetof(struct acpi_table_facs, - firmware_waking_vector); - acpi_sinfo.vector_width = 32; - } else { - acpi_sinfo.wakeup_vector = facs_pa + - offsetof(struct acpi_table_facs, - xfirmware_waking_vector); - acpi_sinfo.vector_width = 64; - } + acpi_sinfo.wakeup_vector = facs_pa + + offsetof(struct acpi_table_facs, firmware_waking_vector); + acpi_sinfo.vector_width = 32; printk(KERN_INFO PREFIX " wakeup_vec[%"PRIx64"], vec_size[%x]\n", From ff635e12aad65d97538bd012beb37506f1d6ca8c Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 15 May 2008 11:09:16 +0100 Subject: [PATCH 3/8] x86, hvm: Support 2MB superpage allocations for HVM guests. Signed-off-by: Xin Xiaohui Signed-off-by: Li Xin, B Signed-off-by: Wei Huang Signed-off-by: Keir Fraser --- tools/libxc/xc_hvm_build.c | 48 +++++- xen/arch/ia64/xen/mm.c | 35 +++-- xen/arch/x86/mm.c | 6 +- xen/arch/x86/mm/hap/p2m-ept.c | 192 ++++++++++++++++++----- xen/arch/x86/mm/p2m.c | 243 +++++++++++++++++++++++------ xen/common/grant_table.c | 2 +- xen/common/memory.c | 12 +- xen/include/asm-ia64/grant_table.h | 2 +- xen/include/asm-ia64/shadow.h | 6 +- xen/include/asm-x86/p2m.h | 13 +- xen/include/xen/paging.h | 4 +- 11 files changed, 434 insertions(+), 129 deletions(-) diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c index 30ac5b4951..8bf5549188 100644 --- a/tools/libxc/xc_hvm_build.c +++ b/tools/libxc/xc_hvm_build.c @@ -19,6 +19,9 @@ #include +#define SUPERPAGE_PFN_SHIFT 9 +#define SUPERPAGE_NR_PFNS (1UL << SUPERPAGE_PFN_SHIFT) + #define SCRATCH_PFN 0xFFFFF #define SPECIALPAGE_GUARD 0 @@ -211,7 +214,7 @@ static int setup_guest(int xc_handle, /* * Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. - * We allocate pages in batches of no more than 2048 to ensure that + * We allocate pages in batches of no more than 8MB to ensure that * we can be preempted and hence dom0 remains responsive. */ rc = xc_domain_memory_populate_physmap( @@ -219,13 +222,50 @@ static int setup_guest(int xc_handle, cur_pages = 0xc0; while ( (rc == 0) && (nr_pages > cur_pages) ) { + /* Clip count to maximum 8MB extent. */ unsigned long count = nr_pages - cur_pages; if ( count > 2048 ) count = 2048; - rc = xc_domain_memory_populate_physmap( - xc_handle, dom, count, 0, 0, &page_array[cur_pages]); - cur_pages += count; + + /* Clip partial superpage extents to superpage boundaries. */ + if ( ((cur_pages & (SUPERPAGE_NR_PFNS-1)) != 0) && + (count > (-cur_pages & (SUPERPAGE_NR_PFNS-1))) ) + count = -cur_pages & (SUPERPAGE_NR_PFNS-1); /* clip s.p. tail */ + else if ( ((count & (SUPERPAGE_NR_PFNS-1)) != 0) && + (count > SUPERPAGE_NR_PFNS) ) + count &= ~(SUPERPAGE_NR_PFNS - 1); /* clip non-s.p. tail */ + + /* Attempt to allocate superpage extents. */ + if ( ((count | cur_pages) & (SUPERPAGE_NR_PFNS - 1)) == 0 ) + { + long done; + xen_pfn_t sp_extents[2048 >> SUPERPAGE_PFN_SHIFT]; + struct xen_memory_reservation sp_req = { + .nr_extents = count >> SUPERPAGE_PFN_SHIFT, + .extent_order = SUPERPAGE_PFN_SHIFT, + .domid = dom + }; + set_xen_guest_handle(sp_req.extent_start, sp_extents); + for ( i = 0; i < sp_req.nr_extents; i++ ) + sp_extents[i] = page_array[cur_pages+(i< 0 ) + { + done <<= SUPERPAGE_PFN_SHIFT; + cur_pages += done; + count -= done; + } + } + + /* Fall back to 4kB extents. */ + if ( count != 0 ) + { + rc = xc_domain_memory_populate_physmap( + xc_handle, dom, count, 0, 0, &page_array[cur_pages]); + cur_pages += count; + } } + if ( rc != 0 ) { PERROR("Could not allocate memory for HVM guest.\n"); diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 5c8c6dd8de..51007bf819 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -2415,16 +2415,20 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags) int guest_physmap_add_page(struct domain *d, unsigned long gpfn, - unsigned long mfn) + unsigned long mfn, unsigned int page_order) { - BUG_ON(!mfn_valid(mfn)); - BUG_ON(mfn_to_page(mfn)->count_info != (PGC_allocated | 1)); - set_gpfn_from_mfn(mfn, gpfn); - smp_mb(); - assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, - ASSIGN_writable | ASSIGN_pgc_allocated); + unsigned long i; - //BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> PAGE_SHIFT)); + for (i = 0; i < (1UL << page_order); i++) { + BUG_ON(!mfn_valid(mfn)); + BUG_ON(mfn_to_page(mfn)->count_info != (PGC_allocated | 1)); + set_gpfn_from_mfn(mfn, gpfn); + smp_mb(); + assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, + ASSIGN_writable | ASSIGN_pgc_allocated); + mfn++; + gpfn++; + } perfc_incr(guest_physmap_add_page); return 0; @@ -2432,10 +2436,15 @@ guest_physmap_add_page(struct domain *d, unsigned long gpfn, void guest_physmap_remove_page(struct domain *d, unsigned long gpfn, - unsigned long mfn) + unsigned long mfn, unsigned int page_order) { + unsigned long i; + BUG_ON(mfn == 0);//XXX - zap_domain_page_one(d, gpfn << PAGE_SHIFT, 0, mfn); + + for (i = 0; i < (1UL << page_order); i++) { + zap_domain_page_one(d, (gpfn+i) << PAGE_SHIFT, 0, mfn+i); + perfc_incr(guest_physmap_remove_page); } @@ -2838,7 +2847,7 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if (prev_mfn && mfn_valid(prev_mfn)) { if (is_xen_heap_mfn(prev_mfn)) /* Xen heap frames are simply unhooked from this phys slot. */ - guest_physmap_remove_page(d, xatp.gpfn, prev_mfn); + guest_physmap_remove_page(d, xatp.gpfn, prev_mfn, 0); else /* Normal domain memory is freed, to avoid leaking memory. */ guest_remove_page(d, xatp.gpfn); @@ -2847,10 +2856,10 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) /* Unmap from old location, if any. */ gpfn = get_gpfn_from_mfn(mfn); if (gpfn != INVALID_M2P_ENTRY) - guest_physmap_remove_page(d, gpfn, mfn); + guest_physmap_remove_page(d, gpfn, mfn, 0); /* Map at new location. */ - guest_physmap_add_page(d, xatp.gpfn, mfn); + guest_physmap_add_page(d, xatp.gpfn, mfn, 0); out: domain_unlock(d); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 6839d53b50..879ce9cb17 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3297,7 +3297,7 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) { if ( is_xen_heap_mfn(prev_mfn) ) /* Xen heap frames are simply unhooked from this phys slot. */ - guest_physmap_remove_page(d, xatp.gpfn, prev_mfn); + guest_physmap_remove_page(d, xatp.gpfn, prev_mfn, 0); else /* Normal domain memory is freed, to avoid leaking memory. */ guest_remove_page(d, xatp.gpfn); @@ -3306,10 +3306,10 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) /* Unmap from old location, if any. */ gpfn = get_gpfn_from_mfn(mfn); if ( gpfn != INVALID_M2P_ENTRY ) - guest_physmap_remove_page(d, gpfn, mfn); + guest_physmap_remove_page(d, gpfn, mfn, 0); /* Map at new location. */ - guest_physmap_add_page(d, xatp.gpfn, mfn); + guest_physmap_add_page(d, xatp.gpfn, mfn, 0); domain_unlock(d); diff --git a/xen/arch/x86/mm/hap/p2m-ept.c b/xen/arch/x86/mm/hap/p2m-ept.c index 697ca4d697..3cac9f3047 100644 --- a/xen/arch/x86/mm/hap/p2m-ept.c +++ b/xen/arch/x86/mm/hap/p2m-ept.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,9 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type) } } +#define GUEST_TABLE_NORMAL_PAGE 1 +#define GUEST_TABLE_SUPER_PAGE 2 + static int ept_next_level(struct domain *d, bool_t read_only, ept_entry_t **table, unsigned long *gfn_remainder, u32 shift) @@ -54,7 +58,6 @@ static int ept_next_level(struct domain *d, bool_t read_only, u32 index; index = *gfn_remainder >> shift; - *gfn_remainder &= (1UL << shift) - 1; ept_entry = (*table) + index; @@ -83,31 +86,53 @@ static int ept_next_level(struct domain *d, bool_t read_only, ept_entry->r = ept_entry->w = ept_entry->x = 1; } - next = map_domain_page(ept_entry->mfn); - unmap_domain_page(*table); - *table = next; - - return 1; + if ( !ept_entry->sp_avail ) + { + *gfn_remainder &= (1UL << shift) - 1; + next = map_domain_page(ept_entry->mfn); + unmap_domain_page(*table); + *table = next; + return GUEST_TABLE_NORMAL_PAGE; + } + else + return GUEST_TABLE_SUPER_PAGE; } static int -ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) +ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, + unsigned int order, p2m_type_t p2mt) { - ept_entry_t *table = - map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); - unsigned long gfn_remainder = gfn; + ept_entry_t *table = NULL; + unsigned long gfn_remainder = gfn, offset = 0; ept_entry_t *ept_entry = NULL; u32 index; - int i, rv = 0; + int i, rv = 0, ret = 0; + int walk_level = order / EPT_TABLE_ORDER; /* Should check if gfn obeys GAW here */ - for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) - if ( !ept_next_level(d, 0, &table, &gfn_remainder, - i * EPT_TABLE_ORDER) ) - goto out; + if ( order != 0 ) + if ( (gfn & ((1UL << order) - 1)) ) + return 1; + + table = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); + + ASSERT(table != NULL); + + for ( i = EPT_DEFAULT_GAW; i > walk_level; i-- ) + { + ret = ept_next_level(d, 0, &table, &gfn_remainder, + i * EPT_TABLE_ORDER); + if ( !ret ) + goto out; + else if ( ret == GUEST_TABLE_SUPER_PAGE ) + break; + } + + index = gfn_remainder >> ( i ? (i * EPT_TABLE_ORDER): order); + walk_level = ( i ? ( i * EPT_TABLE_ORDER) : order) / EPT_TABLE_ORDER; + offset = (gfn_remainder & ( ((1 << (i*EPT_TABLE_ORDER)) - 1))); - index = gfn_remainder; ept_entry = table + index; if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) ) @@ -117,9 +142,20 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) d->arch.p2m->max_mapped_pfn = gfn; ept_entry->emt = EPT_DEFAULT_MT; - ept_entry->sp_avail = 0; + ept_entry->sp_avail = walk_level ? 1 : 0; + + if ( ret == GUEST_TABLE_SUPER_PAGE ) + { + ept_entry->mfn = mfn_x(mfn) - offset; + if ( ept_entry->avail1 == p2m_ram_logdirty && + p2mt == p2m_ram_rw ) + for ( i = 0; i < 512; i++ ) + paging_mark_dirty(d, mfn_x(mfn)-offset+i); + } + else + ept_entry->mfn = mfn_x(mfn); + ept_entry->avail1 = p2mt; - ept_entry->mfn = mfn_x(mfn); ept_entry->rsvd = 0; ept_entry->avail2 = 0; /* last step */ @@ -132,14 +168,42 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) /* Success */ rv = 1; - out: +out: unmap_domain_page(table); ept_sync_domain(d); + /* Now the p2m table is not shared with vt-d page table */ + + if ( iommu_enabled && is_hvm_domain(d) ) + { + if ( p2mt == p2m_ram_rw ) + { + if ( ret == GUEST_TABLE_SUPER_PAGE ) + { + for ( i = 0; i < 512; i++ ) + iommu_map_page(d, gfn-offset+i, mfn_x(mfn)-offset+i); + } + else if ( ret ) + iommu_map_page(d, gfn, mfn_x(mfn)); + } + else + { + if ( ret == GUEST_TABLE_SUPER_PAGE ) + { + for ( i = 0; i < 512; i++ ) + iommu_unmap_page(d, gfn-offset+i); + } + else if ( ret ) + iommu_unmap_page(d, gfn); + } + } + +#ifdef P2M_SHARE_WITH_VTD_PAGE_TABLE /* If p2m table is shared with vtd page-table. */ if ( iommu_enabled && is_hvm_domain(d) && (p2mt == p2m_mmio_direct) ) iommu_flush(d, gfn, (u64*)ept_entry); +#endif return rv; } @@ -152,7 +216,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t) unsigned long gfn_remainder = gfn; ept_entry_t *ept_entry; u32 index; - int i; + int i, ret=0; mfn_t mfn = _mfn(INVALID_MFN); *t = p2m_mmio_dm; @@ -164,17 +228,31 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t) /* Should check if gfn obeys GAW here. */ for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) - if ( !ept_next_level(d, 1, &table, &gfn_remainder, - i * EPT_TABLE_ORDER) ) + { + ret = ept_next_level(d, 1, &table, &gfn_remainder, + i * EPT_TABLE_ORDER); + if ( !ret ) goto out; + else if ( ret == GUEST_TABLE_SUPER_PAGE ) + break; + } - index = gfn_remainder; + index = gfn_remainder >> ( i * EPT_TABLE_ORDER); ept_entry = table + index; if ( ept_entry->avail1 != p2m_invalid ) { *t = ept_entry->avail1; mfn = _mfn(ept_entry->mfn); + if ( i ) + { + /* we may meet super pages, and to split into 4k pages + * to emulate p2m table + */ + unsigned long split_mfn = + mfn_x(mfn) + (gfn_remainder & ( ((1 << (i*EPT_TABLE_ORDER)) - 1 ))); + mfn = _mfn(split_mfn); + } } out: @@ -205,33 +283,63 @@ static void ept_change_entry_type_global(struct domain *d, l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); for (i4 = 0; i4 < EPT_PAGETABLE_ENTRIES; i4++ ) { - if ( !l4e[i4].epte || l4e[i4].sp_avail ) + if ( !l4e[i4].epte ) continue; - l3e = map_domain_page(l4e[i4].mfn); - for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ ) + if ( !l4e[i4].sp_avail ) { - if ( !l3e[i3].epte || l3e[i3].sp_avail ) - continue; - l2e = map_domain_page(l3e[i3].mfn); - for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ ) + l3e = map_domain_page(l4e[i4].mfn); + for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ ) { - if ( !l2e[i2].epte || l2e[i2].sp_avail ) + if ( !l3e[i3].epte ) continue; - l1e = map_domain_page(l2e[i2].mfn); - for ( i1 = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ ) + if ( !l3e[i3].sp_avail ) { - if ( !l1e[i1].epte ) - continue; - if ( l1e[i1].avail1 != ot ) - continue; - l1e[i1].avail1 = nt; - ept_p2m_type_to_flags(l1e+i1, nt); + l2e = map_domain_page(l3e[i3].mfn); + for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ ) + { + if ( !l2e[i2].epte ) + continue; + if ( !l2e[i2].sp_avail ) + { + l1e = map_domain_page(l2e[i2].mfn); + for ( i1 = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ ) + { + if ( !l1e[i1].epte ) + continue; + if ( l1e[i1].avail1 != ot ) + continue; + l1e[i1].avail1 = nt; + ept_p2m_type_to_flags(l1e+i1, nt); + } + unmap_domain_page(l1e); + } + else + { + if ( l2e[i2].avail1 != ot ) + continue; + l2e[i2].avail1 = nt; + ept_p2m_type_to_flags(l2e+i2, nt); + } + } + unmap_domain_page(l2e); + } + else + { + if ( l3e[i3].avail1 != ot ) + continue; + l3e[i3].avail1 = nt; + ept_p2m_type_to_flags(l3e+i3, nt); } - unmap_domain_page(l1e); } - unmap_domain_page(l2e); + unmap_domain_page(l3e); + } + else + { + if ( l4e[i4].avail1 != ot ) + continue; + l4e[i4].avail1 = nt; + ept_p2m_type_to_flags(l4e+i4, nt); } - unmap_domain_page(l3e); } unmap_domain_page(l4e); diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 9c29b20048..dcf35fabcb 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -151,9 +151,11 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table, unsigned long *gfn_remainder, unsigned long gfn, u32 shift, u32 max, unsigned long type) { + l1_pgentry_t *l1_entry; l1_pgentry_t *p2m_entry; l1_pgentry_t new_entry; void *next; + int i; ASSERT(d->arch.p2m->alloc_page); if ( !(p2m_entry = p2m_find_entry(*table, gfn_remainder, gfn, @@ -194,6 +196,44 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table, break; } } + + ASSERT(l1e_get_flags(*p2m_entry) & _PAGE_PRESENT); + + /* split single large page into 4KB page in P2M table */ + if ( type == PGT_l1_page_table && (l1e_get_flags(*p2m_entry) & _PAGE_PSE) ) + { + unsigned long flags, pfn; + struct page_info *pg = d->arch.p2m->alloc_page(d); + if ( pg == NULL ) + return 0; + list_add_tail(&pg->list, &d->arch.p2m->pages); + pg->u.inuse.type_info = PGT_l1_page_table | 1 | PGT_validated; + pg->count_info = 1; + + /* New splintered mappings inherit the flags of the old superpage, + * with a little reorganisation for the _PAGE_PSE_PAT bit. */ + flags = l1e_get_flags(*p2m_entry); + pfn = l1e_get_pfn(*p2m_entry); + if ( pfn & 1 ) /* ==> _PAGE_PSE_PAT was set */ + pfn -= 1; /* Clear it; _PAGE_PSE becomes _PAGE_PAT */ + else + flags &= ~_PAGE_PSE; /* Clear _PAGE_PSE (== _PAGE_PAT) */ + + l1_entry = map_domain_page(mfn_x(page_to_mfn(pg))); + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + { + new_entry = l1e_from_pfn(pfn + i, flags); + paging_write_p2m_entry(d, gfn, + l1_entry+i, *table_mfn, new_entry, 1); + } + unmap_domain_page(l1_entry); + + new_entry = l1e_from_pfn(mfn_x(page_to_mfn(pg)), + __PAGE_HYPERVISOR|_PAGE_USER); + paging_write_p2m_entry(d, gfn, + p2m_entry, *table_mfn, new_entry, 2); + } + *table_mfn = _mfn(l1e_get_pfn(*p2m_entry)); next = map_domain_page(mfn_x(*table_mfn)); unmap_domain_page(*table); @@ -204,7 +244,8 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table, // Returns 0 on error (out of memory) static int -p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) +p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, + unsigned int page_order, p2m_type_t p2mt) { // XXX -- this might be able to be faster iff current->domain == d mfn_t table_mfn = pagetable_get_mfn(d->arch.phys_table); @@ -212,6 +253,7 @@ p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) unsigned long gfn_remainder = gfn; l1_pgentry_t *p2m_entry; l1_pgentry_t entry_content; + l2_pgentry_t l2e_content; int rv=0; #if CONFIG_PAGING_LEVELS >= 4 @@ -235,27 +277,54 @@ p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) PGT_l2_page_table) ) goto out; - if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn, - L2_PAGETABLE_SHIFT - PAGE_SHIFT, - L2_PAGETABLE_ENTRIES, PGT_l1_page_table) ) - goto out; + if ( page_order == 0 ) + { + if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn, + L2_PAGETABLE_SHIFT - PAGE_SHIFT, + L2_PAGETABLE_ENTRIES, PGT_l1_page_table) ) + goto out; - p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, - 0, L1_PAGETABLE_ENTRIES); - ASSERT(p2m_entry); + p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, + 0, L1_PAGETABLE_ENTRIES); + ASSERT(p2m_entry); + + if ( mfn_valid(mfn) || (p2mt == p2m_mmio_direct) ) + entry_content = l1e_from_pfn(mfn_x(mfn), p2m_type_to_flags(p2mt)); + else + entry_content = l1e_empty(); + + /* level 1 entry */ + paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1); + } + else + { + p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, + L2_PAGETABLE_SHIFT - PAGE_SHIFT, + L2_PAGETABLE_ENTRIES); + ASSERT(p2m_entry); + + if ( (l1e_get_flags(*p2m_entry) & _PAGE_PRESENT) && + !(l1e_get_flags(*p2m_entry) & _PAGE_PSE) ) + { + P2M_ERROR("configure P2M table 4KB L2 entry with large page\n"); + domain_crash(d); + goto out; + } + + if ( mfn_valid(mfn) ) + l2e_content = l2e_from_pfn(mfn_x(mfn), + p2m_type_to_flags(p2mt) | _PAGE_PSE); + else + l2e_content = l2e_empty(); + + entry_content.l1 = l2e_content.l2; + paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 2); + } /* Track the highest gfn for which we have ever had a valid mapping */ if ( mfn_valid(mfn) && (gfn > d->arch.p2m->max_mapped_pfn) ) d->arch.p2m->max_mapped_pfn = gfn; - if ( mfn_valid(mfn) || (p2mt == p2m_mmio_direct) ) - entry_content = l1e_from_pfn(mfn_x(mfn), p2m_type_to_flags(p2mt)); - else - entry_content = l1e_empty(); - - /* level 1 entry */ - paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1); - if ( iommu_enabled && is_hvm_domain(d) ) { if ( p2mt == p2m_ram_rw ) @@ -335,6 +404,16 @@ p2m_gfn_to_mfn(struct domain *d, unsigned long gfn, p2m_type_t *t) unmap_domain_page(l2e); return _mfn(INVALID_MFN); } + else if ( (l2e_get_flags(*l2e) & _PAGE_PSE) ) + { + mfn = _mfn(l2e_get_pfn(*l2e) + l1_table_offset(addr)); + *t = p2m_flags_to_type(l2e_get_flags(*l2e)); + unmap_domain_page(l2e); + + ASSERT(mfn_valid(mfn) || !p2m_is_ram(*t)); + return (p2m_is_valid(*t)) ? mfn : _mfn(INVALID_MFN); + } + mfn = _mfn(l2e_get_pfn(*l2e)); unmap_domain_page(l2e); @@ -358,6 +437,7 @@ static mfn_t p2m_gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t) { mfn_t mfn = _mfn(INVALID_MFN); p2m_type_t p2mt = p2m_mmio_dm; + paddr_t addr = ((paddr_t)gfn) << PAGE_SHIFT; /* XXX This is for compatibility with the old model, where anything not * XXX marked as RAM was considered to be emulated MMIO space. * XXX Once we start explicitly registering MMIO regions in the p2m @@ -366,26 +446,45 @@ static mfn_t p2m_gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t) if ( gfn <= current->domain->arch.p2m->max_mapped_pfn ) { l1_pgentry_t l1e = l1e_empty(); + l2_pgentry_t l2e = l2e_empty(); int ret; ASSERT(gfn < (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t)); - /* Need to __copy_from_user because the p2m is sparse and this - * part might not exist */ - ret = __copy_from_user(&l1e, - &phys_to_machine_mapping[gfn], - sizeof(l1e)); - - if ( ret == 0 ) { - p2mt = p2m_flags_to_type(l1e_get_flags(l1e)); - ASSERT(l1e_get_pfn(l1e) != INVALID_MFN || !p2m_is_ram(p2mt)); + ret = __copy_from_user(&l2e, + &__linear_l1_table[l1_linear_offset(RO_MPT_VIRT_START) + l2_linear_offset(addr)], + sizeof(l2e)); + + if ( (ret == 0) && (l2e_get_flags(l2e) & _PAGE_PRESENT) && + (l2e_get_flags(l2e) & _PAGE_PSE) ) + { + p2mt = p2m_flags_to_type(l2e_get_flags(l2e)); + ASSERT(l2e_get_pfn(l2e) != INVALID_MFN || !p2m_is_ram(p2mt)); if ( p2m_is_valid(p2mt) ) - mfn = _mfn(l1e_get_pfn(l1e)); - else - /* XXX see above */ + mfn = _mfn(l2e_get_pfn(l2e) + l1_table_offset(addr)); + else p2mt = p2m_mmio_dm; } + else + { + + /* Need to __copy_from_user because the p2m is sparse and this + * part might not exist */ + ret = __copy_from_user(&l1e, + &phys_to_machine_mapping[gfn], + sizeof(l1e)); + + if ( ret == 0 ) { + p2mt = p2m_flags_to_type(l1e_get_flags(l1e)); + ASSERT(l1e_get_pfn(l1e) != INVALID_MFN || !p2m_is_ram(p2mt)); + if ( p2m_is_valid(p2mt) ) + mfn = _mfn(l1e_get_pfn(l1e)); + else + /* XXX see above */ + p2mt = p2m_mmio_dm; + } + } } *t = p2mt; @@ -430,9 +529,10 @@ void p2m_change_entry_type_global(struct domain *d, } static inline -int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) +int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, + unsigned int page_order, p2m_type_t p2mt) { - return d->arch.p2m->set_entry(d, gfn, mfn, p2mt); + return d->arch.p2m->set_entry(d, gfn, mfn, page_order, p2mt); } // Allocate a new p2m table for a domain. @@ -493,7 +593,8 @@ int p2m_alloc_table(struct domain *d, P2M_PRINTK("populating p2m table\n"); /* Initialise physmap tables for slot zero. Other code assumes this. */ - if ( !set_p2m_entry(d, 0, _mfn(INVALID_MFN), p2m_invalid) ) + if ( !set_p2m_entry(d, 0, _mfn(INVALID_MFN), 0, + p2m_invalid) ) goto error; /* Copy all existing mappings from the page list and m2p */ @@ -512,7 +613,7 @@ int p2m_alloc_table(struct domain *d, (gfn != 0x55555555L) #endif && gfn != INVALID_M2P_ENTRY - && !set_p2m_entry(d, gfn, mfn, p2m_ram_rw) ) + && !set_p2m_entry(d, gfn, mfn, 0, p2m_ram_rw) ) goto error; } @@ -688,6 +789,28 @@ static void audit_p2m(struct domain *d) gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT); continue; } + + /* check for super page */ + if ( l2e_get_flags(l2e[i2]) & _PAGE_PSE ) + { + mfn = l2e_get_pfn(l2e[i2]); + ASSERT(mfn_valid(_mfn(mfn))); + for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++) + { + m2pfn = get_gpfn_from_mfn(mfn+i1); + if ( m2pfn != (gfn + i) ) + { + pmbad++; + P2M_PRINTK("mismatch: gfn %#lx -> mfn %#lx" + " -> gfn %#lx\n", gfn+i, mfn+i, + m2pfn); + BUG(); + } + } + gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT); + continue; + } + l1e = map_domain_page(mfn_x(_mfn(l2e_get_pfn(l2e[i2])))); for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ ) @@ -737,32 +860,38 @@ static void audit_p2m(struct domain *d) static void -p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn) +p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn, + unsigned int page_order) { + unsigned long i; + if ( !paging_mode_translate(d) ) return; + P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn); - set_p2m_entry(d, gfn, _mfn(INVALID_MFN), p2m_invalid); - set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); + set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid); + for ( i = 0; i < (1UL << page_order); i++ ) + set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY); } void guest_physmap_remove_page(struct domain *d, unsigned long gfn, - unsigned long mfn) + unsigned long mfn, unsigned int page_order) { p2m_lock(d->arch.p2m); audit_p2m(d); - p2m_remove_page(d, gfn, mfn); + p2m_remove_page(d, gfn, mfn, page_order); audit_p2m(d); p2m_unlock(d->arch.p2m); } int guest_physmap_add_entry(struct domain *d, unsigned long gfn, - unsigned long mfn, p2m_type_t t) + unsigned long mfn, unsigned int page_order, + p2m_type_t t) { - unsigned long ogfn; + unsigned long i, ogfn; p2m_type_t ot; mfn_t omfn; int rc = 0; @@ -795,7 +924,8 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn, if ( p2m_is_ram(ot) ) { ASSERT(mfn_valid(omfn)); - set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY); + for ( i = 0; i < (1UL << page_order); i++ ) + set_gpfn_from_mfn(mfn_x(omfn)+i, INVALID_M2P_ENTRY); } ogfn = mfn_to_gfn(d, _mfn(mfn)); @@ -818,21 +948,23 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn, P2M_DEBUG("old gfn=%#lx -> mfn %#lx\n", ogfn , mfn_x(omfn)); if ( mfn_x(omfn) == mfn ) - p2m_remove_page(d, ogfn, mfn); + p2m_remove_page(d, ogfn, mfn, page_order); } } if ( mfn_valid(_mfn(mfn)) ) { - if ( !set_p2m_entry(d, gfn, _mfn(mfn), t) ) + if ( !set_p2m_entry(d, gfn, _mfn(mfn), page_order, t) ) rc = -EINVAL; - set_gpfn_from_mfn(mfn, gfn); + for ( i = 0; i < (1UL << page_order); i++ ) + set_gpfn_from_mfn(mfn+i, gfn+i); } else { gdprintk(XENLOG_WARNING, "Adding bad mfn to p2m map (%#lx -> %#lx)\n", gfn, mfn); - if ( !set_p2m_entry(d, gfn, _mfn(INVALID_MFN), p2m_invalid) ) + if ( !set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, + p2m_invalid) ) rc = -EINVAL; } @@ -851,7 +983,7 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt) l1_pgentry_t l1e_content; l1_pgentry_t *l1e; l2_pgentry_t *l2e; - mfn_t l1mfn; + mfn_t l1mfn, l2mfn; int i1, i2; l3_pgentry_t *l3e; int i3; @@ -891,6 +1023,7 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt) { continue; } + l2mfn = _mfn(l3e_get_pfn(l3e[i3])); l2e = map_domain_page(l3e_get_pfn(l3e[i3])); for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ ) { @@ -899,6 +1032,20 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt) continue; } + if ( (l2e_get_flags(l2e[i2]) & _PAGE_PSE) ) + { + flags = l2e_get_flags(l2e[i2]); + if ( p2m_flags_to_type(flags) != ot ) + continue; + mfn = l2e_get_pfn(l2e[i2]); + gfn = get_gpfn_from_mfn(mfn); + flags = p2m_flags_to_type(nt); + l1e_content = l1e_from_pfn(mfn, flags | _PAGE_PSE); + paging_write_p2m_entry(d, gfn, (l1_pgentry_t *)&l2e[i2], + l2mfn, l1e_content, 2); + continue; + } + l1mfn = _mfn(l2e_get_pfn(l2e[i2])); l1e = map_domain_page(mfn_x(l1mfn)); @@ -944,7 +1091,7 @@ p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn, mfn = gfn_to_mfn(d, gfn, &pt); if ( pt == ot ) - set_p2m_entry(d, gfn, mfn, nt); + set_p2m_entry(d, gfn, mfn, 0, nt); p2m_unlock(d->arch.p2m); @@ -968,7 +1115,7 @@ set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY); } - rc = set_p2m_entry(d, gfn, mfn, p2m_mmio_direct); + rc = set_p2m_entry(d, gfn, mfn, 0, p2m_mmio_direct); if ( 0 == rc ) gdprintk(XENLOG_ERR, "set_mmio_p2m_entry: set_p2m_entry failed! mfn=%08lx\n", @@ -992,7 +1139,7 @@ clear_mmio_p2m_entry(struct domain *d, unsigned long gfn) "clear_mmio_p2m_entry: gfn_to_mfn failed! gfn=%08lx\n", gfn); return 0; } - rc = set_p2m_entry(d, gfn, _mfn(INVALID_MFN), 0); + rc = set_p2m_entry(d, gfn, _mfn(INVALID_MFN), 0, 0); return rc; } diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 53662df865..0e7f19251b 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -1159,7 +1159,7 @@ gnttab_transfer( spin_lock(&e->grant_table->lock); sha = &shared_entry(e->grant_table, gop.ref); - guest_physmap_add_page(e, sha->frame, mfn); + guest_physmap_add_page(e, sha->frame, mfn, 0); sha->frame = mfn; wmb(); sha->flags |= GTF_transfer_completed; diff --git a/xen/common/memory.c b/xen/common/memory.c index 3e9f7071ab..cc9d1851a7 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -127,9 +127,7 @@ static void populate_physmap(struct memop_args *a) if ( unlikely(paging_mode_translate(d)) ) { - for ( j = 0; j < (1 << a->extent_order); j++ ) - if ( guest_physmap_add_page(d, gpfn + j, mfn + j) ) - goto out; + guest_physmap_add_page(d, gpfn, mfn, a->extent_order); } else { @@ -172,7 +170,7 @@ int guest_remove_page(struct domain *d, unsigned long gmfn) if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) put_page(page); - guest_physmap_remove_page(d, gmfn, mfn); + guest_physmap_remove_page(d, gmfn, mfn, 0); put_page(page); @@ -419,7 +417,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) if ( !test_and_clear_bit(_PGC_allocated, &page->count_info) ) BUG(); mfn = page_to_mfn(page); - guest_physmap_remove_page(d, mfn_to_gmfn(d, mfn), mfn); + guest_physmap_remove_page(d, mfn_to_gmfn(d, mfn), mfn, 0); put_page(page); } @@ -440,9 +438,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) mfn = page_to_mfn(page); if ( unlikely(paging_mode_translate(d)) ) { - /* Ignore failure here. There's nothing we can do. */ - for ( k = 0; k < (1UL << exch.out.extent_order); k++ ) - (void)guest_physmap_add_page(d, gpfn + k, mfn + k); + guest_physmap_add_page(d, gpfn, mfn, exch.out.extent_order); } else { diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h index 52949b822e..a9db1d5015 100644 --- a/xen/include/asm-ia64/grant_table.h +++ b/xen/include/asm-ia64/grant_table.h @@ -13,7 +13,7 @@ int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, int replace_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned long new_gpaddr, unsigned int flags); // for grant transfer -int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn); +int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn, int order); /* XXX * somewhere appropriate diff --git a/xen/include/asm-ia64/shadow.h b/xen/include/asm-ia64/shadow.h index d978a2bccf..935d3059ad 100644 --- a/xen/include/asm-ia64/shadow.h +++ b/xen/include/asm-ia64/shadow.h @@ -40,8 +40,10 @@ * Utilities to change relationship of gpfn->mfn for designated domain, * which is required by gnttab transfer, balloon, device model and etc. */ -int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn); -void guest_physmap_remove_page(struct domain *d, unsigned long gpfn, unsigned long mfn); +int guest_physmap_add_page(struct domain *d, unsigned long gpfn, + unsigned long mfn, unsigned int page_order); +void guest_physmap_remove_page(struct domain *d, unsigned long gpfn, + unsigned long mfn, unsigned int page_order); static inline int shadow_mode_enabled(struct domain *d) diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index cb5c882b03..4e478502c3 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -102,7 +102,8 @@ struct p2m_domain { void (*free_page )(struct domain *d, struct page_info *pg); int (*set_entry )(struct domain *d, unsigned long gfn, - mfn_t mfn, p2m_type_t p2mt); + mfn_t mfn, unsigned int page_order, + p2m_type_t p2mt); mfn_t (*get_entry )(struct domain *d, unsigned long gfn, p2m_type_t *p2mt); mfn_t (*get_entry_current)(unsigned long gfn, @@ -203,21 +204,23 @@ void p2m_final_teardown(struct domain *d); /* Add a page to a domain's p2m table */ int guest_physmap_add_entry(struct domain *d, unsigned long gfn, - unsigned long mfn, p2m_type_t t); + unsigned long mfn, unsigned int page_order, + p2m_type_t t); /* Untyped version for RAM only, for compatibility * * Return 0 for success */ static inline int guest_physmap_add_page(struct domain *d, unsigned long gfn, - unsigned long mfn) + unsigned long mfn, + unsigned int page_order) { - return guest_physmap_add_entry(d, gfn, mfn, p2m_ram_rw); + return guest_physmap_add_entry(d, gfn, mfn, page_order, p2m_ram_rw); } /* Remove a page from a domain's p2m table */ void guest_physmap_remove_page(struct domain *d, unsigned long gfn, - unsigned long mfn); + unsigned long mfn, unsigned int page_order); /* Change types across all p2m entries in a domain */ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt); diff --git a/xen/include/xen/paging.h b/xen/include/xen/paging.h index 3e77d94e8e..e7455a269d 100644 --- a/xen/include/xen/paging.h +++ b/xen/include/xen/paging.h @@ -18,8 +18,8 @@ #else #define paging_mode_translate(d) (0) -#define guest_physmap_add_page(d, p, m) (0) -#define guest_physmap_remove_page(d, p, m) ((void)0) +#define guest_physmap_add_page(d, p, m, o) (0) +#define guest_physmap_remove_page(d, p, m, o) ((void)0) #endif From 65e7eed196395ad2912e8185ad1384b033e2969e Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 15 May 2008 15:10:05 +0100 Subject: [PATCH 4/8] ioemu: Do not try to guess backing file format when using qcow vbds. Signed-off-by: Ian Jackson --- tools/ioemu/block.c | 32 ++++++++++++++++++++++++++------ tools/ioemu/xenstore.c | 4 +++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/tools/ioemu/block.c b/tools/ioemu/block.c index 7bf990f787..e61ba2637e 100644 --- a/tools/ioemu/block.c +++ b/tools/ioemu/block.c @@ -240,8 +240,28 @@ static int is_windows_drive(const char *filename) } #endif +static int bdrv_invalid_protocol_open(BlockDriverState *bs, + const char *filename, int flags) { + return -ENOENT; +} + +static BlockDriver bdrv_invalid_protocol = { + "invalid_protocol", + .bdrv_open = bdrv_invalid_protocol_open, +}; + static BlockDriver *find_protocol(const char *filename) { + /* Return values: + * &bdrv_xxx + * filename specifies protocol xxx + * caller should use that + * NULL filename does not specify any protocol + * caller may apply their own default + * &bdrv_invalid_protocol filename speciies an unknown protocol + * caller should return -ENOENT; or may just try to open with + * that bdrv, which always fails that way. + */ BlockDriver *drv1; char protocol[128]; int len; @@ -254,7 +274,7 @@ static BlockDriver *find_protocol(const char *filename) #endif p = strchr(filename, ':'); if (!p) - return NULL; /* do not ever guess raw, it is a security problem! */ + return NULL; len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; @@ -265,7 +285,7 @@ static BlockDriver *find_protocol(const char *filename) !strcmp(drv1->protocol_name, protocol)) return drv1; } - return NULL; + return &bdrv_invalid_protocol; } /* XXX: force raw format if block or character device ? It would @@ -295,8 +315,8 @@ static BlockDriver *find_image_format(const char *filename) #endif drv = find_protocol(filename); - /* no need to test disk image formats for vvfat */ - if (drv == &bdrv_vvfat) + /* no need to test disk image format if the filename told us */ + if (drv != NULL) return drv; ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); @@ -390,7 +410,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (flags & BDRV_O_FILE) { drv = find_protocol(filename); if (!drv) - return -ENOENT; + drv = &bdrv_raw; } else { if (!drv) { drv = find_image_format(filename); @@ -438,7 +458,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0) + if (bdrv_open2(bs->backing_hd, backing_filename, 0, &bdrv_raw) < 0) goto fail; } diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index 6093618e44..551190e86c 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -260,6 +260,8 @@ void xenstore_parse_domain_config(int hvm_domid) /* autoguess qcow vs qcow2 */ } else if (!strcmp(drv,"file") || !strcmp(drv,"phy")) { format = &bdrv_raw; + } else if (!strcmp(drv,"phy")) { + format = &bdrv_raw; } else { format = bdrv_find_format(drv); if (!format) { @@ -269,7 +271,7 @@ void xenstore_parse_domain_config(int hvm_domid) } } if (bdrv_open2(bs, params, 0 /* snapshot */, format) < 0) - fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s')\n", buf, params, drv ? drv : "?"); + fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0"); } } From b93de169c393454ac8cba172e85131fb0a6006c0 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 15 May 2008 16:40:51 +0100 Subject: [PATCH 5/8] xend: Device configurations of suspended virtual machines are inaccessible The device configurations of suspended virtual machines are inaccessible even though for example the UUIDs of the VIFs and VBDs are known and returned when VM.get_VIFs()/get_VBDs() is called, though when trying to access their records for example, then handle is reported as being invalid. This patch fixes this. Signed-off-by: Stefan Berger --- tools/python/xen/xend/XendDomainInfo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 7ebb0bf3f3..3f87e35693 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -3013,7 +3013,8 @@ class XendDomainInfo: # shortcut if the domain isn't started because # the devcontrollers will have no better information # than XendConfig. - if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,): + if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED, + XEN_API_VM_POWER_STATE_SUSPENDED): if dev_config: return copy.deepcopy(dev_config) return None From d4c079bdc594d1d9ef3c7f9c3707638570d764d8 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Fri, 16 May 2008 09:30:10 +0100 Subject: [PATCH 6/8] ioemu: serial save/load fix This patch fixes several bugs in serial.c (1) A typo in serial_save() where qemu_get_8s is called (should be qemu_put_8s) (2) No support provided in serial_load() for version_id == 1 (should unmarshal a 1 byte s->divider and should provide a default value for s->fcr) (3) Call serial_ioport_write() to initialize s->fcr. It is not sufficient to load its value; other hidden values (such as s->recv_fifo.itl) must be re-initialized. Signed-off-by: Ben Guthro Signed-off-by: Robert Phillips --- tools/ioemu/hw/serial.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/ioemu/hw/serial.c b/tools/ioemu/hw/serial.c index af6aa64ee3..c6758315a2 100644 --- a/tools/ioemu/hw/serial.c +++ b/tools/ioemu/hw/serial.c @@ -705,12 +705,13 @@ static void serial_save(QEMUFile *f, void *opaque) qemu_put_8s(f,&s->lsr); qemu_put_8s(f,&s->msr); qemu_put_8s(f,&s->scr); - qemu_get_8s(f,&s->fcr); + qemu_put_8s(f,&s->fcr); } static int serial_load(QEMUFile *f, void *opaque, int version_id) { SerialState *s = opaque; + uint8_t fcr = 0; if(version_id > 2) return -EINVAL; @@ -729,6 +730,11 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f,&s->scr); qemu_get_8s(f,&s->fcr); + if (version_id >= 2) + qemu_get_8s(f,&fcr); + + /* Initialize fcr via setter to perform essential side-effects */ + serial_ioport_write(s, 0x02, fcr); return 0; } From 652c2b91745604cf1645947e572875bf86ff7f94 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Fri, 16 May 2008 09:31:03 +0100 Subject: [PATCH 7/8] [IA64] trivial compilation error fix for 17645:8d18e52a1b23. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/mm.c | 2 +- xen/include/asm-ia64/grant_table.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 51007bf819..ee67c3d54e 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -2442,7 +2442,7 @@ guest_physmap_remove_page(struct domain *d, unsigned long gpfn, BUG_ON(mfn == 0);//XXX - for (i = 0; i < (1UL << page_order); i++) { + for (i = 0; i < (1UL << page_order); i++) zap_domain_page_one(d, (gpfn+i) << PAGE_SHIFT, 0, mfn+i); perfc_incr(guest_physmap_remove_page); diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h index a9db1d5015..903a930910 100644 --- a/xen/include/asm-ia64/grant_table.h +++ b/xen/include/asm-ia64/grant_table.h @@ -13,7 +13,7 @@ int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, int replace_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned long new_gpaddr, unsigned int flags); // for grant transfer -int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn, int order); +int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn, unsigned int page_order); /* XXX * somewhere appropriate From 2950bd57c142d3d60f0368fdc9a8d625a1c9f623 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Fri, 16 May 2008 09:37:19 +0100 Subject: [PATCH 8/8] Provide Px statistic data to user through libxc Sampling and collecting dynamic Px statistic data, including Px state value, Px count, Px residency time, Px transition matrix, etc. Provide Px statistic data to user through libxc. Signed-off-by: Liu Jinsong --- tools/libxc/Makefile | 1 + tools/libxc/xc_pm.c | 101 ++++++++++++++++++++ tools/libxc/xenctrl.h | 19 ++++ xen/arch/x86/acpi/Makefile | 1 + xen/arch/x86/acpi/cpufreq/cpufreq.c | 12 ++- xen/arch/x86/acpi/cpufreq/utility.c | 77 +++++++++++++++ xen/arch/x86/acpi/pmstat.c | 110 ++++++++++++++++++++++ xen/arch/x86/platform_hypercall.c | 3 + xen/common/sysctl.c | 16 ++++ xen/include/acpi/cpufreq/processor_perf.h | 23 ++++- xen/include/public/sysctl.h | 37 +++++++- 11 files changed, 395 insertions(+), 5 deletions(-) create mode 100644 tools/libxc/xc_pm.c create mode 100644 xen/arch/x86/acpi/pmstat.c diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 3fd926ad47..47bfb2c004 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -20,6 +20,7 @@ CTRL_SRCS-y += xc_private.c CTRL_SRCS-y += xc_sedf.c CTRL_SRCS-y += xc_csched.c CTRL_SRCS-y += xc_tbuf.c +CTRL_SRCS-y += xc_pm.c ifneq ($(stubdom),y) CTRL_SRCS-y += xc_resume.c endif diff --git a/tools/libxc/xc_pm.c b/tools/libxc/xc_pm.c new file mode 100644 index 0000000000..0378cbd521 --- /dev/null +++ b/tools/libxc/xc_pm.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * xc_pm.c - Libxc API for Xen Power Management (Px/Cx/Tx, etc.) statistic + * + * Copyright (c) 2008, Liu Jinsong + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "xc_private.h" + +int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px) +{ + DECLARE_SYSCTL; + int ret; + + sysctl.cmd = XEN_SYSCTL_get_pmstat; + sysctl.u.get_pmstat.type = PMSTAT_get_max_px; + sysctl.u.get_pmstat.cpuid = cpuid; + ret = xc_sysctl(xc_handle, &sysctl); + if ( ret ) + return ret; + + *max_px = sysctl.u.get_pmstat.u.getpx.total; + return ret; +} + +int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt) +{ + DECLARE_SYSCTL; + int max_px, ret; + + if ( !pxpt || !(pxpt->trans_pt) || !(pxpt->pt) ) + return -EINVAL; + + if ( (ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px)) != 0) + return ret; + + if ( (ret = lock_pages(pxpt->trans_pt, + max_px * max_px * sizeof(uint64_t))) != 0 ) + return ret; + + if ( (ret = lock_pages(pxpt->pt, + max_px * sizeof(struct xc_px_val))) != 0 ) + { + unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t)); + return ret; + } + + sysctl.cmd = XEN_SYSCTL_get_pmstat; + sysctl.u.get_pmstat.type = PMSTAT_get_pxstat; + sysctl.u.get_pmstat.cpuid = cpuid; + set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.trans_pt, pxpt->trans_pt); + set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.pt, + (pm_px_val_t *)pxpt->pt); + + ret = xc_sysctl(xc_handle, &sysctl); + if ( ret ) + { + unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t)); + unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val)); + return ret; + } + + pxpt->total = sysctl.u.get_pmstat.u.getpx.total; + pxpt->usable = sysctl.u.get_pmstat.u.getpx.usable; + pxpt->last = sysctl.u.get_pmstat.u.getpx.last; + pxpt->cur = sysctl.u.get_pmstat.u.getpx.cur; + + unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t)); + unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val)); + + return ret; +} + +int xc_pm_reset_pxstat(int xc_handle, int cpuid) +{ + DECLARE_SYSCTL; + + sysctl.cmd = XEN_SYSCTL_get_pmstat; + sysctl.u.get_pmstat.type = PMSTAT_reset_pxstat; + sysctl.u.get_pmstat.cpuid = cpuid; + + return xc_sysctl(xc_handle, &sysctl); +} diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 40e44b1fbf..130a05e19d 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -1034,4 +1034,23 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs); #endif +struct xc_px_val { + uint64_t freq; /* Px core frequency */ + uint64_t residency; /* Px residency time */ + uint64_t count; /* Px transition count */ +}; + +struct xc_px_stat { + uint8_t total; /* total Px states */ + uint8_t usable; /* usable Px states */ + uint8_t last; /* last Px state */ + uint8_t cur; /* current Px state */ + uint64_t *trans_pt; /* Px transition table */ + struct xc_px_val *pt; +}; + +int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px); +int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt); +int xc_pm_reset_pxstat(int xc_handle, int cpuid); + #endif /* XENCTRL_H */ diff --git a/xen/arch/x86/acpi/Makefile b/xen/arch/x86/acpi/Makefile index 1a82f5d75c..e4cb83b0c6 100644 --- a/xen/arch/x86/acpi/Makefile +++ b/xen/arch/x86/acpi/Makefile @@ -2,3 +2,4 @@ subdir-y += cpufreq obj-y += boot.o obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o +obj-y += pmstat.o diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c index 2ac4be4e55..53b7f0cd45 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -369,6 +369,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, if (!check_freqs(cmd.mask, freqs.new, data)) return -EAGAIN; + px_statistic_update(cmd.mask, perf->state, next_perf_state); + perf->state = next_perf_state; policy->cur = freqs.new; @@ -581,9 +583,13 @@ int acpi_cpufreq_init(void) for_each_online_cpu(i) { xen_px_policy[i].cpu = i; + ret = px_statistic_init(i); + if (ret) + goto out; + ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]); if (ret) - goto cpufreq_init_out; + goto out; } /* setup ondemand cpufreq */ @@ -593,10 +599,10 @@ int acpi_cpufreq_init(void) i = first_cpu(pt[dom]); ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START); if (ret) - goto cpufreq_init_out; + goto out; } -cpufreq_init_out: +out: xfree(pt); return ret; diff --git a/xen/arch/x86/acpi/cpufreq/utility.c b/xen/arch/x86/acpi/cpufreq/utility.c index 83475935dc..89934b320b 100644 --- a/xen/arch/x86/acpi/cpufreq/utility.c +++ b/xen/arch/x86/acpi/cpufreq/utility.c @@ -33,6 +33,83 @@ struct cpufreq_driver *cpufreq_driver; +/********************************************************************* + * Px STATISTIC INFO * + *********************************************************************/ + +void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) +{ + uint32_t i; + uint64_t now; + + now = NOW(); + + for_each_cpu_mask(i, cpumask) { + struct pm_px *pxpt = &px_statistic_data[i]; + uint32_t statnum = processor_pminfo[i].perf.state_count; + + pxpt->u.last = from; + pxpt->u.cur = to; + pxpt->u.pt[to].count++; + pxpt->u.pt[from].residency += now - pxpt->prev_state_wall; + + (*(pxpt->u.trans_pt + from*statnum + to))++; + + pxpt->prev_state_wall = now; + } +} + +int px_statistic_init(int cpuid) +{ + uint32_t i, count; + struct pm_px *pxpt = &px_statistic_data[cpuid]; + struct processor_pminfo *pmpt = &processor_pminfo[cpuid]; + + count = pmpt->perf.state_count; + + pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count); + if (!pxpt->u.trans_pt) + return -ENOMEM; + + pxpt->u.pt = xmalloc_array(struct pm_px_val, count); + if (!pxpt->u.pt) { + xfree(pxpt->u.trans_pt); + return -ENOMEM; + } + + memset(pxpt->u.trans_pt, 0, count * count * (sizeof(uint64_t))); + memset(pxpt->u.pt, 0, count * (sizeof(struct pm_px_val))); + + pxpt->u.total = pmpt->perf.state_count; + pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc; + + for (i=0; i < pmpt->perf.state_count; i++) + pxpt->u.pt[i].freq = pmpt->perf.states[i].core_frequency; + + pxpt->prev_state_wall = NOW(); + + return 0; +} + +void px_statistic_reset(int cpuid) +{ + uint32_t i, j, count; + struct pm_px *pxpt = &px_statistic_data[cpuid]; + + count = processor_pminfo[cpuid].perf.state_count; + + for (i=0; i < count; i++) { + pxpt->u.pt[i].residency = 0; + pxpt->u.pt[i].count = 0; + + for (j=0; j < count; j++) + *(pxpt->u.trans_pt + i*count + j) = 0; + } + + pxpt->prev_state_wall = NOW(); +} + + /********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/ diff --git a/xen/arch/x86/acpi/pmstat.c b/xen/arch/x86/acpi/pmstat.c new file mode 100644 index 0000000000..a18a78e69f --- /dev/null +++ b/xen/arch/x86/acpi/pmstat.c @@ -0,0 +1,110 @@ +/***************************************************************************** +# pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.) +# +# Copyright (c) 2008, Liu Jinsong +# +# 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., 59 +# Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The full GNU General Public License is included in this distribution in the +# file called LICENSE. +# +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct pm_px px_statistic_data[NR_CPUS]; + +int do_get_pm_info(struct xen_sysctl_get_pmstat *op) +{ + int ret = 0; + struct pm_px *pxpt = &px_statistic_data[op->cpuid]; + struct processor_pminfo *pmpt = &processor_pminfo[op->cpuid]; + + /* to protect the case when Px was controlled by dom0-kernel */ + /* or when CPU_FREQ not set in which case ACPI Px objects not parsed */ + if ( !pmpt->perf.init ) + return -EINVAL; + + if ( !cpu_online(op->cpuid) ) + return -EINVAL; + + switch( op->type ) + { + case PMSTAT_get_max_px: + { + op->u.getpx.total = pmpt->perf.state_count; + break; + } + + case PMSTAT_get_pxstat: + { + uint64_t now, ct; + + now = NOW(); + pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc; + pxpt->u.pt[pxpt->u.cur].residency += now - pxpt->prev_state_wall; + pxpt->prev_state_wall = now; + + ct = pmpt->perf.state_count; + if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) ) + { + ret = -EFAULT; + break; + } + + if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) ) + { + ret = -EFAULT; + break; + } + + op->u.getpx.total = pxpt->u.total; + op->u.getpx.usable = pxpt->u.usable; + op->u.getpx.last = pxpt->u.last; + op->u.getpx.cur = pxpt->u.cur; + + break; + } + + case PMSTAT_reset_pxstat: + { + px_statistic_reset(op->cpuid); + break; + } + + default: + printk("not defined sub-hypercall @ do_get_pm_info\n"); + ret = -ENOSYS; + break; + } + + return ret; +} diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 5538eb3149..dbcc4a2e5b 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -403,7 +403,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS | XEN_PX_PSD | XEN_PX_PPC ) ) + { + pxpt->init =1; cpu_count++; + } if ( cpu_count == num_online_cpus() ) ret = acpi_cpufreq_init(); break; diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 1b9c6a58a8..0b32378df7 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -25,6 +25,8 @@ #include #include +extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op); + extern long arch_do_sysctl( struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl); @@ -196,6 +198,20 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) } break; + case XEN_SYSCTL_get_pmstat: + { + ret = do_get_pm_info(&op->u.get_pmstat); + if ( ret ) + break; + + if ( copy_to_guest(u_sysctl, op, 1) ) + { + ret = -EFAULT; + break; + } + } + break; + default: ret = arch_do_sysctl(op, u_sysctl); break; diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index 27add2a77f..3596947910 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -2,9 +2,13 @@ #define __XEN_PROCESSOR_PM_H__ #include +#include int get_cpu_id(u8); int acpi_cpufreq_init(void); +void px_statistic_update(cpumask_t, uint8_t, uint8_t); +int px_statistic_init(int); +void px_statistic_reset(int); struct processor_performance { uint32_t state; @@ -16,15 +20,32 @@ struct processor_performance { struct xen_psd_package domain_info; cpumask_t shared_cpu_map; uint32_t shared_type; + + uint32_t init; }; struct processor_pminfo { uint32_t acpi_id; uint32_t id; - uint32_t flag; struct processor_performance perf; }; extern struct processor_pminfo processor_pminfo[NR_CPUS]; +struct px_stat { + uint8_t total; /* total Px states */ + uint8_t usable; /* usable Px states */ + uint8_t last; /* last Px state */ + uint8_t cur; /* current Px state */ + uint64_t *trans_pt; /* Px transition table */ + pm_px_val_t *pt; +}; + +struct pm_px { + struct px_stat u; + uint64_t prev_state_wall; +}; + +extern struct pm_px px_statistic_data[NR_CPUS]; + #endif /* __XEN_PROCESSOR_PM_H__ */ diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index b66c02190c..0a2c55b7cf 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -212,7 +212,41 @@ struct xen_sysctl_availheap { }; typedef struct xen_sysctl_availheap xen_sysctl_availheap_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t); - + +#define XEN_SYSCTL_get_pmstat 10 +struct pm_px_val { + uint64_aligned_t freq; /* Px core frequency */ + uint64_aligned_t residency; /* Px residency time */ + uint64_aligned_t count; /* Px transition count */ +}; +typedef struct pm_px_val pm_px_val_t; +DEFINE_XEN_GUEST_HANDLE(pm_px_val_t); + +struct pm_px_stat { + uint8_t total; /* total Px states */ + uint8_t usable; /* usable Px states */ + uint8_t last; /* last Px state */ + uint8_t cur; /* current Px state */ + XEN_GUEST_HANDLE_64(uint64) trans_pt; /* Px transition table */ + XEN_GUEST_HANDLE_64(pm_px_val_t) pt; +}; +typedef struct pm_px_stat pm_px_stat_t; +DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t); + +struct xen_sysctl_get_pmstat { +#define PMSTAT_get_max_px 0x11 +#define PMSTAT_get_pxstat 0x12 +#define PMSTAT_reset_pxstat 0x13 + uint32_t type; + uint32_t cpuid; + union { + struct pm_px_stat getpx; + /* other struct for cx, tx, etc */ + } u; +}; +typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_get_pmstat_t); + struct xen_sysctl { uint32_t cmd; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -226,6 +260,7 @@ struct xen_sysctl { struct xen_sysctl_debug_keys debug_keys; struct xen_sysctl_getcpuinfo getcpuinfo; struct xen_sysctl_availheap availheap; + struct xen_sysctl_get_pmstat get_pmstat; uint8_t pad[128]; } u; };