diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/domain_page.c index efda6af..d297037 100644 --- a/xen/arch/x86/domain_page.c +++ b/xen/arch/x86/domain_page.c @@ -14,6 +14,7 @@ #include #include #include +#include static struct vcpu *__read_mostly override; @@ -59,12 +60,12 @@ void __init mapcache_override_current(struct vcpu *v) void *map_domain_page(unsigned long mfn) { unsigned long flags; - unsigned int idx, i; + unsigned int idx, i, j = 0; struct vcpu *v; struct mapcache_domain *dcache; struct mapcache_vcpu *vcache; struct vcpu_maphash_entry *hashent; - + int branch = 0; #ifdef NDEBUG if ( mfn <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) ) return mfn_to_virt(mfn); @@ -115,31 +116,102 @@ void *map_domain_page(unsigned long mfn) /* /First/, clean the garbage map and update the inuse list. */ for ( i = 0; i < BITS_TO_LONGS(dcache->entries); i++ ) { + unsigned long garbage = dcache->garbage[i]; + unsigned long _inuse = dcache->inuse[i]; + barrier(); dcache->inuse[i] &= ~xchg(&dcache->garbage[i], 0); + if (v->domain->domain_id) { + if (~dcache->inuse[i]) { + gdprintk(XENLOG_INFO, "mfn: %lx, [%d]: %lx->%lx, garbage: %lx -> ~%lx, idx: %d, ~garbage: %lx \n", mfn, i, _inuse, dcache->inuse[i], garbage, ~dcache->inuse[i], + find_first_zero_bit(dcache->inuse, dcache->entries),~garbage); + branch |= 8; + } + } accum |= ~dcache->inuse[i]; } - if ( accum ) + if ( accum ) { idx = find_first_zero_bit(dcache->inuse, dcache->entries); + branch |= 1; + } else { + branch |= 2; /* Replace a hash entry instead. */ i = MAPHASH_HASHFN(mfn); do { hashent = &vcache->hash[i]; if ( hashent->idx != MAPHASHENT_NOTINUSE && !hashent->refcnt ) { + branch |= 4; idx = hashent->idx; ASSERT(l1e_get_pfn(MAPCACHE_L1ENT(idx)) == hashent->mfn); l1e_write(&MAPCACHE_L1ENT(idx), l1e_empty()); hashent->idx = MAPHASHENT_NOTINUSE; hashent->mfn = ~0UL; + if (idx >= dcache->entries) { + branch |= 8; + gdprintk(XENLOG_INFO, "mfn (%lx) -> %ld idx (iter:%d)\n", mfn, MAPHASH_HASHFN(mfn), j); + + for (i = 0; i < MAPHASH_ENTRIES;i++) { + hashent = &vcache->hash[i]; + + gdprintk(XENLOG_INFO, "[%d] idx=%d, mfn=0x%lx, refcnt: %d\n", + i, hashent->idx, hashent->mfn, hashent->refcnt); + } + } break; } if ( ++i == MAPHASH_ENTRIES ) i = 0; + j++; } while ( i != MAPHASH_HASHFN(mfn) ); } + if (idx >= dcache->entries) { + unsigned long _mfn; + const char *name; + unsigned long offset, size; + + static char namebuf[KSYM_NAME_LEN+1]; + #define BUFFER_SIZE sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN + \ + 2*(BITS_PER_LONG*3/10) + 1 + static char buffer[BUFFER_SIZE]; + + + + gdprintk(XENLOG_INFO, "mfn (%lx) -> %ld idx: %d(i:%d,j:%d), branch:%x 0x%lx\n", mfn, MAPHASH_HASHFN(mfn), idx, i, j, branch, accum); + + for (i = 0; i < dcache->entries; i++) { + int in_mapcache = 0; + _mfn = l1e_get_pfn(MAPCACHE_L1ENT(i)); + hashent = NULL; + + for (j = 0; j < MAPHASH_ENTRIES;j++) { + hashent = &vcache->hash[j]; + + if (hashent->mfn == _mfn) { + in_mapcache = 1; + break; + } + } + if (i <= 32 && dcache->ips[i]) { + name = symbols_lookup(dcache->ips[i], &size, &offset, namebuf); + + if (!name) + snprintf(buffer, BUFFER_SIZE, "0x%lx", dcache->ips[i]); + else + snprintf(buffer, BUFFER_SIZE, "%s+%#lx/%#lx", name, offset, size); + } else + snprintf(buffer, BUFFER_SIZE, "EIP=0"); + + if (in_mapcache) + gdprintk(XENLOG_INFO, "[%d] mfn=0x%lx idx=%d, mfn=0x%lx, refcnt: %d [%s]\n", + i, _mfn, hashent->idx, hashent->mfn, hashent->refcnt, buffer); + else + gdprintk(XENLOG_INFO, "[%d] mfn=%lx, [%s]\n", i, _mfn, buffer); + } + + } BUG_ON(idx >= dcache->entries); /* /Second/, flush TLBs. */ @@ -152,6 +224,9 @@ void *map_domain_page(unsigned long mfn) set_bit(idx, dcache->inuse); dcache->cursor = idx + 1; + if (v->domain->domain_id && idx <= 32) + dcache->ips[idx] = (unsigned long)__builtin_return_address(0); + spin_unlock(&dcache->lock); l1e_write(&MAPCACHE_L1ENT(idx), l1e_from_pfn(mfn, __PAGE_HYPERVISOR)); @@ -215,7 +290,8 @@ void unmap_domain_page(const void *ptr) /* /Second/, mark as garbage. */ set_bit(idx, dcache->garbage); } - + if (v->domain->domain_id && idx <= 32) + dcache->ips[idx] = 0; local_irq_restore(flags); } @@ -254,6 +330,7 @@ int mapcache_domain_init(struct domain *d) 2 * PFN_UP(BITS_TO_LONGS(MAPCACHE_ENTRIES) * sizeof(long))) > MAPCACHE_VIRT_START + (PERDOMAIN_SLOT_MBYTES << 20)); bitmap_pages = PFN_UP(BITS_TO_LONGS(MAPCACHE_ENTRIES) * sizeof(long)); + gdprintk(XENLOG_INFO, "domain bitmap pages: %d\n", bitmap_pages); dcache->inuse = (void *)MAPCACHE_VIRT_END + PAGE_SIZE; dcache->garbage = dcache->inuse + (bitmap_pages + 1) * PAGE_SIZE / sizeof(long); @@ -276,6 +353,7 @@ int mapcache_vcpu_init(struct vcpu *v) if ( is_hvm_vcpu(v) || !dcache->inuse ) return 0; + gdprintk(XENLOG_INFO, "ents: %d, entries: %d\n", ents, dcache->entries); if ( ents > dcache->entries ) { /* Populate page tables. */ diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index d79464d..5389ea9 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -67,6 +67,7 @@ struct mapcache_domain { /* Which mappings are in use, and which are garbage to reap next epoch? */ unsigned long *inuse; unsigned long *garbage; + unsigned long ips[33]; }; int mapcache_domain_init(struct domain *);