446 lines
18 KiB
Diff
446 lines
18 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1232986782 0
|
|
# Node ID 39517e863cc89a085341e1d53317aaa7ceddd127
|
|
# Parent 055c589f4791811797867736857b08fdd0fd6d49
|
|
x86_64: Widen page counts to avoid overflow.
|
|
References: bnc#470949
|
|
|
|
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
|
|
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1232988758 0
|
|
# Node ID 728d1892f0e24c2531df2d61a2d95177400ceb17
|
|
# Parent 90909b81b3b9cf9b303e2bc457580603da3ac7fd
|
|
x86: Clean up shadow_page_info after page_info changes.
|
|
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
|
|
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1233056759 0
|
|
# Node ID 6e623569455c08b57e43e3355f6809b3a4ba0707
|
|
# Parent 7b56dbd1b439e0996083810489398cb51dc43aa6
|
|
x86: clean up struct page_info
|
|
|
|
Remove the now unnecessary (and leading to misalignment of cpumask on
|
|
x86-64) 'packed' attributes.
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@novell.com>
|
|
|
|
--- a/xen/arch/x86/domain.c
|
|
+++ b/xen/arch/x86/domain.c
|
|
@@ -143,7 +143,7 @@ void dump_pageframe_info(struct domain *
|
|
{
|
|
list_for_each_entry ( page, &d->page_list, list )
|
|
{
|
|
- printk(" DomPage %p: caf=%08x, taf=%" PRtype_info "\n",
|
|
+ printk(" DomPage %p: caf=%08lx, taf=%" PRtype_info "\n",
|
|
_p(page_to_mfn(page)),
|
|
page->count_info, page->u.inuse.type_info);
|
|
}
|
|
@@ -151,7 +151,7 @@ void dump_pageframe_info(struct domain *
|
|
|
|
list_for_each_entry ( page, &d->xenpage_list, list )
|
|
{
|
|
- printk(" XenPage %p: caf=%08x, taf=%" PRtype_info "\n",
|
|
+ printk(" XenPage %p: caf=%08lx, taf=%" PRtype_info "\n",
|
|
_p(page_to_mfn(page)),
|
|
page->count_info, page->u.inuse.type_info);
|
|
}
|
|
--- a/xen/arch/x86/mm.c
|
|
+++ b/xen/arch/x86/mm.c
|
|
@@ -714,8 +714,8 @@ get_page_from_l1e(
|
|
else if ( pte_flags_to_cacheattr(l1f) !=
|
|
((page->count_info >> PGC_cacheattr_base) & 7) )
|
|
{
|
|
- uint32_t x, nx, y = page->count_info;
|
|
- uint32_t cacheattr = pte_flags_to_cacheattr(l1f);
|
|
+ unsigned long x, nx, y = page->count_info;
|
|
+ unsigned long cacheattr = pte_flags_to_cacheattr(l1f);
|
|
|
|
if ( is_xen_heap_page(page) )
|
|
{
|
|
@@ -1869,7 +1869,7 @@ static int mod_l4_entry(l4_pgentry_t *pl
|
|
|
|
void put_page(struct page_info *page)
|
|
{
|
|
- u32 nx, x, y = page->count_info;
|
|
+ unsigned long nx, x, y = page->count_info;
|
|
|
|
do {
|
|
x = y;
|
|
@@ -1887,7 +1887,7 @@ void put_page(struct page_info *page)
|
|
|
|
int get_page(struct page_info *page, struct domain *domain)
|
|
{
|
|
- u32 x, y = page->count_info;
|
|
+ unsigned long x, y = page->count_info;
|
|
|
|
do {
|
|
x = y;
|
|
@@ -1906,7 +1906,7 @@ int get_page(struct page_info *page, str
|
|
fail:
|
|
if ( !_shadow_mode_refcounts(domain) && !domain->is_dying )
|
|
gdprintk(XENLOG_INFO,
|
|
- "Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%" PRtype_info,
|
|
+ "Error pfn %lx: rd=%p, od=%p, caf=%08lx, taf=%" PRtype_info,
|
|
page_to_mfn(page), domain, page_get_owner(page),
|
|
y, page->u.inuse.type_info);
|
|
return 0;
|
|
@@ -1922,7 +1922,7 @@ int get_page(struct page_info *page, str
|
|
*/
|
|
static void get_page_light(struct page_info *page)
|
|
{
|
|
- u32 x, nx, y = page->count_info;
|
|
+ unsigned long x, nx, y = page->count_info;
|
|
|
|
do {
|
|
x = y;
|
|
@@ -1963,7 +1963,7 @@ static int alloc_page_type(struct page_i
|
|
rc = alloc_segdesc_page(page);
|
|
break;
|
|
default:
|
|
- printk("Bad type in alloc_page_type %lx t=%" PRtype_info " c=%x\n",
|
|
+ printk("Bad type in alloc_page_type %lx t=%" PRtype_info " c=%lx\n",
|
|
type, page->u.inuse.type_info,
|
|
page->count_info);
|
|
rc = -EINVAL;
|
|
@@ -1987,7 +1987,7 @@ static int alloc_page_type(struct page_i
|
|
{
|
|
ASSERT(rc < 0);
|
|
MEM_LOG("Error while validating mfn %lx (pfn %lx) for type %"
|
|
- PRtype_info ": caf=%08x taf=%" PRtype_info,
|
|
+ PRtype_info ": caf=%08lx taf=%" PRtype_info,
|
|
page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)),
|
|
type, page->count_info, page->u.inuse.type_info);
|
|
page->u.inuse.type_info = 0;
|
|
@@ -3144,7 +3144,7 @@ static int create_grant_pte_mapping(
|
|
void *va;
|
|
unsigned long gmfn, mfn;
|
|
struct page_info *page;
|
|
- u32 type;
|
|
+ unsigned long type;
|
|
l1_pgentry_t ol1e;
|
|
struct domain *d = v->domain;
|
|
|
|
@@ -3205,7 +3205,7 @@ static int destroy_grant_pte_mapping(
|
|
void *va;
|
|
unsigned long gmfn, mfn;
|
|
struct page_info *page;
|
|
- u32 type;
|
|
+ unsigned long type;
|
|
l1_pgentry_t ol1e;
|
|
|
|
gmfn = addr >> PAGE_SHIFT;
|
|
@@ -3431,7 +3431,7 @@ int replace_grant_host_mapping(
|
|
int steal_page(
|
|
struct domain *d, struct page_info *page, unsigned int memflags)
|
|
{
|
|
- u32 x, y;
|
|
+ unsigned long x, y;
|
|
|
|
spin_lock(&d->page_alloc_lock);
|
|
|
|
@@ -3468,7 +3468,7 @@ int steal_page(
|
|
|
|
fail:
|
|
spin_unlock(&d->page_alloc_lock);
|
|
- MEM_LOG("Bad page %p: ed=%p(%u), sd=%p, caf=%08x, taf=%" PRtype_info,
|
|
+ MEM_LOG("Bad page %p: ed=%p(%u), sd=%p, caf=%08lx, taf=%" PRtype_info,
|
|
(void *)page_to_mfn(page), d, d->domain_id,
|
|
page_get_owner(page), page->count_info, page->u.inuse.type_info);
|
|
return -1;
|
|
--- a/xen/arch/x86/mm/hap/hap.c
|
|
+++ b/xen/arch/x86/mm/hap/hap.c
|
|
@@ -166,7 +166,7 @@ void hap_free_p2m_page(struct domain *d,
|
|
ASSERT(page_get_owner(pg) == d);
|
|
/* Should have just the one ref we gave it in alloc_p2m_page() */
|
|
if ( (pg->count_info & PGC_count_mask) != 1 )
|
|
- HAP_ERROR("Odd p2m page count c=%#x t=%"PRtype_info"\n",
|
|
+ HAP_ERROR("Odd p2m page count c=%#lx t=%"PRtype_info"\n",
|
|
pg->count_info, pg->u.inuse.type_info);
|
|
pg->count_info = 0;
|
|
/* Free should not decrement domain's total allocation, since
|
|
--- a/xen/arch/x86/mm/shadow/common.c
|
|
+++ b/xen/arch/x86/mm/shadow/common.c
|
|
@@ -1678,7 +1678,7 @@ shadow_free_p2m_page(struct domain *d, s
|
|
/* Should have just the one ref we gave it in alloc_p2m_page() */
|
|
if ( (pg->count_info & PGC_count_mask) != 1 )
|
|
{
|
|
- SHADOW_ERROR("Odd p2m page count c=%#x t=%"PRtype_info"\n",
|
|
+ SHADOW_ERROR("Odd p2m page count c=%#lx t=%"PRtype_info"\n",
|
|
pg->count_info, pg->u.inuse.type_info);
|
|
}
|
|
pg->count_info = 0;
|
|
@@ -1796,14 +1796,21 @@ static unsigned int sh_set_allocation(st
|
|
sp = list_entry(d->arch.paging.shadow.freelists[order].next,
|
|
struct shadow_page_info, list);
|
|
list_del(&sp->list);
|
|
-#if defined(__x86_64__)
|
|
/*
|
|
- * Re-instate lock field which we overwrite with shadow_page_info.
|
|
- * This was safe, since the lock is only used on guest pages.
|
|
+ * The pages were allocated anonymously, but the owner field
|
|
+ * may get overwritten, so need to clear it here.
|
|
*/
|
|
for ( j = 0; j < 1U << order; j++ )
|
|
+ {
|
|
+ page_set_owner(&((struct page_info *)sp)[j], NULL);
|
|
+#if defined(__x86_64__)
|
|
+ /*
|
|
+ * Re-instate lock field which we overwrite with shadow_page_info.
|
|
+ * This was safe, since the lock is only used on guest pages.
|
|
+ */
|
|
spin_lock_init(&((struct page_info *)sp)[j].lock);
|
|
#endif
|
|
+ }
|
|
d->arch.paging.shadow.free_pages -= 1 << order;
|
|
d->arch.paging.shadow.total_pages -= 1 << order;
|
|
free_domheap_pages((struct page_info *)sp, order);
|
|
@@ -2516,7 +2523,7 @@ int sh_remove_all_mappings(struct vcpu *
|
|
&& (page->u.inuse.type_info & PGT_count_mask) == 0) )
|
|
{
|
|
SHADOW_ERROR("can't find all mappings of mfn %lx: "
|
|
- "c=%08x t=%08lx\n", mfn_x(gmfn),
|
|
+ "c=%08lx t=%08lx\n", mfn_x(gmfn),
|
|
page->count_info, page->u.inuse.type_info);
|
|
}
|
|
}
|
|
@@ -3591,7 +3598,6 @@ int shadow_track_dirty_vram(struct domai
|
|
for ( i = 0; i < nr; i++ ) {
|
|
mfn_t mfn = gfn_to_mfn(d, begin_pfn + i, &t);
|
|
struct page_info *page;
|
|
- u32 count_info;
|
|
int dirty = 0;
|
|
paddr_t sl1ma = d->dirty_vram->sl1ma[i];
|
|
|
|
@@ -3602,8 +3608,7 @@ int shadow_track_dirty_vram(struct domai
|
|
else
|
|
{
|
|
page = mfn_to_page(mfn);
|
|
- count_info = page->u.inuse.type_info & PGT_count_mask;
|
|
- switch (count_info)
|
|
+ switch (page->u.inuse.type_info & PGT_count_mask)
|
|
{
|
|
case 0:
|
|
/* No guest reference, nothing to track. */
|
|
--- a/xen/arch/x86/mm/shadow/multi.c
|
|
+++ b/xen/arch/x86/mm/shadow/multi.c
|
|
@@ -1334,9 +1334,8 @@ static inline void shadow_vram_get_l1e(s
|
|
if ( (gfn >= d->dirty_vram->begin_pfn) && (gfn < d->dirty_vram->end_pfn) ) {
|
|
unsigned long i = gfn - d->dirty_vram->begin_pfn;
|
|
struct page_info *page = mfn_to_page(mfn);
|
|
- u32 count_info = page->u.inuse.type_info & PGT_count_mask;
|
|
|
|
- if ( count_info == 1 )
|
|
+ if ( (page->u.inuse.type_info & PGT_count_mask) == 1 )
|
|
/* Initial guest reference, record it */
|
|
d->dirty_vram->sl1ma[i] = pfn_to_paddr(mfn_x(sl1mfn))
|
|
| ((unsigned long)sl1e & ~PAGE_MASK);
|
|
@@ -1362,12 +1361,11 @@ static inline void shadow_vram_put_l1e(s
|
|
if ( (gfn >= d->dirty_vram->begin_pfn) && (gfn < d->dirty_vram->end_pfn) ) {
|
|
unsigned long i = gfn - d->dirty_vram->begin_pfn;
|
|
struct page_info *page = mfn_to_page(mfn);
|
|
- u32 count_info = page->u.inuse.type_info & PGT_count_mask;
|
|
int dirty = 0;
|
|
paddr_t sl1ma = pfn_to_paddr(mfn_x(sl1mfn))
|
|
| ((unsigned long)sl1e & ~PAGE_MASK);
|
|
|
|
- if ( count_info == 1 ) {
|
|
+ if ( (page->u.inuse.type_info & PGT_count_mask) == 1 ) {
|
|
/* Last reference */
|
|
if ( d->dirty_vram->sl1ma[i] == INVALID_PADDR ) {
|
|
/* We didn't know it was that one, let's say it is dirty */
|
|
--- a/xen/arch/x86/mm/shadow/private.h
|
|
+++ b/xen/arch/x86/mm/shadow/private.h
|
|
@@ -201,12 +201,11 @@ struct shadow_page_info
|
|
u32 tlbflush_timestamp;
|
|
};
|
|
struct {
|
|
- unsigned int type:5; /* What kind of shadow is this? */
|
|
- unsigned int pinned:1; /* Is the shadow pinned? */
|
|
- unsigned int count:26; /* Reference count */
|
|
- u32 mbz; /* Must be zero: this is where the
|
|
- * owner field lives in page_info */
|
|
- } __attribute__((packed));
|
|
+ unsigned long mbz; /* Must be zero: count_info is here. */
|
|
+ unsigned long type:5; /* What kind of shadow is this? */
|
|
+ unsigned long pinned:1; /* Is the shadow pinned? */
|
|
+ unsigned long count:26; /* Reference count */
|
|
+ };
|
|
union {
|
|
/* For unused shadow pages, a list of pages of this order; for
|
|
* pinnable shadows, if pinned, a list of other pinned shadows
|
|
@@ -229,7 +228,7 @@ static inline void shadow_check_page_str
|
|
BUILD_BUG_ON(sizeof (struct shadow_page_info) !=
|
|
sizeof (struct page_info));
|
|
BUILD_BUG_ON(offsetof(struct shadow_page_info, mbz) !=
|
|
- offsetof(struct page_info, u.inuse._domain));
|
|
+ offsetof(struct page_info, count_info));
|
|
};
|
|
|
|
/* Shadow type codes */
|
|
--- a/xen/arch/x86/x86_32/mm.c
|
|
+++ b/xen/arch/x86/x86_32/mm.c
|
|
@@ -159,15 +159,6 @@ void __init subarch_init_memory(void)
|
|
unsigned long m2p_start_mfn;
|
|
unsigned int i, j;
|
|
|
|
- /*
|
|
- * We are rather picky about the layout of 'struct page_info'. The
|
|
- * count_info and domain fields must be adjacent, as we perform atomic
|
|
- * 64-bit operations on them. Also, just for sanity, we assert the size
|
|
- * of the structure here.
|
|
- */
|
|
- BUILD_BUG_ON(offsetof(struct page_info, u.inuse._domain) !=
|
|
- (offsetof(struct page_info, count_info) + sizeof(u32)));
|
|
- BUILD_BUG_ON((offsetof(struct page_info, count_info) & 7) != 0);
|
|
BUILD_BUG_ON(sizeof(struct page_info) != 24);
|
|
|
|
/* M2P table is mappable read-only by privileged domains. */
|
|
--- a/xen/arch/x86/x86_64/mm.c
|
|
+++ b/xen/arch/x86/x86_64/mm.c
|
|
@@ -225,17 +225,6 @@ void __init subarch_init_memory(void)
|
|
l3_pgentry_t l3e;
|
|
l2_pgentry_t l2e;
|
|
|
|
- /*
|
|
- * We are rather picky about the layout of 'struct page_info'. The
|
|
- * count_info and domain fields must be adjacent, as we perform atomic
|
|
- * 64-bit operations on them.
|
|
- */
|
|
- BUILD_BUG_ON(offsetof(struct page_info, u.inuse._domain) !=
|
|
- (offsetof(struct page_info, count_info) + sizeof(u32)));
|
|
- BUILD_BUG_ON((offsetof(struct page_info, count_info) & 7) != 0);
|
|
- BUILD_BUG_ON(sizeof(struct page_info) !=
|
|
- (32 + BITS_TO_LONGS(NR_CPUS)*sizeof(long)));
|
|
-
|
|
/* M2P table is mappable read-only by privileged domains. */
|
|
for ( v = RDWR_MPT_VIRT_START;
|
|
v != RDWR_MPT_VIRT_END;
|
|
--- a/xen/common/xenoprof.c
|
|
+++ b/xen/common/xenoprof.c
|
|
@@ -142,8 +142,8 @@ share_xenoprof_page_with_guest(struct do
|
|
struct page_info *page = mfn_to_page(mfn + i);
|
|
if ( (page->count_info & (PGC_allocated|PGC_count_mask)) != 0 )
|
|
{
|
|
- gdprintk(XENLOG_INFO, "mfn 0x%lx page->count_info 0x%x\n",
|
|
- mfn + i, page->count_info);
|
|
+ gdprintk(XENLOG_INFO, "mfn 0x%lx page->count_info 0x%lx\n",
|
|
+ mfn + i, (unsigned long)page->count_info);
|
|
return -EBUSY;
|
|
}
|
|
page_set_owner(page, NULL);
|
|
--- a/xen/include/asm-x86/mm.h
|
|
+++ b/xen/include/asm-x86/mm.h
|
|
@@ -23,7 +23,7 @@ struct page_info
|
|
struct list_head list;
|
|
|
|
/* Reference count and various PGC_xxx flags and fields. */
|
|
- u32 count_info;
|
|
+ unsigned long count_info;
|
|
|
|
/* Context-dependent fields follow... */
|
|
union {
|
|
@@ -34,7 +34,7 @@ struct page_info
|
|
u32 _domain; /* pickled format */
|
|
/* Type reference count and various PGT_xxx flags and fields. */
|
|
unsigned long type_info;
|
|
- } __attribute__ ((packed)) inuse;
|
|
+ } inuse;
|
|
|
|
/* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
|
|
struct {
|
|
@@ -42,7 +42,7 @@ struct page_info
|
|
u32 order;
|
|
/* Mask of possibly-tainted TLBs. */
|
|
cpumask_t cpumask;
|
|
- } __attribute__ ((packed)) free;
|
|
+ } free;
|
|
|
|
} u;
|
|
|
|
@@ -102,48 +102,53 @@ struct page_info
|
|
};
|
|
};
|
|
|
|
+#define PG_shift(idx) (BITS_PER_LONG - (idx))
|
|
+#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
|
|
+
|
|
/* The following page types are MUTUALLY EXCLUSIVE. */
|
|
-#define PGT_none (0U<<29) /* no special uses of this page */
|
|
-#define PGT_l1_page_table (1U<<29) /* using this page as an L1 page table? */
|
|
-#define PGT_l2_page_table (2U<<29) /* using this page as an L2 page table? */
|
|
-#define PGT_l3_page_table (3U<<29) /* using this page as an L3 page table? */
|
|
-#define PGT_l4_page_table (4U<<29) /* using this page as an L4 page table? */
|
|
-#define PGT_seg_desc_page (5U<<29) /* using this page in a GDT/LDT? */
|
|
-#define PGT_writable_page (7U<<29) /* has writable mappings of this page? */
|
|
-#define PGT_type_mask (7U<<29) /* Bits 29-31. */
|
|
+#define PGT_none PG_mask(0, 3) /* no special uses of this page */
|
|
+#define PGT_l1_page_table PG_mask(1, 3) /* using as an L1 page table? */
|
|
+#define PGT_l2_page_table PG_mask(2, 3) /* using as an L2 page table? */
|
|
+#define PGT_l3_page_table PG_mask(3, 3) /* using as an L3 page table? */
|
|
+#define PGT_l4_page_table PG_mask(4, 3) /* using as an L4 page table? */
|
|
+#define PGT_seg_desc_page PG_mask(5, 3) /* using this page in a GDT/LDT? */
|
|
+#define PGT_writable_page PG_mask(7, 3) /* has writable mappings? */
|
|
+#define PGT_type_mask PG_mask(7, 3) /* Bits 29-31. */
|
|
|
|
/* Owning guest has pinned this page to its current type? */
|
|
-#define _PGT_pinned 28
|
|
-#define PGT_pinned (1U<<_PGT_pinned)
|
|
+#define _PGT_pinned PG_shift(4)
|
|
+#define PGT_pinned PG_mask(1, 4)
|
|
/* Has this page been validated for use as its current type? */
|
|
-#define _PGT_validated 27
|
|
-#define PGT_validated (1U<<_PGT_validated)
|
|
+#define _PGT_validated PG_shift(5)
|
|
+#define PGT_validated PG_mask(1, 5)
|
|
/* PAE only: is this an L2 page directory containing Xen-private mappings? */
|
|
-#define _PGT_pae_xen_l2 26
|
|
-#define PGT_pae_xen_l2 (1U<<_PGT_pae_xen_l2)
|
|
+#define _PGT_pae_xen_l2 PG_shift(6)
|
|
+#define PGT_pae_xen_l2 PG_mask(1, 6)
|
|
/* Has this page been *partially* validated for use as its current type? */
|
|
-#define _PGT_partial 25
|
|
-#define PGT_partial (1U<<_PGT_partial)
|
|
+#define _PGT_partial PG_shift(7)
|
|
+#define PGT_partial PG_mask(1, 7)
|
|
|
|
- /* 25-bit count of uses of this frame as its current type. */
|
|
-#define PGT_count_mask ((1U<<25)-1)
|
|
+ /* Count of uses of this frame as its current type. */
|
|
+#define PGT_count_width PG_shift(7)
|
|
+#define PGT_count_mask ((1UL<<PGT_count_width)-1)
|
|
|
|
/* Cleared when the owning guest 'frees' this page. */
|
|
-#define _PGC_allocated 31
|
|
-#define PGC_allocated (1U<<_PGC_allocated)
|
|
+#define _PGC_allocated PG_shift(1)
|
|
+#define PGC_allocated PG_mask(1, 1)
|
|
#if defined(__i386__)
|
|
/* Page is locked? */
|
|
-# define _PGC_locked 30
|
|
-# define PGC_locked (1U<<_PGC_out_of_sync)
|
|
+# define _PGC_locked PG_shift(2)
|
|
+# define PGC_locked PG_mask(1, 2)
|
|
#endif
|
|
/* Set when is using a page as a page table */
|
|
-#define _PGC_page_table 29
|
|
-#define PGC_page_table (1U<<_PGC_page_table)
|
|
+#define _PGC_page_table PG_shift(3)
|
|
+#define PGC_page_table PG_mask(1, 3)
|
|
/* 3-bit PAT/PCD/PWT cache-attribute hint. */
|
|
-#define PGC_cacheattr_base 26
|
|
-#define PGC_cacheattr_mask (7U<<PGC_cacheattr_base)
|
|
- /* 26-bit count of references to this frame. */
|
|
-#define PGC_count_mask ((1U<<26)-1)
|
|
+#define PGC_cacheattr_base PG_shift(6)
|
|
+#define PGC_cacheattr_mask PG_mask(7, 6)
|
|
+ /* Count of references to this frame. */
|
|
+#define PGC_count_width PG_shift(6)
|
|
+#define PGC_count_mask ((1UL<<PGC_count_width)-1)
|
|
|
|
#define is_xen_heap_page(page) is_xen_heap_mfn(page_to_mfn(page))
|
|
#define is_xen_heap_mfn(mfn) ({ \
|