mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
merge
This commit is contained in:
commit
e6bde27c82
47 files changed
+1377
-681
No files matched your search
@@ -1,8 +1,6 @@
|
||||
XEN_ROOT = ../../..
|
||||
include ./Rules.mk
|
||||
|
||||
sbindir=/usr/sbin
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) -C gx
|
||||
@@ -16,8 +14,8 @@ clean:
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
[ -d $(DESTDIR)$(sbindir) ] || $(INSTALL_DIR) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL_PROG) gdbsx $(DESTDIR)$(sbindir)/gdbsx
|
||||
[ -d $(DESTDIR)$(SBINDIR) ] || $(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
|
||||
$(INSTALL_PROG) gdbsx $(DESTDIR)$(SBINDIR)/gdbsx
|
||||
|
||||
gdbsx: gx/gx_all.a xg/xg_all.a
|
||||
$(CC) -o $@ $^
|
||||
|
||||
@@ -61,7 +61,7 @@ dbg_hvm_va2mfn(dbgva_t vaddr, struct domain *dp, int toaddr)
|
||||
return INVALID_MFN;
|
||||
}
|
||||
|
||||
mfn = mfn_x(gfn_to_mfn(dp, gfn, &gfntype));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(dp), gfn, &gfntype));
|
||||
if ( p2m_is_readonly(gfntype) && toaddr )
|
||||
{
|
||||
DBGP2("kdb:p2m_is_readonly: gfntype:%x\n", gfntype);
|
||||
|
||||
@@ -151,7 +151,7 @@ void dump_pageframe_info(struct domain *d)
|
||||
|
||||
if ( is_hvm_domain(d) )
|
||||
{
|
||||
p2m_pod_dump_data(d);
|
||||
p2m_pod_dump_data(p2m_get_hostp2m(d));
|
||||
}
|
||||
|
||||
spin_lock(&d->page_alloc_lock);
|
||||
|
||||
@@ -982,7 +982,7 @@ long arch_do_domctl(
|
||||
|
||||
ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
|
||||
for ( i = 0; i < nr_mfns; i++ )
|
||||
set_mmio_p2m_entry(d, gfn+i, _mfn(mfn+i));
|
||||
set_mmio_p2m_entry(p2m_get_hostp2m(d), gfn+i, _mfn(mfn+i));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -991,7 +991,7 @@ long arch_do_domctl(
|
||||
gfn, mfn, nr_mfns);
|
||||
|
||||
for ( i = 0; i < nr_mfns; i++ )
|
||||
clear_mmio_p2m_entry(d, gfn+i);
|
||||
clear_mmio_p2m_entry(p2m_get_hostp2m(d), gfn+i);
|
||||
ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ int hvmemul_do_io(
|
||||
paddr_t value = ram_gpa;
|
||||
int value_is_ptr = (p_data == NULL);
|
||||
struct vcpu *curr = current;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(curr->domain);
|
||||
ioreq_t *p = get_ioreq(curr);
|
||||
unsigned long ram_gfn = paddr_to_pfn(ram_gpa);
|
||||
p2m_type_t p2mt;
|
||||
@@ -62,10 +63,10 @@ int hvmemul_do_io(
|
||||
int rc;
|
||||
|
||||
/* Check for paged out page */
|
||||
ram_mfn = gfn_to_mfn_unshare(current->domain, ram_gfn, &p2mt, 0);
|
||||
ram_mfn = gfn_to_mfn_unshare(p2m, ram_gfn, &p2mt, 0);
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(curr->domain, ram_gfn);
|
||||
p2m_mem_paging_populate(p2m, ram_gfn);
|
||||
return X86EMUL_RETRY;
|
||||
}
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
@@ -638,6 +639,7 @@ static int hvmemul_rep_movs(
|
||||
unsigned long saddr, daddr, bytes;
|
||||
paddr_t sgpa, dgpa;
|
||||
uint32_t pfec = PFEC_page_present;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(current->domain);
|
||||
p2m_type_t p2mt;
|
||||
int rc, df = !!(ctxt->regs->eflags & X86_EFLAGS_DF);
|
||||
char *buf;
|
||||
@@ -668,12 +670,12 @@ static int hvmemul_rep_movs(
|
||||
if ( rc != X86EMUL_OKAY )
|
||||
return rc;
|
||||
|
||||
(void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
|
||||
(void)gfn_to_mfn(p2m, sgpa >> PAGE_SHIFT, &p2mt);
|
||||
if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
|
||||
return hvmemul_do_mmio(
|
||||
sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ, df, NULL);
|
||||
|
||||
(void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
|
||||
(void)gfn_to_mfn(p2m, dgpa >> PAGE_SHIFT, &p2mt);
|
||||
if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
|
||||
return hvmemul_do_mmio(
|
||||
dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE, df, NULL);
|
||||
|
||||
+55
-41
@@ -335,16 +335,17 @@ static int hvm_set_ioreq_page(
|
||||
struct domain *d, struct hvm_ioreq_page *iorp, unsigned long gmfn)
|
||||
{
|
||||
struct page_info *page;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
p2m_type_t p2mt;
|
||||
unsigned long mfn;
|
||||
void *va;
|
||||
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(d, gmfn, &p2mt, 0));
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(p2m, gmfn, &p2mt, 0));
|
||||
if ( !p2m_is_ram(p2mt) )
|
||||
return -EINVAL;
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(d, gmfn);
|
||||
p2m_mem_paging_populate(p2m, gmfn);
|
||||
return -ENOENT;
|
||||
}
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
@@ -968,8 +969,10 @@ bool_t hvm_hap_nested_page_fault(unsigned long gfn)
|
||||
{
|
||||
p2m_type_t p2mt;
|
||||
mfn_t mfn;
|
||||
struct vcpu *v = current;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
|
||||
mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest);
|
||||
mfn = gfn_to_mfn_guest(p2m, gfn, &p2mt);
|
||||
|
||||
/*
|
||||
* If this GFN is emulated MMIO or marked as read-only, pass the fault
|
||||
@@ -985,12 +988,12 @@ bool_t hvm_hap_nested_page_fault(unsigned long gfn)
|
||||
#ifdef __x86_64__
|
||||
/* Check if the page has been paged out */
|
||||
if ( p2m_is_paged(p2mt) || (p2mt == p2m_ram_paging_out) )
|
||||
p2m_mem_paging_populate(current->domain, gfn);
|
||||
p2m_mem_paging_populate(p2m, gfn);
|
||||
|
||||
/* Mem sharing: unshare the page and try again */
|
||||
if ( p2mt == p2m_ram_shared )
|
||||
{
|
||||
mem_sharing_unshare_page(current->domain, gfn, 0);
|
||||
mem_sharing_unshare_page(p2m, gfn, 0);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -1003,8 +1006,8 @@ bool_t hvm_hap_nested_page_fault(unsigned long gfn)
|
||||
* a large page, we do not change other pages type within that large
|
||||
* page.
|
||||
*/
|
||||
paging_mark_dirty(current->domain, mfn_x(mfn));
|
||||
p2m_change_type(current->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);
|
||||
paging_mark_dirty(v->domain, mfn_x(mfn));
|
||||
p2m_change_type(p2m, gfn, p2m_ram_logdirty, p2m_ram_rw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1088,6 +1091,7 @@ int hvm_set_cr0(unsigned long value)
|
||||
{
|
||||
struct vcpu *v = current;
|
||||
p2m_type_t p2mt;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
unsigned long gfn, mfn, old_value = v->arch.hvm_vcpu.guest_cr[0];
|
||||
|
||||
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value);
|
||||
@@ -1126,7 +1130,7 @@ int hvm_set_cr0(unsigned long value)
|
||||
{
|
||||
/* The guest CR3 must be pointing to the guest physical. */
|
||||
gfn = v->arch.hvm_vcpu.guest_cr[3]>>PAGE_SHIFT;
|
||||
mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m, gfn, &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) || !mfn_valid(mfn) ||
|
||||
!get_page(mfn_to_page(mfn), v->domain))
|
||||
{
|
||||
@@ -1213,7 +1217,8 @@ int hvm_set_cr3(unsigned long value)
|
||||
{
|
||||
/* Shadow-mode CR3 change. Check PDBR and update refcounts. */
|
||||
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx", value);
|
||||
mfn = mfn_x(gfn_to_mfn_current(value >> PAGE_SHIFT, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(v->domain),
|
||||
value >> PAGE_SHIFT, &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) || !mfn_valid(mfn) ||
|
||||
!get_page(mfn_to_page(mfn), v->domain) )
|
||||
goto bad_cr3;
|
||||
@@ -1356,6 +1361,8 @@ static void *hvm_map_entry(unsigned long va)
|
||||
unsigned long gfn, mfn;
|
||||
p2m_type_t p2mt;
|
||||
uint32_t pfec;
|
||||
struct vcpu *v = current;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
|
||||
if ( ((va & ~PAGE_MASK) + 8) > PAGE_SIZE )
|
||||
{
|
||||
@@ -1372,10 +1379,10 @@ static void *hvm_map_entry(unsigned long va)
|
||||
gfn = paging_gva_to_gfn(current, va, &pfec);
|
||||
if ( pfec == PFEC_page_paged || pfec == PFEC_page_shared )
|
||||
return NULL;
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(current->domain, gfn, &p2mt, 0));
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(p2m, gfn, &p2mt, 0));
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(current->domain, gfn);
|
||||
p2m_mem_paging_populate(p2m, gfn);
|
||||
return NULL;
|
||||
}
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
@@ -1742,6 +1749,7 @@ static enum hvm_copy_result __hvm_copy(
|
||||
void *buf, paddr_t addr, int size, unsigned int flags, uint32_t pfec)
|
||||
{
|
||||
struct vcpu *curr = current;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(curr->domain);
|
||||
unsigned long gfn, mfn;
|
||||
p2m_type_t p2mt;
|
||||
char *p;
|
||||
@@ -1770,11 +1778,11 @@ static enum hvm_copy_result __hvm_copy(
|
||||
gfn = addr >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(current->domain, gfn, &p2mt, 0));
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(p2m, gfn, &p2mt, 0));
|
||||
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(curr->domain, gfn);
|
||||
p2m_mem_paging_populate(p2m, gfn);
|
||||
return HVMCOPY_gfn_paged_out;
|
||||
}
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
@@ -2021,7 +2029,7 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
|
||||
uint64_t *var_range_base, *fixed_range_base;
|
||||
int index, mtrr;
|
||||
uint32_t cpuid[4];
|
||||
int ret;
|
||||
int ret = X86EMUL_OKAY;
|
||||
|
||||
var_range_base = (uint64_t *)v->arch.hvm_vcpu.mtrr.var_ranges;
|
||||
fixed_range_base = (uint64_t *)v->arch.hvm_vcpu.mtrr.fixed_ranges;
|
||||
@@ -2094,24 +2102,25 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = vmce_rdmsr(msr, msr_content);
|
||||
if ( ret < 0 )
|
||||
if ( (ret = vmce_rdmsr(msr, msr_content)) < 0 )
|
||||
goto gp_fault;
|
||||
else if ( ret )
|
||||
break;
|
||||
/* ret == 0, This is not an MCE MSR, see other MSRs */
|
||||
else if (!ret) {
|
||||
return hvm_funcs.msr_read_intercept(msr, msr_content);
|
||||
}
|
||||
/* If ret == 0 then this is not an MCE MSR, see other MSRs. */
|
||||
ret = ((ret == 0)
|
||||
? hvm_funcs.msr_read_intercept(msr, msr_content)
|
||||
: X86EMUL_OKAY);
|
||||
break;
|
||||
}
|
||||
|
||||
HVMTRACE_3D(MSR_READ, (uint32_t)*msr_content, (uint32_t)(*msr_content >> 32), msr);
|
||||
out:
|
||||
HVMTRACE_3D(MSR_READ, msr,
|
||||
(uint32_t)*msr_content, (uint32_t)(*msr_content >> 32));
|
||||
return ret;
|
||||
|
||||
return X86EMUL_OKAY;
|
||||
|
||||
gp_fault:
|
||||
gp_fault:
|
||||
hvm_inject_exception(TRAP_gp_fault, 0, 0);
|
||||
return X86EMUL_EXCEPTION;
|
||||
ret = X86EMUL_EXCEPTION;
|
||||
*msr_content = -1ull;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
@@ -2119,9 +2128,10 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
struct vcpu *v = current;
|
||||
int index, mtrr;
|
||||
uint32_t cpuid[4];
|
||||
int ret;
|
||||
int ret = X86EMUL_OKAY;
|
||||
|
||||
HVMTRACE_3D(MSR_WRITE, (uint32_t)msr_content, (uint32_t)(msr_content >> 32), msr);
|
||||
HVMTRACE_3D(MSR_WRITE, msr,
|
||||
(uint32_t)msr_content, (uint32_t)(msr_content >> 32));
|
||||
|
||||
hvm_cpuid(1, &cpuid[0], &cpuid[1], &cpuid[2], &cpuid[3]);
|
||||
mtrr = !!(cpuid[3] & bitmaskof(X86_FEATURE_MTRR));
|
||||
@@ -2194,16 +2204,16 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = vmce_wrmsr(msr, msr_content);
|
||||
if ( ret < 0 )
|
||||
if ( (ret = vmce_wrmsr(msr, msr_content)) < 0 )
|
||||
goto gp_fault;
|
||||
else if ( ret )
|
||||
break;
|
||||
else if (!ret)
|
||||
return hvm_funcs.msr_write_intercept(msr, msr_content);
|
||||
/* If ret == 0 then this is not an MCE MSR, see other MSRs. */
|
||||
ret = ((ret == 0)
|
||||
? hvm_funcs.msr_write_intercept(msr, msr_content)
|
||||
: X86EMUL_OKAY);
|
||||
break;
|
||||
}
|
||||
|
||||
return X86EMUL_OKAY;
|
||||
return ret;
|
||||
|
||||
gp_fault:
|
||||
hvm_inject_exception(TRAP_gp_fault, 0, 0);
|
||||
@@ -3029,6 +3039,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct xen_hvm_modified_memory a;
|
||||
struct domain *d;
|
||||
struct p2m_domain *p2m;
|
||||
unsigned long pfn;
|
||||
|
||||
if ( copy_from_guest(&a, arg, 1) )
|
||||
@@ -3056,13 +3067,14 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
if ( !paging_mode_log_dirty(d) )
|
||||
goto param_fail3;
|
||||
|
||||
p2m = p2m_get_hostp2m(d);
|
||||
for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
|
||||
{
|
||||
p2m_type_t t;
|
||||
mfn_t mfn = gfn_to_mfn(d, pfn, &t);
|
||||
mfn_t mfn = gfn_to_mfn(p2m, pfn, &t);
|
||||
if ( p2m_is_paging(t) )
|
||||
{
|
||||
p2m_mem_paging_populate(d, pfn);
|
||||
p2m_mem_paging_populate(p2m, pfn);
|
||||
|
||||
rc = -EINVAL;
|
||||
goto param_fail3;
|
||||
@@ -3089,6 +3101,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct xen_hvm_set_mem_type a;
|
||||
struct domain *d;
|
||||
struct p2m_domain *p2m;
|
||||
unsigned long pfn;
|
||||
|
||||
/* Interface types to internal p2m types */
|
||||
@@ -3118,15 +3131,16 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
|
||||
goto param_fail4;
|
||||
|
||||
p2m = p2m_get_hostp2m(d);
|
||||
for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
|
||||
{
|
||||
p2m_type_t t;
|
||||
p2m_type_t nt;
|
||||
mfn_t mfn;
|
||||
mfn = gfn_to_mfn_unshare(d, pfn, &t, 0);
|
||||
mfn = gfn_to_mfn_unshare(p2m, pfn, &t, 0);
|
||||
if ( p2m_is_paging(t) )
|
||||
{
|
||||
p2m_mem_paging_populate(d, pfn);
|
||||
p2m_mem_paging_populate(p2m, pfn);
|
||||
|
||||
rc = -EINVAL;
|
||||
goto param_fail4;
|
||||
@@ -3145,7 +3159,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
}
|
||||
else
|
||||
{
|
||||
nt = p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
|
||||
nt = p2m_change_type(p2m, pfn, t, memtype[a.hvmmem_type]);
|
||||
if ( nt != t )
|
||||
{
|
||||
gdprintk(XENLOG_WARNING,
|
||||
|
||||
@@ -399,7 +399,7 @@ uint32_t get_pat_flags(struct vcpu *v,
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
p2m_type_t p2mt;
|
||||
gfn_to_mfn(d, paddr_to_pfn(gpaddr), &p2mt);
|
||||
gfn_to_mfn(p2m_get_hostp2m(d), paddr_to_pfn(gpaddr), &p2mt);
|
||||
if (p2m_is_ram(p2mt))
|
||||
gdprintk(XENLOG_WARNING,
|
||||
"Conflict occurs for a given guest l1e flags:%x "
|
||||
|
||||
@@ -469,6 +469,7 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p)
|
||||
int i;
|
||||
int sign = p->df ? -1 : 1;
|
||||
p2m_type_t p2mt;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(current->domain);
|
||||
|
||||
if ( p->data_is_ptr )
|
||||
{
|
||||
@@ -481,7 +482,7 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p)
|
||||
if ( hvm_copy_to_guest_phys(data, &tmp, p->size) !=
|
||||
HVMCOPY_okay )
|
||||
{
|
||||
(void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt);
|
||||
(void)gfn_to_mfn(p2m, data >> PAGE_SHIFT, &p2mt);
|
||||
/*
|
||||
* The only case we handle is vga_mem <-> vga_mem.
|
||||
* Anything else disables caching and leaves it to qemu-dm.
|
||||
@@ -503,7 +504,7 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p)
|
||||
if ( hvm_copy_from_guest_phys(&tmp, data, p->size) !=
|
||||
HVMCOPY_okay )
|
||||
{
|
||||
(void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt);
|
||||
(void)gfn_to_mfn(p2m, data >> PAGE_SHIFT, &p2mt);
|
||||
if ( (p2mt != p2m_mmio_dm) || (data < VGA_MEM_BASE) ||
|
||||
((data + p->size) > (VGA_MEM_BASE + VGA_MEM_SIZE)) )
|
||||
return 0;
|
||||
|
||||
@@ -232,7 +232,7 @@ static int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c)
|
||||
{
|
||||
if ( c->cr0 & X86_CR0_PG )
|
||||
{
|
||||
mfn = mfn_x(gfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m, c->cr3 >> PAGE_SHIFT, &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) || !get_page(mfn_to_page(mfn), v->domain) )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%"PRIx64"\n",
|
||||
@@ -946,6 +946,9 @@ static void svm_do_nested_pgfault(paddr_t gpa)
|
||||
unsigned long gfn = gpa >> PAGE_SHIFT;
|
||||
mfn_t mfn;
|
||||
p2m_type_t p2mt;
|
||||
struct p2m_domain *p2m;
|
||||
|
||||
p2m = p2m_get_hostp2m(current->domain);
|
||||
|
||||
if ( tb_init_done )
|
||||
{
|
||||
@@ -958,7 +961,7 @@ static void svm_do_nested_pgfault(paddr_t gpa)
|
||||
|
||||
_d.gpa = gpa;
|
||||
_d.qualification = 0;
|
||||
_d.mfn = mfn_x(gfn_to_mfn_query(current->domain, gfn, &_d.p2mt));
|
||||
_d.mfn = mfn_x(gfn_to_mfn_query(p2m, gfn, &_d.p2mt));
|
||||
|
||||
__trace_var(TRC_HVM_NPF, 0, sizeof(_d), (unsigned char *)&_d);
|
||||
}
|
||||
@@ -967,7 +970,7 @@ static void svm_do_nested_pgfault(paddr_t gpa)
|
||||
return;
|
||||
|
||||
/* Everything else is an error. */
|
||||
mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest);
|
||||
mfn = gfn_to_mfn_guest(p2m, gfn, &p2mt);
|
||||
gdprintk(XENLOG_ERR, "SVM violation gpa %#"PRIpaddr", mfn %#lx, type %i\n",
|
||||
gpa, mfn_x(mfn), p2mt);
|
||||
domain_crash(current->domain);
|
||||
@@ -1117,8 +1120,6 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
|
||||
goto gpf;
|
||||
}
|
||||
|
||||
HVMTRACE_3D (MSR_READ, msr,
|
||||
(uint32_t)*msr_content, (uint32_t)(*msr_content>>32));
|
||||
HVM_DBG_LOG(DBG_LEVEL_1, "returns: ecx=%x, msr_value=%"PRIx64,
|
||||
msr, *msr_content);
|
||||
return X86EMUL_OKAY;
|
||||
@@ -1133,9 +1134,6 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
struct vcpu *v = current;
|
||||
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
|
||||
|
||||
HVMTRACE_3D(MSR_WRITE, msr,
|
||||
(uint32_t)msr_content, (uint32_t)(msr_content >> 32));
|
||||
|
||||
switch ( msr )
|
||||
{
|
||||
case MSR_K8_VM_HSAVE_PA:
|
||||
|
||||
+29
-9
@@ -159,7 +159,10 @@ struct msixtbl_entry
|
||||
unsigned long gtable; /* gpa of msix table */
|
||||
unsigned long table_len;
|
||||
unsigned long table_flags[MAX_MSIX_TABLE_ENTRIES / BITS_PER_LONG + 1];
|
||||
|
||||
#define MAX_MSIX_ACC_ENTRIES 3
|
||||
struct {
|
||||
uint32_t msi_ad[3]; /* Shadow of address low, high and data */
|
||||
} gentries[MAX_MSIX_ACC_ENTRIES];
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
@@ -205,9 +208,10 @@ static int msixtbl_read(
|
||||
struct vcpu *v, unsigned long address,
|
||||
unsigned long len, unsigned long *pval)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long offset, val;
|
||||
struct msixtbl_entry *entry;
|
||||
void *virt;
|
||||
int nr_entry, index;
|
||||
int r = X86EMUL_UNHANDLEABLE;
|
||||
|
||||
rcu_read_lock(&msixtbl_rcu_lock);
|
||||
@@ -215,18 +219,29 @@ static int msixtbl_read(
|
||||
if ( len != 4 )
|
||||
goto out;
|
||||
|
||||
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
|
||||
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
|
||||
goto out;
|
||||
|
||||
entry = msixtbl_find_entry(v, address);
|
||||
virt = msixtbl_addr_to_virt(entry, address);
|
||||
if ( !virt )
|
||||
goto out;
|
||||
|
||||
*pval = readl(virt);
|
||||
r = X86EMUL_OKAY;
|
||||
nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
|
||||
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
|
||||
if ( nr_entry >= MAX_MSIX_ACC_ENTRIES &&
|
||||
offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
|
||||
goto out;
|
||||
|
||||
val = readl(virt);
|
||||
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
|
||||
{
|
||||
index = offset / sizeof(uint32_t);
|
||||
*pval = entry->gentries[nr_entry].msi_ad[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
*pval = val;
|
||||
}
|
||||
|
||||
r = X86EMUL_OKAY;
|
||||
out:
|
||||
rcu_read_unlock(&msixtbl_rcu_lock);
|
||||
return r;
|
||||
@@ -238,7 +253,7 @@ static int msixtbl_write(struct vcpu *v, unsigned long address,
|
||||
unsigned long offset;
|
||||
struct msixtbl_entry *entry;
|
||||
void *virt;
|
||||
int nr_entry;
|
||||
int nr_entry, index;
|
||||
int r = X86EMUL_UNHANDLEABLE;
|
||||
|
||||
rcu_read_lock(&msixtbl_rcu_lock);
|
||||
@@ -252,6 +267,11 @@ static int msixtbl_write(struct vcpu *v, unsigned long address,
|
||||
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
|
||||
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
|
||||
{
|
||||
if ( nr_entry < MAX_MSIX_ACC_ENTRIES )
|
||||
{
|
||||
index = offset / sizeof(uint32_t);
|
||||
entry->gentries[nr_entry].msi_ad[index] = val;
|
||||
}
|
||||
set_bit(nr_entry, &entry->table_flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
+11
-12
@@ -486,7 +486,8 @@ static int vmx_restore_cr0_cr3(
|
||||
{
|
||||
if ( cr0 & X86_CR0_PG )
|
||||
{
|
||||
mfn = mfn_x(gfn_to_mfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(v->domain),
|
||||
cr3 >> PAGE_SHIFT, &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) || !get_page(mfn_to_page(mfn), v->domain) )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%lx\n", cr3);
|
||||
@@ -1002,7 +1003,8 @@ static void vmx_load_pdptrs(struct vcpu *v)
|
||||
if ( cr3 & 0x1fUL )
|
||||
goto crash;
|
||||
|
||||
mfn = mfn_x(gfn_to_mfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(v->domain),
|
||||
cr3 >> PAGE_SHIFT, &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) )
|
||||
goto crash;
|
||||
|
||||
@@ -1221,7 +1223,7 @@ void ept_sync_domain(struct domain *d)
|
||||
return;
|
||||
|
||||
ASSERT(local_irq_is_enabled());
|
||||
ASSERT(p2m_locked_by_me(d->arch.p2m));
|
||||
ASSERT(p2m_locked_by_me(p2m_get_hostp2m(d)));
|
||||
|
||||
/*
|
||||
* Flush active cpus synchronously. Flush others the next time this domain
|
||||
@@ -1340,7 +1342,7 @@ static void vmx_set_uc_mode(struct vcpu *v)
|
||||
{
|
||||
if ( paging_mode_hap(v->domain) )
|
||||
ept_change_entry_emt_with_range(
|
||||
v->domain, 0, v->domain->arch.p2m->max_mapped_pfn);
|
||||
v->domain, 0, p2m_get_hostp2m(v->domain)->max_mapped_pfn);
|
||||
hvm_asid_flush_vcpu(v);
|
||||
}
|
||||
|
||||
@@ -1872,8 +1874,6 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
|
||||
}
|
||||
|
||||
done:
|
||||
HVMTRACE_3D(MSR_READ, msr,
|
||||
(uint32_t)*msr_content, (uint32_t)(*msr_content >> 32));
|
||||
HVM_DBG_LOG(DBG_LEVEL_1, "returns: ecx=%x, msr_value=0x%"PRIx64,
|
||||
msr, *msr_content);
|
||||
return X86EMUL_OKAY;
|
||||
@@ -1895,7 +1895,8 @@ static int vmx_alloc_vlapic_mapping(struct domain *d)
|
||||
return -ENOMEM;
|
||||
share_xen_page_with_guest(virt_to_page(apic_va), d, XENSHARE_writable);
|
||||
set_mmio_p2m_entry(
|
||||
d, paddr_to_pfn(APIC_DEFAULT_PHYS_BASE), _mfn(virt_to_mfn(apic_va)));
|
||||
p2m_get_hostp2m(d), paddr_to_pfn(APIC_DEFAULT_PHYS_BASE),
|
||||
_mfn(virt_to_mfn(apic_va)));
|
||||
d->arch.hvm_domain.vmx.apic_access_mfn = virt_to_mfn(apic_va);
|
||||
|
||||
return 0;
|
||||
@@ -1950,9 +1951,6 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, msr_value=0x%"PRIx64,
|
||||
msr, msr_content);
|
||||
|
||||
HVMTRACE_3D(MSR_WRITE, msr,
|
||||
(uint32_t)msr_content, (uint32_t)(msr_content >> 32));
|
||||
|
||||
switch ( msr )
|
||||
{
|
||||
case MSR_IA32_SYSENTER_CS:
|
||||
@@ -2103,6 +2101,7 @@ static void ept_handle_violation(unsigned long qualification, paddr_t gpa)
|
||||
unsigned long gla, gfn = gpa >> PAGE_SHIFT;
|
||||
mfn_t mfn;
|
||||
p2m_type_t p2mt;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(current->domain);
|
||||
|
||||
if ( tb_init_done )
|
||||
{
|
||||
@@ -2115,7 +2114,7 @@ static void ept_handle_violation(unsigned long qualification, paddr_t gpa)
|
||||
|
||||
_d.gpa = gpa;
|
||||
_d.qualification = qualification;
|
||||
_d.mfn = mfn_x(gfn_to_mfn_query(current->domain, gfn, &_d.p2mt));
|
||||
_d.mfn = mfn_x(gfn_to_mfn_query(p2m, gfn, &_d.p2mt));
|
||||
|
||||
__trace_var(TRC_HVM_NPF, 0, sizeof(_d), (unsigned char *)&_d);
|
||||
}
|
||||
@@ -2125,7 +2124,7 @@ static void ept_handle_violation(unsigned long qualification, paddr_t gpa)
|
||||
return;
|
||||
|
||||
/* Everything else is an error. */
|
||||
mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest);
|
||||
mfn = gfn_to_mfn_guest(p2m, gfn, &p2mt);
|
||||
gdprintk(XENLOG_ERR, "EPT violation %#lx (%c%c%c/%c%c%c), "
|
||||
"gpa %#"PRIpaddr", mfn %#lx, type %i.\n",
|
||||
qualification,
|
||||
|
||||
+32
-25
@@ -398,7 +398,7 @@ int page_is_ram_type(unsigned long mfn, unsigned long mem_type)
|
||||
unsigned long domain_get_maximum_gpfn(struct domain *d)
|
||||
{
|
||||
if ( is_hvm_domain(d) )
|
||||
return d->arch.p2m->max_mapped_pfn;
|
||||
return p2m_get_hostp2m(d)->max_mapped_pfn;
|
||||
/* NB. PV guests specify nr_pfns rather than max_pfn so we adjust here. */
|
||||
return arch_get_max_pfn(d) - 1;
|
||||
}
|
||||
@@ -1741,7 +1741,8 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e,
|
||||
if ( l1e_get_flags(nl1e) & _PAGE_PRESENT )
|
||||
{
|
||||
/* Translate foreign guest addresses. */
|
||||
mfn = mfn_x(gfn_to_mfn(pg_dom, l1e_get_pfn(nl1e), &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(pg_dom),
|
||||
l1e_get_pfn(nl1e), &p2mt));
|
||||
if ( !p2m_is_ram(p2mt) || unlikely(mfn == INVALID_MFN) )
|
||||
return 0;
|
||||
ASSERT((mfn & ~(PADDR_MASK >> PAGE_SHIFT)) == 0);
|
||||
@@ -3318,8 +3319,8 @@ int do_mmu_update(
|
||||
struct page_info *page;
|
||||
int rc = 0, okay = 1, i = 0;
|
||||
unsigned int cmd, done = 0, pt_dom;
|
||||
struct domain *d = current->domain, *pt_owner = d, *pg_owner;
|
||||
struct vcpu *v = current;
|
||||
struct domain *d = v->domain, *pt_owner = d, *pg_owner;
|
||||
struct domain_mmap_cache mapcache;
|
||||
|
||||
if ( unlikely(count & MMU_UPDATE_PREEMPTED) )
|
||||
@@ -3403,13 +3404,13 @@ int do_mmu_update(
|
||||
|
||||
req.ptr -= cmd;
|
||||
gmfn = req.ptr >> PAGE_SHIFT;
|
||||
mfn = mfn_x(gfn_to_mfn(pt_owner, gmfn, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(pt_owner), gmfn, &p2mt));
|
||||
if ( !p2m_is_valid(p2mt) )
|
||||
mfn = INVALID_MFN;
|
||||
|
||||
if ( p2m_is_paged(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(pg_owner, gmfn);
|
||||
p2m_mem_paging_populate(p2m_get_hostp2m(pg_owner), gmfn);
|
||||
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
@@ -3434,12 +3435,13 @@ int do_mmu_update(
|
||||
{
|
||||
l1_pgentry_t l1e = l1e_from_intpte(req.val);
|
||||
p2m_type_t l1e_p2mt;
|
||||
gfn_to_mfn(pg_owner, l1e_get_pfn(l1e), &l1e_p2mt);
|
||||
gfn_to_mfn(p2m_get_hostp2m(pg_owner),
|
||||
l1e_get_pfn(l1e), &l1e_p2mt);
|
||||
|
||||
if ( p2m_is_paged(l1e_p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(pg_owner, l1e_get_pfn(l1e));
|
||||
|
||||
p2m_mem_paging_populate(p2m_get_hostp2m(pg_owner),
|
||||
l1e_get_pfn(l1e));
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
}
|
||||
@@ -3457,7 +3459,7 @@ int do_mmu_update(
|
||||
/* Unshare the page for RW foreign mappings */
|
||||
if ( l1e_get_flags(l1e) & _PAGE_RW )
|
||||
{
|
||||
rc = mem_sharing_unshare_page(pg_owner,
|
||||
rc = mem_sharing_unshare_page(p2m_get_hostp2m(pg_owner),
|
||||
l1e_get_pfn(l1e),
|
||||
0);
|
||||
if ( rc )
|
||||
@@ -3475,12 +3477,12 @@ int do_mmu_update(
|
||||
{
|
||||
l2_pgentry_t l2e = l2e_from_intpte(req.val);
|
||||
p2m_type_t l2e_p2mt;
|
||||
gfn_to_mfn(pg_owner, l2e_get_pfn(l2e), &l2e_p2mt);
|
||||
gfn_to_mfn(p2m_get_hostp2m(pg_owner), l2e_get_pfn(l2e), &l2e_p2mt);
|
||||
|
||||
if ( p2m_is_paged(l2e_p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(pg_owner, l2e_get_pfn(l2e));
|
||||
|
||||
p2m_mem_paging_populate(p2m_get_hostp2m(pg_owner),
|
||||
l2e_get_pfn(l2e));
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
}
|
||||
@@ -3505,12 +3507,12 @@ int do_mmu_update(
|
||||
{
|
||||
l3_pgentry_t l3e = l3e_from_intpte(req.val);
|
||||
p2m_type_t l3e_p2mt;
|
||||
gfn_to_mfn(pg_owner, l3e_get_pfn(l3e), &l3e_p2mt);
|
||||
gfn_to_mfn(p2m_get_hostp2m(pg_owner), l3e_get_pfn(l3e), &l3e_p2mt);
|
||||
|
||||
if ( p2m_is_paged(l3e_p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(pg_owner, l3e_get_pfn(l3e));
|
||||
|
||||
p2m_mem_paging_populate(p2m_get_hostp2m(pg_owner),
|
||||
l3e_get_pfn(l3e));
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
}
|
||||
@@ -3536,12 +3538,13 @@ int do_mmu_update(
|
||||
{
|
||||
l4_pgentry_t l4e = l4e_from_intpte(req.val);
|
||||
p2m_type_t l4e_p2mt;
|
||||
gfn_to_mfn(pg_owner, l4e_get_pfn(l4e), &l4e_p2mt);
|
||||
gfn_to_mfn(p2m_get_hostp2m(pg_owner),
|
||||
l4e_get_pfn(l4e), &l4e_p2mt);
|
||||
|
||||
if ( p2m_is_paged(l4e_p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(pg_owner, l4e_get_pfn(l4e));
|
||||
|
||||
p2m_mem_paging_populate(p2m_get_hostp2m(pg_owner),
|
||||
l4e_get_pfn(l4e));
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
}
|
||||
@@ -3923,8 +3926,8 @@ static int create_grant_p2m_mapping(uint64_t addr, unsigned long frame,
|
||||
p2mt = p2m_grant_map_ro;
|
||||
else
|
||||
p2mt = p2m_grant_map_rw;
|
||||
rc = guest_physmap_add_entry(current->domain, addr >> PAGE_SHIFT,
|
||||
frame, 0, p2mt);
|
||||
rc = guest_physmap_add_entry(p2m_get_hostp2m(current->domain),
|
||||
addr >> PAGE_SHIFT, frame, 0, p2mt);
|
||||
if ( rc )
|
||||
return GNTST_general_error;
|
||||
else
|
||||
@@ -3962,11 +3965,12 @@ static int replace_grant_p2m_mapping(
|
||||
unsigned long gfn = (unsigned long)(addr >> PAGE_SHIFT);
|
||||
p2m_type_t type;
|
||||
mfn_t old_mfn;
|
||||
struct domain *d = current->domain;
|
||||
|
||||
if ( new_addr != 0 || (flags & GNTMAP_contains_pte) )
|
||||
return GNTST_general_error;
|
||||
|
||||
old_mfn = gfn_to_mfn_current(gfn, &type);
|
||||
old_mfn = gfn_to_mfn(p2m_get_hostp2m(d), gfn, &type);
|
||||
if ( !p2m_is_grant(type) || mfn_x(old_mfn) != frame )
|
||||
{
|
||||
gdprintk(XENLOG_WARNING,
|
||||
@@ -3974,7 +3978,7 @@ static int replace_grant_p2m_mapping(
|
||||
type, mfn_x(old_mfn), frame);
|
||||
return GNTST_general_error;
|
||||
}
|
||||
guest_physmap_remove_page(current->domain, gfn, frame, 0);
|
||||
guest_physmap_remove_page(d, gfn, frame, 0);
|
||||
|
||||
return GNTST_okay;
|
||||
}
|
||||
@@ -4581,7 +4585,8 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
p2m_type_t p2mt;
|
||||
|
||||
xatp.idx = mfn_x(gfn_to_mfn_unshare(d, xatp.idx, &p2mt, 0));
|
||||
xatp.idx = mfn_x(gfn_to_mfn_unshare(p2m_get_hostp2m(d),
|
||||
xatp.idx, &p2mt, 0));
|
||||
/* If the page is still shared, exit early */
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
{
|
||||
@@ -4771,6 +4776,7 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
xen_pod_target_t target;
|
||||
struct domain *d;
|
||||
struct p2m_domain *p2m;
|
||||
|
||||
/* Support DOMID_SELF? */
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
@@ -4794,9 +4800,10 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
rc = p2m_pod_set_mem_target(d, target.target_pages);
|
||||
}
|
||||
|
||||
p2m = p2m_get_hostp2m(d);
|
||||
target.tot_pages = d->tot_pages;
|
||||
target.pod_cache_pages = d->arch.p2m->pod.count;
|
||||
target.pod_entries = d->arch.p2m->pod.entry_count;
|
||||
target.pod_cache_pages = p2m->pod.count;
|
||||
target.pod_entries = p2m->pod.entry_count;
|
||||
|
||||
if ( copy_to_guest(arg, &target, 1) )
|
||||
{
|
||||
|
||||
@@ -86,17 +86,17 @@ static uint32_t set_ad_bits(void *guest_p, void *walk_p, int set_dirty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *map_domain_gfn(struct domain *d,
|
||||
static inline void *map_domain_gfn(struct p2m_domain *p2m,
|
||||
gfn_t gfn,
|
||||
mfn_t *mfn,
|
||||
p2m_type_t *p2mt,
|
||||
uint32_t *rc)
|
||||
{
|
||||
/* Translate the gfn, unsharing if shared */
|
||||
*mfn = gfn_to_mfn_unshare(d, gfn_x(gfn), p2mt, 0);
|
||||
*mfn = gfn_to_mfn_unshare(p2m, gfn_x(gfn), p2mt, 0);
|
||||
if ( p2m_is_paging(*p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(d, gfn_x(gfn));
|
||||
p2m_mem_paging_populate(p2m, gfn_x(gfn));
|
||||
|
||||
*rc = _PAGE_PAGED;
|
||||
return NULL;
|
||||
@@ -119,7 +119,8 @@ static inline void *map_domain_gfn(struct domain *d,
|
||||
|
||||
/* Walk the guest pagetables, after the manner of a hardware walker. */
|
||||
uint32_t
|
||||
guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
|
||||
unsigned long va, walk_t *gw,
|
||||
uint32_t pfec, mfn_t top_mfn, void *top_map)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
@@ -154,7 +155,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
if ( rc & _PAGE_PRESENT ) goto out;
|
||||
|
||||
/* Map the l3 table */
|
||||
l3p = map_domain_gfn(d,
|
||||
l3p = map_domain_gfn(p2m,
|
||||
guest_l4e_get_gfn(gw->l4e),
|
||||
&gw->l3mfn,
|
||||
&p2mt,
|
||||
@@ -181,7 +182,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
#endif /* PAE or 64... */
|
||||
|
||||
/* Map the l2 table */
|
||||
l2p = map_domain_gfn(d,
|
||||
l2p = map_domain_gfn(p2m,
|
||||
guest_l3e_get_gfn(gw->l3e),
|
||||
&gw->l2mfn,
|
||||
&p2mt,
|
||||
@@ -237,7 +238,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
else
|
||||
{
|
||||
/* Not a superpage: carry on and find the l1e. */
|
||||
l1p = map_domain_gfn(d,
|
||||
l1p = map_domain_gfn(p2m,
|
||||
guest_l2e_get_gfn(gw->l2e),
|
||||
&gw->l1mfn,
|
||||
&p2mt,
|
||||
|
||||
@@ -43,13 +43,14 @@ unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
|
||||
void *top_map;
|
||||
p2m_type_t p2mt;
|
||||
walk_t gw;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
|
||||
/* Get the top-level table's MFN */
|
||||
cr3 = v->arch.hvm_vcpu.guest_cr[3];
|
||||
top_mfn = gfn_to_mfn_unshare(v->domain, cr3 >> PAGE_SHIFT, &p2mt, 0);
|
||||
top_mfn = gfn_to_mfn_unshare(p2m, cr3 >> PAGE_SHIFT, &p2mt, 0);
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(v->domain, cr3 >> PAGE_SHIFT);
|
||||
p2m_mem_paging_populate(p2m, cr3 >> PAGE_SHIFT);
|
||||
|
||||
pfec[0] = PFEC_page_paged;
|
||||
return INVALID_GFN;
|
||||
@@ -71,17 +72,17 @@ unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
|
||||
#if GUEST_PAGING_LEVELS == 3
|
||||
top_map += (cr3 & ~(PAGE_MASK | 31));
|
||||
#endif
|
||||
missing = guest_walk_tables(v, gva, &gw, pfec[0], top_mfn, top_map);
|
||||
missing = guest_walk_tables(v, p2m, gva, &gw, pfec[0], top_mfn, top_map);
|
||||
unmap_domain_page(top_map);
|
||||
|
||||
/* Interpret the answer */
|
||||
if ( missing == 0 )
|
||||
{
|
||||
gfn_t gfn = guest_l1e_get_gfn(gw.l1e);
|
||||
gfn_to_mfn_unshare(v->domain, gfn_x(gfn), &p2mt, 0);
|
||||
gfn_to_mfn_unshare(p2m, gfn_x(gfn), &p2mt, 0);
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(v->domain, gfn_x(gfn));
|
||||
p2m_mem_paging_populate(p2m, gfn_x(gfn));
|
||||
|
||||
pfec[0] = PFEC_page_paged;
|
||||
return INVALID_GFN;
|
||||
@@ -130,4 +131,3 @@ unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
|
||||
+20
-14
@@ -70,7 +70,7 @@ static int hap_enable_vram_tracking(struct domain *d)
|
||||
|
||||
/* set l1e entries of P2M table to be read-only. */
|
||||
for (i = dirty_vram->begin_pfn; i < dirty_vram->end_pfn; i++)
|
||||
p2m_change_type(d, i, p2m_ram_rw, p2m_ram_logdirty);
|
||||
p2m_change_type(p2m_get_hostp2m(d), i, p2m_ram_rw, p2m_ram_logdirty);
|
||||
|
||||
flush_tlb_mask(&d->domain_dirty_cpumask);
|
||||
return 0;
|
||||
@@ -90,7 +90,7 @@ static int hap_disable_vram_tracking(struct domain *d)
|
||||
|
||||
/* set l1e entries of P2M table with normal mode */
|
||||
for (i = dirty_vram->begin_pfn; i < dirty_vram->end_pfn; i++)
|
||||
p2m_change_type(d, i, p2m_ram_logdirty, p2m_ram_rw);
|
||||
p2m_change_type(p2m_get_hostp2m(d), i, p2m_ram_logdirty, p2m_ram_rw);
|
||||
|
||||
flush_tlb_mask(&d->domain_dirty_cpumask);
|
||||
return 0;
|
||||
@@ -106,7 +106,7 @@ static void hap_clean_vram_tracking(struct domain *d)
|
||||
|
||||
/* set l1e entries of P2M table to be read-only. */
|
||||
for (i = dirty_vram->begin_pfn; i < dirty_vram->end_pfn; i++)
|
||||
p2m_change_type(d, i, p2m_ram_rw, p2m_ram_logdirty);
|
||||
p2m_change_type(p2m_get_hostp2m(d), i, p2m_ram_rw, p2m_ram_logdirty);
|
||||
|
||||
flush_tlb_mask(&d->domain_dirty_cpumask);
|
||||
}
|
||||
@@ -200,7 +200,8 @@ static int hap_enable_log_dirty(struct domain *d)
|
||||
hap_unlock(d);
|
||||
|
||||
/* set l1e entries of P2M table to be read-only. */
|
||||
p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
|
||||
p2m_change_entry_type_global(p2m_get_hostp2m(d),
|
||||
p2m_ram_rw, p2m_ram_logdirty);
|
||||
flush_tlb_mask(&d->domain_dirty_cpumask);
|
||||
return 0;
|
||||
}
|
||||
@@ -212,14 +213,16 @@ static int hap_disable_log_dirty(struct domain *d)
|
||||
hap_unlock(d);
|
||||
|
||||
/* set l1e entries of P2M table with normal mode */
|
||||
p2m_change_entry_type_global(d, p2m_ram_logdirty, p2m_ram_rw);
|
||||
p2m_change_entry_type_global(p2m_get_hostp2m(d),
|
||||
p2m_ram_logdirty, p2m_ram_rw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hap_clean_dirty_bitmap(struct domain *d)
|
||||
{
|
||||
/* set l1e entries of P2M table to be read-only. */
|
||||
p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
|
||||
p2m_change_entry_type_global(p2m_get_hostp2m(d),
|
||||
p2m_ram_rw, p2m_ram_logdirty);
|
||||
flush_tlb_mask(&d->domain_dirty_cpumask);
|
||||
}
|
||||
|
||||
@@ -273,8 +276,9 @@ static void hap_free(struct domain *d, mfn_t mfn)
|
||||
page_list_add_tail(pg, &d->arch.paging.hap.freelist);
|
||||
}
|
||||
|
||||
static struct page_info *hap_alloc_p2m_page(struct domain *d)
|
||||
static struct page_info *hap_alloc_p2m_page(struct p2m_domain *p2m)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
struct page_info *pg;
|
||||
|
||||
hap_lock(d);
|
||||
@@ -312,8 +316,9 @@ static struct page_info *hap_alloc_p2m_page(struct domain *d)
|
||||
return pg;
|
||||
}
|
||||
|
||||
static void hap_free_p2m_page(struct domain *d, struct page_info *pg)
|
||||
static void hap_free_p2m_page(struct p2m_domain *p2m, struct page_info *pg)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
hap_lock(d);
|
||||
ASSERT(page_get_owner(pg) == d);
|
||||
/* Should have just the one ref we gave it in alloc_p2m_page() */
|
||||
@@ -594,7 +599,8 @@ int hap_enable(struct domain *d, u32 mode)
|
||||
/* allocate P2m table */
|
||||
if ( mode & PG_translate )
|
||||
{
|
||||
rv = p2m_alloc_table(d, hap_alloc_p2m_page, hap_free_p2m_page);
|
||||
rv = p2m_alloc_table(p2m_get_hostp2m(d),
|
||||
hap_alloc_p2m_page, hap_free_p2m_page);
|
||||
if ( rv != 0 )
|
||||
goto out;
|
||||
}
|
||||
@@ -611,7 +617,7 @@ void hap_final_teardown(struct domain *d)
|
||||
if ( d->arch.paging.hap.total_pages != 0 )
|
||||
hap_teardown(d);
|
||||
|
||||
p2m_teardown(d);
|
||||
p2m_teardown(p2m_get_hostp2m(d));
|
||||
ASSERT(d->arch.paging.hap.p2m_pages == 0);
|
||||
}
|
||||
|
||||
@@ -711,9 +717,11 @@ void hap_vcpu_init(struct vcpu *v)
|
||||
static int hap_page_fault(struct vcpu *v, unsigned long va,
|
||||
struct cpu_user_regs *regs)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
|
||||
HAP_ERROR("Intercepted a guest #PF (%u:%u) with HAP enabled.\n",
|
||||
v->domain->domain_id, v->vcpu_id);
|
||||
domain_crash(v->domain);
|
||||
d->domain_id, v->vcpu_id);
|
||||
domain_crash(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -882,5 +890,3 @@ static const struct paging_mode hap_paging_long_mode = {
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
|
||||
|
||||
@@ -36,23 +36,23 @@
|
||||
#define is_epte_superpage(ept_entry) ((ept_entry)->sp)
|
||||
|
||||
/* Non-ept "lock-and-check" wrapper */
|
||||
static int ept_pod_check_and_populate(struct domain *d, unsigned long gfn,
|
||||
static int ept_pod_check_and_populate(struct p2m_domain *p2m, unsigned long gfn,
|
||||
ept_entry_t *entry, int order,
|
||||
p2m_query_t q)
|
||||
{
|
||||
int r;
|
||||
p2m_lock(d->arch.p2m);
|
||||
p2m_lock(p2m);
|
||||
|
||||
/* Check to make sure this is still PoD */
|
||||
if ( entry->avail1 != p2m_populate_on_demand )
|
||||
{
|
||||
p2m_unlock(d->arch.p2m);
|
||||
p2m_unlock(p2m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = p2m_pod_demand_populate(d, gfn, order, q);
|
||||
r = p2m_pod_demand_populate(p2m, gfn, order, q);
|
||||
|
||||
p2m_unlock(d->arch.p2m);
|
||||
p2m_unlock(p2m);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -98,11 +98,11 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type)
|
||||
#define GUEST_TABLE_POD_PAGE 3
|
||||
|
||||
/* Fill in middle levels of ept table */
|
||||
static int ept_set_middle_entry(struct domain *d, ept_entry_t *ept_entry)
|
||||
static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry)
|
||||
{
|
||||
struct page_info *pg;
|
||||
|
||||
pg = p2m_alloc_ptp(d, 0);
|
||||
pg = p2m_alloc_ptp(p2m, 0);
|
||||
if ( pg == NULL )
|
||||
return 0;
|
||||
|
||||
@@ -119,7 +119,7 @@ static int ept_set_middle_entry(struct domain *d, ept_entry_t *ept_entry)
|
||||
}
|
||||
|
||||
/* free ept sub tree behind an entry */
|
||||
void ept_free_entry(struct domain *d, ept_entry_t *ept_entry, int level)
|
||||
void ept_free_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry, int level)
|
||||
{
|
||||
/* End if the entry is a leaf entry. */
|
||||
if ( level == 0 || !is_epte_present(ept_entry) ||
|
||||
@@ -130,14 +130,14 @@ void ept_free_entry(struct domain *d, ept_entry_t *ept_entry, int level)
|
||||
{
|
||||
ept_entry_t *epte = map_domain_page(ept_entry->mfn);
|
||||
for ( int i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
|
||||
ept_free_entry(d, epte + i, level - 1);
|
||||
ept_free_entry(p2m, epte + i, level - 1);
|
||||
unmap_domain_page(epte);
|
||||
}
|
||||
|
||||
d->arch.p2m->free_page(d, mfn_to_page(ept_entry->mfn));
|
||||
p2m->free_page(p2m, mfn_to_page(ept_entry->mfn));
|
||||
}
|
||||
|
||||
static int ept_split_super_page(struct domain *d, ept_entry_t *ept_entry,
|
||||
static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
|
||||
int level, int target)
|
||||
{
|
||||
ept_entry_t new_ept, *table;
|
||||
@@ -150,7 +150,7 @@ static int ept_split_super_page(struct domain *d, ept_entry_t *ept_entry,
|
||||
|
||||
ASSERT(is_epte_superpage(ept_entry));
|
||||
|
||||
if ( !ept_set_middle_entry(d, &new_ept) )
|
||||
if ( !ept_set_middle_entry(p2m, &new_ept) )
|
||||
return 0;
|
||||
|
||||
table = map_domain_page(new_ept.mfn);
|
||||
@@ -174,7 +174,7 @@ static int ept_split_super_page(struct domain *d, ept_entry_t *ept_entry,
|
||||
|
||||
ASSERT(is_epte_superpage(epte));
|
||||
|
||||
if ( !(rv = ept_split_super_page(d, epte, level - 1, target)) )
|
||||
if ( !(rv = ept_split_super_page(p2m, epte, level - 1, target)) )
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ static int ept_split_super_page(struct domain *d, ept_entry_t *ept_entry,
|
||||
* GUEST_TABLE_POD:
|
||||
* The next entry is marked populate-on-demand.
|
||||
*/
|
||||
static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
static int ept_next_level(struct p2m_domain *p2m, bool_t read_only,
|
||||
ept_entry_t **table, unsigned long *gfn_remainder,
|
||||
int next_level)
|
||||
{
|
||||
@@ -225,7 +225,7 @@ static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
if ( read_only )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
|
||||
if ( !ept_set_middle_entry(d, ept_entry) )
|
||||
if ( !ept_set_middle_entry(p2m, ept_entry) )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
* by observing whether any gfn->mfn translations are modified.
|
||||
*/
|
||||
static int
|
||||
ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
|
||||
unsigned int order, p2m_type_t p2mt)
|
||||
{
|
||||
ept_entry_t *table, *ept_entry;
|
||||
@@ -259,6 +259,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
uint8_t ipat = 0;
|
||||
int need_modify_vtd_table = 1;
|
||||
int needs_sync = 1;
|
||||
struct domain *d = p2m->domain;
|
||||
|
||||
/*
|
||||
* the caller must make sure:
|
||||
@@ -267,7 +268,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
* 3. passing a valid order.
|
||||
*/
|
||||
if ( ((gfn | mfn_x(mfn)) & ((1UL << order) - 1)) ||
|
||||
(gfn >> ((ept_get_wl(d) + 1) * EPT_TABLE_ORDER)) ||
|
||||
((u64)gfn >> ((ept_get_wl(d) + 1) * EPT_TABLE_ORDER)) ||
|
||||
(order % EPT_TABLE_ORDER) )
|
||||
return 0;
|
||||
|
||||
@@ -281,7 +282,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
|
||||
for ( i = ept_get_wl(d); i > target; i-- )
|
||||
{
|
||||
ret = ept_next_level(d, 0, &table, &gfn_remainder, i);
|
||||
ret = ept_next_level(p2m, 0, &table, &gfn_remainder, i);
|
||||
if ( !ret )
|
||||
goto out;
|
||||
else if ( ret != GUEST_TABLE_NORMAL_PAGE )
|
||||
@@ -311,7 +312,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
if ( mfn_valid(mfn_x(mfn)) || direct_mmio || p2m_is_paged(p2mt) ||
|
||||
(p2mt == p2m_ram_paging_in_start) )
|
||||
{
|
||||
ept_entry->emt = epte_get_entry_emt(d, gfn, mfn, &ipat,
|
||||
ept_entry->emt = epte_get_entry_emt(p2m->domain, gfn, mfn, &ipat,
|
||||
direct_mmio);
|
||||
ept_entry->ipat = ipat;
|
||||
ept_entry->sp = order ? 1 : 0;
|
||||
@@ -337,9 +338,9 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
|
||||
split_ept_entry = *ept_entry;
|
||||
|
||||
if ( !ept_split_super_page(d, &split_ept_entry, i, target) )
|
||||
if ( !ept_split_super_page(p2m, &split_ept_entry, i, target) )
|
||||
{
|
||||
ept_free_entry(d, &split_ept_entry, i);
|
||||
ept_free_entry(p2m, &split_ept_entry, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -349,7 +350,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
|
||||
/* then move to the level we want to make real changes */
|
||||
for ( ; i > target; i-- )
|
||||
ept_next_level(d, 0, &table, &gfn_remainder, i);
|
||||
ept_next_level(p2m, 0, &table, &gfn_remainder, i);
|
||||
|
||||
ASSERT(i == target);
|
||||
|
||||
@@ -374,8 +375,8 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
|
||||
/* Track the highest gfn for which we have ever had a valid mapping */
|
||||
if ( mfn_valid(mfn_x(mfn)) &&
|
||||
(gfn + (1UL << order) - 1 > d->arch.p2m->max_mapped_pfn) )
|
||||
d->arch.p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
|
||||
(gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
|
||||
p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
|
||||
|
||||
/* Success */
|
||||
rv = 1;
|
||||
@@ -384,10 +385,10 @@ out:
|
||||
unmap_domain_page(table);
|
||||
|
||||
if ( needs_sync )
|
||||
ept_sync_domain(d);
|
||||
ept_sync_domain(p2m->domain);
|
||||
|
||||
/* Now the p2m table is not shared with vt-d page table */
|
||||
if ( rv && iommu_enabled && need_iommu(d) && need_modify_vtd_table )
|
||||
if ( rv && iommu_enabled && need_iommu(p2m->domain) && need_modify_vtd_table )
|
||||
{
|
||||
if ( p2mt == p2m_ram_rw )
|
||||
{
|
||||
@@ -395,22 +396,22 @@ out:
|
||||
{
|
||||
for ( i = 0; i < (1 << order); i++ )
|
||||
iommu_map_page(
|
||||
d, gfn - offset + i, mfn_x(mfn) - offset + i,
|
||||
p2m->domain, gfn - offset + i, mfn_x(mfn) - offset + i,
|
||||
IOMMUF_readable | IOMMUF_writable);
|
||||
}
|
||||
else if ( !order )
|
||||
iommu_map_page(
|
||||
d, gfn, mfn_x(mfn), IOMMUF_readable | IOMMUF_writable);
|
||||
p2m->domain, gfn, mfn_x(mfn), IOMMUF_readable | IOMMUF_writable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( order == EPT_TABLE_ORDER )
|
||||
{
|
||||
for ( i = 0; i < (1 << order); i++ )
|
||||
iommu_unmap_page(d, gfn - offset + i);
|
||||
iommu_unmap_page(p2m->domain, gfn - offset + i);
|
||||
}
|
||||
else if ( !order )
|
||||
iommu_unmap_page(d, gfn);
|
||||
iommu_unmap_page(p2m->domain, gfn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,9 +419,11 @@ out:
|
||||
}
|
||||
|
||||
/* Read ept p2m entries */
|
||||
static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
static mfn_t ept_get_entry(struct p2m_domain *p2m,
|
||||
unsigned long gfn, p2m_type_t *t,
|
||||
p2m_query_t q)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
ept_entry_t *table = map_domain_page(ept_get_asr(d));
|
||||
unsigned long gfn_remainder = gfn;
|
||||
ept_entry_t *ept_entry;
|
||||
@@ -432,7 +435,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
*t = p2m_mmio_dm;
|
||||
|
||||
/* This pfn is higher than the highest the p2m map currently holds */
|
||||
if ( gfn > d->arch.p2m->max_mapped_pfn )
|
||||
if ( gfn > p2m->max_mapped_pfn )
|
||||
goto out;
|
||||
|
||||
/* Should check if gfn obeys GAW here. */
|
||||
@@ -440,7 +443,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
for ( i = ept_get_wl(d); i > 0; i-- )
|
||||
{
|
||||
retry:
|
||||
ret = ept_next_level(d, 1, &table, &gfn_remainder, i);
|
||||
ret = ept_next_level(p2m, 1, &table, &gfn_remainder, i);
|
||||
if ( !ret )
|
||||
goto out;
|
||||
else if ( ret == GUEST_TABLE_POD_PAGE )
|
||||
@@ -457,7 +460,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
index = gfn_remainder >> ( i * EPT_TABLE_ORDER);
|
||||
ept_entry = table + index;
|
||||
|
||||
if ( !ept_pod_check_and_populate(d, gfn,
|
||||
if ( !ept_pod_check_and_populate(p2m, gfn,
|
||||
ept_entry, 9, q) )
|
||||
goto retry;
|
||||
else
|
||||
@@ -480,7 +483,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
|
||||
ASSERT(i == 0);
|
||||
|
||||
if ( ept_pod_check_and_populate(d, gfn,
|
||||
if ( ept_pod_check_and_populate(p2m, gfn,
|
||||
ept_entry, 0, q) )
|
||||
goto out;
|
||||
}
|
||||
@@ -511,9 +514,10 @@ out:
|
||||
/* WARNING: Only caller doesn't care about PoD pages. So this function will
|
||||
* always return 0 for PoD pages, not populate them. If that becomes necessary,
|
||||
* pass a p2m_query_t type along to distinguish. */
|
||||
static ept_entry_t ept_get_entry_content(struct domain *d, unsigned long gfn, int *level)
|
||||
static ept_entry_t ept_get_entry_content(struct p2m_domain *p2m,
|
||||
unsigned long gfn, int *level)
|
||||
{
|
||||
ept_entry_t *table = map_domain_page(ept_get_asr(d));
|
||||
ept_entry_t *table = map_domain_page(ept_get_asr(p2m->domain));
|
||||
unsigned long gfn_remainder = gfn;
|
||||
ept_entry_t *ept_entry;
|
||||
ept_entry_t content = { .epte = 0 };
|
||||
@@ -522,12 +526,12 @@ static ept_entry_t ept_get_entry_content(struct domain *d, unsigned long gfn, in
|
||||
int ret=0;
|
||||
|
||||
/* This pfn is higher than the highest the p2m map currently holds */
|
||||
if ( gfn > d->arch.p2m->max_mapped_pfn )
|
||||
if ( gfn > p2m->max_mapped_pfn )
|
||||
goto out;
|
||||
|
||||
for ( i = ept_get_wl(d); i > 0; i-- )
|
||||
for ( i = ept_get_wl(p2m->domain); i > 0; i-- )
|
||||
{
|
||||
ret = ept_next_level(d, 1, &table, &gfn_remainder, i);
|
||||
ret = ept_next_level(p2m, 1, &table, &gfn_remainder, i);
|
||||
if ( !ret || ret == GUEST_TABLE_POD_PAGE )
|
||||
goto out;
|
||||
else if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
@@ -546,6 +550,7 @@ static ept_entry_t ept_get_entry_content(struct domain *d, unsigned long gfn, in
|
||||
|
||||
void ept_walk_table(struct domain *d, unsigned long gfn)
|
||||
{
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
ept_entry_t *table = map_domain_page(ept_get_asr(d));
|
||||
unsigned long gfn_remainder = gfn;
|
||||
|
||||
@@ -555,10 +560,10 @@ void ept_walk_table(struct domain *d, unsigned long gfn)
|
||||
d->domain_id, gfn);
|
||||
|
||||
/* This pfn is higher than the highest the p2m map currently holds */
|
||||
if ( gfn > d->arch.p2m->max_mapped_pfn )
|
||||
if ( gfn > p2m->max_mapped_pfn )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, " gfn exceeds max_mapped_pfn %lx\n",
|
||||
d->arch.p2m->max_mapped_pfn);
|
||||
p2m->max_mapped_pfn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -593,17 +598,18 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static mfn_t ept_get_entry_current(unsigned long gfn, p2m_type_t *t,
|
||||
static mfn_t ept_get_entry_current(struct p2m_domain *p2m,
|
||||
unsigned long gfn, p2m_type_t *t,
|
||||
p2m_query_t q)
|
||||
{
|
||||
return ept_get_entry(current->domain, gfn, t, q);
|
||||
return ept_get_entry(p2m, gfn, t, q);
|
||||
}
|
||||
|
||||
/*
|
||||
* To test if the new emt type is the same with old,
|
||||
* return 1 to not to reset ept entry.
|
||||
*/
|
||||
static int need_modify_ept_entry(struct domain *d, unsigned long gfn,
|
||||
static int need_modify_ept_entry(struct p2m_domain *p2m, unsigned long gfn,
|
||||
mfn_t mfn, uint8_t o_ipat, uint8_t o_emt,
|
||||
p2m_type_t p2mt)
|
||||
{
|
||||
@@ -611,7 +617,7 @@ static int need_modify_ept_entry(struct domain *d, unsigned long gfn,
|
||||
uint8_t emt;
|
||||
bool_t direct_mmio = (p2mt == p2m_mmio_direct);
|
||||
|
||||
emt = epte_get_entry_emt(d, gfn, mfn, &ipat, direct_mmio);
|
||||
emt = epte_get_entry_emt(p2m->domain, gfn, mfn, &ipat, direct_mmio);
|
||||
|
||||
if ( (emt == o_emt) && (ipat == o_ipat) )
|
||||
return 0;
|
||||
@@ -619,21 +625,23 @@ static int need_modify_ept_entry(struct domain *d, unsigned long gfn,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn,
|
||||
void ept_change_entry_emt_with_range(struct domain *d,
|
||||
unsigned long start_gfn,
|
||||
unsigned long end_gfn)
|
||||
{
|
||||
unsigned long gfn;
|
||||
ept_entry_t e;
|
||||
mfn_t mfn;
|
||||
int order = 0;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
|
||||
p2m_lock(d->arch.p2m);
|
||||
p2m_lock(p2m);
|
||||
for ( gfn = start_gfn; gfn <= end_gfn; gfn++ )
|
||||
{
|
||||
int level = 0;
|
||||
uint64_t trunk = 0;
|
||||
|
||||
e = ept_get_entry_content(d, gfn, &level);
|
||||
e = ept_get_entry_content(p2m, gfn, &level);
|
||||
if ( !p2m_has_emt(e.avail1) )
|
||||
continue;
|
||||
|
||||
@@ -652,9 +660,9 @@ void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn,
|
||||
* Set emt for super page.
|
||||
*/
|
||||
order = level * EPT_TABLE_ORDER;
|
||||
if ( need_modify_ept_entry(d, gfn, mfn,
|
||||
if ( need_modify_ept_entry(p2m, gfn, mfn,
|
||||
e.ipat, e.emt, e.avail1) )
|
||||
ept_set_entry(d, gfn, mfn, order, e.avail1);
|
||||
ept_set_entry(p2m, gfn, mfn, order, e.avail1);
|
||||
gfn += trunk;
|
||||
break;
|
||||
}
|
||||
@@ -663,11 +671,11 @@ void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn,
|
||||
}
|
||||
else /* gfn assigned with 4k */
|
||||
{
|
||||
if ( need_modify_ept_entry(d, gfn, mfn, e.ipat, e.emt, e.avail1) )
|
||||
ept_set_entry(d, gfn, mfn, order, e.avail1);
|
||||
if ( need_modify_ept_entry(p2m, gfn, mfn, e.ipat, e.emt, e.avail1) )
|
||||
ept_set_entry(p2m, gfn, mfn, order, e.avail1);
|
||||
}
|
||||
}
|
||||
p2m_unlock(d->arch.p2m);
|
||||
p2m_unlock(p2m);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -701,9 +709,10 @@ static void ept_change_entry_type_page(mfn_t ept_page_mfn, int ept_page_level,
|
||||
unmap_domain_page(epte);
|
||||
}
|
||||
|
||||
static void ept_change_entry_type_global(struct domain *d,
|
||||
static void ept_change_entry_type_global(struct p2m_domain *p2m,
|
||||
p2m_type_t ot, p2m_type_t nt)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
if ( ept_get_asr(d) == 0 )
|
||||
return;
|
||||
|
||||
@@ -714,10 +723,11 @@ static void ept_change_entry_type_global(struct domain *d,
|
||||
|
||||
void ept_p2m_init(struct domain *d)
|
||||
{
|
||||
d->arch.p2m->set_entry = ept_set_entry;
|
||||
d->arch.p2m->get_entry = ept_get_entry;
|
||||
d->arch.p2m->get_entry_current = ept_get_entry_current;
|
||||
d->arch.p2m->change_entry_type_global = ept_change_entry_type_global;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
p2m->set_entry = ept_set_entry;
|
||||
p2m->get_entry = ept_get_entry;
|
||||
p2m->get_entry_current = ept_get_entry_current;
|
||||
p2m->change_entry_type_global = ept_change_entry_type_global;
|
||||
}
|
||||
|
||||
static void ept_dump_p2m_table(unsigned char key)
|
||||
@@ -742,7 +752,7 @@ static void ept_dump_p2m_table(unsigned char key)
|
||||
p2m = p2m_get_hostp2m(d);
|
||||
printk("\ndomain%d EPT p2m table: \n", d->domain_id);
|
||||
|
||||
for ( gfn = 0; gfn <= d->arch.p2m->max_mapped_pfn; gfn += (1 << order) )
|
||||
for ( gfn = 0; gfn <= p2m->max_mapped_pfn; gfn += (1 << order) )
|
||||
{
|
||||
gfn_remainder = gfn;
|
||||
mfn = _mfn(INVALID_MFN);
|
||||
@@ -750,7 +760,7 @@ static void ept_dump_p2m_table(unsigned char key)
|
||||
|
||||
for ( i = ept_get_wl(d); i > 0; i-- )
|
||||
{
|
||||
ret = ept_next_level(d, 1, &table, &gfn_remainder, i);
|
||||
ret = ept_next_level(p2m, 1, &table, &gfn_remainder, i);
|
||||
if ( ret != GUEST_TABLE_NORMAL_PAGE )
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
|
||||
/* Get MFN of ring page */
|
||||
guest_get_eff_l1e(v, ring_addr, &l1e);
|
||||
gfn = l1e_get_pfn(l1e);
|
||||
ring_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
|
||||
ring_mfn = gfn_to_mfn(p2m_get_hostp2m(dom_mem_event), gfn, &p2mt);
|
||||
|
||||
rc = -EINVAL;
|
||||
if ( unlikely(!mfn_valid(mfn_x(ring_mfn))) )
|
||||
@@ -244,7 +244,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
|
||||
/* Get MFN of shared page */
|
||||
guest_get_eff_l1e(v, shared_addr, &l1e);
|
||||
gfn = l1e_get_pfn(l1e);
|
||||
shared_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
|
||||
shared_mfn = gfn_to_mfn(p2m_get_hostp2m(dom_mem_event), gfn, &p2mt);
|
||||
|
||||
rc = -EINVAL;
|
||||
if ( unlikely(!mfn_valid(mfn_x(shared_mfn))) )
|
||||
|
||||
@@ -29,33 +29,34 @@ int mem_paging_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
|
||||
XEN_GUEST_HANDLE(void) u_domctl)
|
||||
{
|
||||
int rc;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
|
||||
switch( mec->op )
|
||||
{
|
||||
case XEN_DOMCTL_MEM_EVENT_OP_PAGING_NOMINATE:
|
||||
{
|
||||
unsigned long gfn = mec->gfn;
|
||||
rc = p2m_mem_paging_nominate(d, gfn);
|
||||
rc = p2m_mem_paging_nominate(p2m, gfn);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_MEM_EVENT_OP_PAGING_EVICT:
|
||||
{
|
||||
unsigned long gfn = mec->gfn;
|
||||
rc = p2m_mem_paging_evict(d, gfn);
|
||||
rc = p2m_mem_paging_evict(p2m, gfn);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_MEM_EVENT_OP_PAGING_PREP:
|
||||
{
|
||||
unsigned long gfn = mec->gfn;
|
||||
rc = p2m_mem_paging_prep(d, gfn);
|
||||
rc = p2m_mem_paging_prep(p2m, gfn);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_MEM_EVENT_OP_PAGING_RESUME:
|
||||
{
|
||||
p2m_mem_paging_resume(d);
|
||||
p2m_mem_paging_resume(p2m);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -251,6 +251,7 @@ static void mem_sharing_audit(void)
|
||||
list_for_each(le, &e->gfns)
|
||||
{
|
||||
struct domain *d;
|
||||
struct p2m_domain *p2m;
|
||||
p2m_type_t t;
|
||||
mfn_t mfn;
|
||||
|
||||
@@ -262,7 +263,8 @@ static void mem_sharing_audit(void)
|
||||
g->domain, g->gfn, mfn_x(e->mfn));
|
||||
continue;
|
||||
}
|
||||
mfn = gfn_to_mfn(d, g->gfn, &t);
|
||||
p2m = p2m_get_hostp2m(d);
|
||||
mfn = gfn_to_mfn(p2m, g->gfn, &t);
|
||||
if(mfn_x(mfn) != mfn_x(e->mfn))
|
||||
MEM_SHARING_DEBUG("Incorrect P2M for d=%d, PFN=%lx."
|
||||
"Expecting MFN=%ld, got %ld\n",
|
||||
@@ -377,7 +379,7 @@ int mem_sharing_debug_gfn(struct domain *d, unsigned long gfn)
|
||||
mfn_t mfn;
|
||||
struct page_info *page;
|
||||
|
||||
mfn = gfn_to_mfn(d, gfn, &p2mt);
|
||||
mfn = gfn_to_mfn(p2m_get_hostp2m(d), gfn, &p2mt);
|
||||
page = mfn_to_page(mfn);
|
||||
|
||||
printk("Debug for domain=%d, gfn=%lx, ",
|
||||
@@ -487,7 +489,7 @@ int mem_sharing_debug_gref(struct domain *d, grant_ref_t ref)
|
||||
return mem_sharing_debug_gfn(d, gfn);
|
||||
}
|
||||
|
||||
int mem_sharing_nominate_page(struct domain *d,
|
||||
int mem_sharing_nominate_page(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
int expected_refcnt,
|
||||
shr_handle_t *phandle)
|
||||
@@ -499,10 +501,11 @@ int mem_sharing_nominate_page(struct domain *d,
|
||||
shr_handle_t handle;
|
||||
shr_hash_entry_t *hash_entry;
|
||||
struct gfn_info *gfn_info;
|
||||
struct domain *d = p2m->domain;
|
||||
|
||||
*phandle = 0UL;
|
||||
|
||||
mfn = gfn_to_mfn(d, gfn, &p2mt);
|
||||
mfn = gfn_to_mfn(p2m, gfn, &p2mt);
|
||||
|
||||
/* Check if mfn is valid */
|
||||
ret = -EINVAL;
|
||||
@@ -536,7 +539,7 @@ int mem_sharing_nominate_page(struct domain *d,
|
||||
}
|
||||
|
||||
/* Change the p2m type */
|
||||
if(p2m_change_type(d, gfn, p2mt, p2m_ram_shared) != p2mt)
|
||||
if(p2m_change_type(p2m, gfn, p2mt, p2m_ram_shared) != p2mt)
|
||||
{
|
||||
/* This is unlikely, as the type must have changed since we've checked
|
||||
* it a few lines above.
|
||||
@@ -599,7 +602,7 @@ int mem_sharing_share_pages(shr_handle_t sh, shr_handle_t ch)
|
||||
list_del(&gfn->list);
|
||||
d = get_domain_by_id(gfn->domain);
|
||||
BUG_ON(!d);
|
||||
BUG_ON(set_shared_p2m_entry(d, gfn->gfn, se->mfn) == 0);
|
||||
BUG_ON(set_shared_p2m_entry(p2m_get_hostp2m(d), gfn->gfn, se->mfn) == 0);
|
||||
put_domain(d);
|
||||
list_add(&gfn->list, &se->gfns);
|
||||
put_page_and_type(cpage);
|
||||
@@ -618,7 +621,7 @@ err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mem_sharing_unshare_page(struct domain *d,
|
||||
int mem_sharing_unshare_page(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
uint16_t flags)
|
||||
{
|
||||
@@ -631,8 +634,9 @@ int mem_sharing_unshare_page(struct domain *d,
|
||||
struct gfn_info *gfn_info = NULL;
|
||||
shr_handle_t handle;
|
||||
struct list_head *le;
|
||||
struct domain *d = p2m->domain;
|
||||
|
||||
mfn = gfn_to_mfn(d, gfn, &p2mt);
|
||||
mfn = gfn_to_mfn(p2m, gfn, &p2mt);
|
||||
|
||||
page = mfn_to_page(mfn);
|
||||
handle = page->shr_handle;
|
||||
@@ -696,7 +700,7 @@ gfn_found:
|
||||
unmap_domain_page(s);
|
||||
unmap_domain_page(t);
|
||||
|
||||
ASSERT(set_shared_p2m_entry(d, gfn, page_to_mfn(page)) != 0);
|
||||
ASSERT(set_shared_p2m_entry(p2m, gfn, page_to_mfn(page)) != 0);
|
||||
put_page_and_type(old_page);
|
||||
|
||||
private_page_found:
|
||||
@@ -708,7 +712,7 @@ private_page_found:
|
||||
atomic_dec(&nr_saved_mfns);
|
||||
shr_unlock();
|
||||
|
||||
if(p2m_change_type(d, gfn, p2m_ram_shared, p2m_ram_rw) !=
|
||||
if(p2m_change_type(p2m, gfn, p2m_ram_shared, p2m_ram_rw) !=
|
||||
p2m_ram_shared)
|
||||
{
|
||||
printk("Could not change p2m type.\n");
|
||||
@@ -740,7 +744,7 @@ int mem_sharing_domctl(struct domain *d, xen_domctl_mem_sharing_op_t *mec)
|
||||
shr_handle_t handle;
|
||||
if(!mem_sharing_enabled(d))
|
||||
return -EINVAL;
|
||||
rc = mem_sharing_nominate_page(d, gfn, 0, &handle);
|
||||
rc = mem_sharing_nominate_page(p2m_get_hostp2m(d), gfn, 0, &handle);
|
||||
mec->u.nominate.handle = handle;
|
||||
mem_sharing_audit();
|
||||
}
|
||||
@@ -756,7 +760,8 @@ int mem_sharing_domctl(struct domain *d, xen_domctl_mem_sharing_op_t *mec)
|
||||
return -EINVAL;
|
||||
if(mem_sharing_gref_to_gfn(d, gref, &gfn) < 0)
|
||||
return -EINVAL;
|
||||
rc = mem_sharing_nominate_page(d, gfn, 3, &handle);
|
||||
rc = mem_sharing_nominate_page(p2m_get_hostp2m(d),
|
||||
gfn, 3, &handle);
|
||||
mec->u.nominate.handle = handle;
|
||||
mem_sharing_audit();
|
||||
}
|
||||
|
||||
+336
-326
File diff suppressed because it is too large.
Load diff
@@ -1714,8 +1714,9 @@ sh_alloc_p2m_pages(struct domain *d)
|
||||
|
||||
// Returns 0 if no memory is available...
|
||||
static struct page_info *
|
||||
shadow_alloc_p2m_page(struct domain *d)
|
||||
shadow_alloc_p2m_page(struct p2m_domain *p2m)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
struct page_info *pg;
|
||||
mfn_t mfn;
|
||||
void *p;
|
||||
@@ -1741,8 +1742,9 @@ shadow_alloc_p2m_page(struct domain *d)
|
||||
}
|
||||
|
||||
static void
|
||||
shadow_free_p2m_page(struct domain *d, struct page_info *pg)
|
||||
shadow_free_p2m_page(struct p2m_domain *p2m, struct page_info *pg)
|
||||
{
|
||||
struct domain *d = p2m->domain;
|
||||
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 )
|
||||
@@ -3100,6 +3102,7 @@ int shadow_enable(struct domain *d, u32 mode)
|
||||
struct page_info *pg = NULL;
|
||||
uint32_t *e;
|
||||
int i, rv = 0;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
|
||||
mode |= PG_SH_enable;
|
||||
|
||||
@@ -3135,7 +3138,8 @@ int shadow_enable(struct domain *d, u32 mode)
|
||||
* to avoid possible deadlock. */
|
||||
if ( mode & PG_translate )
|
||||
{
|
||||
rv = p2m_alloc_table(d, shadow_alloc_p2m_page, shadow_free_p2m_page);
|
||||
rv = p2m_alloc_table(p2m,
|
||||
shadow_alloc_p2m_page, shadow_free_p2m_page);
|
||||
if (rv != 0)
|
||||
goto out_unlocked;
|
||||
}
|
||||
@@ -3146,7 +3150,7 @@ int shadow_enable(struct domain *d, u32 mode)
|
||||
{
|
||||
/* Get a single page from the shadow pool. Take it via the
|
||||
* P2M interface to make freeing it simpler afterwards. */
|
||||
pg = shadow_alloc_p2m_page(d);
|
||||
pg = shadow_alloc_p2m_page(p2m);
|
||||
if ( pg == NULL )
|
||||
{
|
||||
rv = -ENOMEM;
|
||||
@@ -3195,10 +3199,10 @@ int shadow_enable(struct domain *d, u32 mode)
|
||||
out_locked:
|
||||
shadow_unlock(d);
|
||||
out_unlocked:
|
||||
if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m_get_hostp2m(d))) )
|
||||
p2m_teardown(d);
|
||||
if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) )
|
||||
p2m_teardown(p2m);
|
||||
if ( rv != 0 && pg != NULL )
|
||||
shadow_free_p2m_page(d, pg);
|
||||
shadow_free_p2m_page(p2m, pg);
|
||||
domain_unpause(d);
|
||||
return rv;
|
||||
}
|
||||
@@ -3210,6 +3214,7 @@ void shadow_teardown(struct domain *d)
|
||||
struct vcpu *v;
|
||||
mfn_t mfn;
|
||||
struct page_info *pg;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
|
||||
ASSERT(d->is_dying);
|
||||
ASSERT(d != current->domain);
|
||||
@@ -3264,7 +3269,7 @@ void shadow_teardown(struct domain *d)
|
||||
#endif /* (SHADOW_OPTIMIZATIONS & (SHOPT_VIRTUAL_TLB|SHOPT_OUT_OF_SYNC)) */
|
||||
|
||||
while ( (pg = page_list_remove_head(&d->arch.paging.shadow.p2m_freelist)) )
|
||||
shadow_free_p2m_page(d, pg);
|
||||
shadow_free_p2m_page(p2m, pg);
|
||||
|
||||
if ( d->arch.paging.shadow.total_pages != 0 )
|
||||
{
|
||||
@@ -3298,7 +3303,7 @@ void shadow_teardown(struct domain *d)
|
||||
if ( !hvm_paging_enabled(v) )
|
||||
v->arch.guest_table = pagetable_null();
|
||||
}
|
||||
shadow_free_p2m_page(d,
|
||||
shadow_free_p2m_page(p2m,
|
||||
pagetable_get_page(d->arch.paging.shadow.unpaged_pagetable));
|
||||
d->arch.paging.shadow.unpaged_pagetable = pagetable_null();
|
||||
}
|
||||
@@ -3335,7 +3340,7 @@ void shadow_final_teardown(struct domain *d)
|
||||
shadow_teardown(d);
|
||||
|
||||
/* It is now safe to pull down the p2m map. */
|
||||
p2m_teardown(d);
|
||||
p2m_teardown(p2m_get_hostp2m(d));
|
||||
|
||||
SHADOW_PRINTK("dom %u final teardown done."
|
||||
" Shadow pages total = %u, free = %u, p2m=%u\n",
|
||||
@@ -3657,10 +3662,11 @@ int shadow_track_dirty_vram(struct domain *d,
|
||||
unsigned long i;
|
||||
p2m_type_t t;
|
||||
struct sh_dirty_vram *dirty_vram = d->arch.hvm_domain.dirty_vram;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
|
||||
if (end_pfn < begin_pfn
|
||||
|| begin_pfn > d->arch.p2m->max_mapped_pfn
|
||||
|| end_pfn >= d->arch.p2m->max_mapped_pfn)
|
||||
|| begin_pfn > p2m->max_mapped_pfn
|
||||
|| end_pfn >= p2m->max_mapped_pfn)
|
||||
return -EINVAL;
|
||||
|
||||
shadow_lock(d);
|
||||
@@ -3729,7 +3735,7 @@ int shadow_track_dirty_vram(struct domain *d,
|
||||
|
||||
/* Iterate over VRAM to track dirty bits. */
|
||||
for ( i = 0; i < nr; i++ ) {
|
||||
mfn_t mfn = gfn_to_mfn(d, begin_pfn + i, &t);
|
||||
mfn_t mfn = gfn_to_mfn(p2m, begin_pfn + i, &t);
|
||||
struct page_info *page;
|
||||
int dirty = 0;
|
||||
paddr_t sl1ma = dirty_vram->sl1ma[i];
|
||||
@@ -3814,7 +3820,7 @@ int shadow_track_dirty_vram(struct domain *d,
|
||||
/* was clean for more than two seconds, try to disable guest
|
||||
* write access */
|
||||
for ( i = begin_pfn; i < end_pfn; i++ ) {
|
||||
mfn_t mfn = gfn_to_mfn(d, i, &t);
|
||||
mfn_t mfn = gfn_to_mfn(p2m, i, &t);
|
||||
if (mfn_x(mfn) != INVALID_MFN)
|
||||
flush_tlb |= sh_remove_write_access(d->vcpu[0], mfn, 1, 0);
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ static inline uint32_t
|
||||
sh_walk_guest_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
uint32_t pfec)
|
||||
{
|
||||
return guest_walk_tables(v, va, gw, pfec,
|
||||
return guest_walk_tables(v, p2m_get_hostp2m(v->domain), va, gw, pfec,
|
||||
#if GUEST_PAGING_LEVELS == 3 /* PAE */
|
||||
_mfn(INVALID_MFN),
|
||||
v->arch.paging.shadow.gl3e
|
||||
@@ -2240,6 +2240,7 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se)
|
||||
shadow_l4e_t *sl4p = se;
|
||||
mfn_t sl3mfn = _mfn(INVALID_MFN);
|
||||
struct domain *d = v->domain;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(d);
|
||||
p2m_type_t p2mt;
|
||||
int result = 0;
|
||||
|
||||
@@ -2248,7 +2249,7 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se)
|
||||
if ( guest_l4e_get_flags(new_gl4e) & _PAGE_PRESENT )
|
||||
{
|
||||
gfn_t gl3gfn = guest_l4e_get_gfn(new_gl4e);
|
||||
mfn_t gl3mfn = gfn_to_mfn_query(d, gl3gfn, &p2mt);
|
||||
mfn_t gl3mfn = gfn_to_mfn_query(p2m, gl3gfn, &p2mt);
|
||||
if ( p2m_is_ram(p2mt) )
|
||||
sl3mfn = get_shadow_status(v, gl3mfn, SH_type_l3_shadow);
|
||||
else if ( p2mt != p2m_populate_on_demand )
|
||||
@@ -2299,13 +2300,14 @@ static int validate_gl3e(struct vcpu *v, void *new_ge, mfn_t sl3mfn, void *se)
|
||||
mfn_t sl2mfn = _mfn(INVALID_MFN);
|
||||
p2m_type_t p2mt;
|
||||
int result = 0;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
|
||||
perfc_incr(shadow_validate_gl3e_calls);
|
||||
|
||||
if ( guest_l3e_get_flags(new_gl3e) & _PAGE_PRESENT )
|
||||
{
|
||||
gfn_t gl2gfn = guest_l3e_get_gfn(new_gl3e);
|
||||
mfn_t gl2mfn = gfn_to_mfn_query(v->domain, gl2gfn, &p2mt);
|
||||
mfn_t gl2mfn = gfn_to_mfn_query(p2m, gl2gfn, &p2mt);
|
||||
if ( p2m_is_ram(p2mt) )
|
||||
sl2mfn = get_shadow_status(v, gl2mfn, SH_type_l2_shadow);
|
||||
else if ( p2mt != p2m_populate_on_demand )
|
||||
@@ -2329,6 +2331,7 @@ static int validate_gl2e(struct vcpu *v, void *new_ge, mfn_t sl2mfn, void *se)
|
||||
guest_l2e_t new_gl2e = *(guest_l2e_t *)new_ge;
|
||||
shadow_l2e_t *sl2p = se;
|
||||
mfn_t sl1mfn = _mfn(INVALID_MFN);
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
p2m_type_t p2mt;
|
||||
int result = 0;
|
||||
|
||||
@@ -2354,7 +2357,7 @@ static int validate_gl2e(struct vcpu *v, void *new_ge, mfn_t sl2mfn, void *se)
|
||||
}
|
||||
else
|
||||
{
|
||||
mfn_t gl1mfn = gfn_to_mfn_query(v->domain, gl1gfn, &p2mt);
|
||||
mfn_t gl1mfn = gfn_to_mfn_query(p2m, gl1gfn, &p2mt);
|
||||
if ( p2m_is_ram(p2mt) )
|
||||
sl1mfn = get_shadow_status(v, gl1mfn, SH_type_l1_shadow);
|
||||
else if ( p2mt != p2m_populate_on_demand )
|
||||
@@ -2415,6 +2418,7 @@ static int validate_gl1e(struct vcpu *v, void *new_ge, mfn_t sl1mfn, void *se)
|
||||
shadow_l1e_t *sl1p = se;
|
||||
gfn_t gfn;
|
||||
mfn_t gmfn;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
p2m_type_t p2mt;
|
||||
int result = 0;
|
||||
#if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
|
||||
@@ -2424,7 +2428,7 @@ static int validate_gl1e(struct vcpu *v, void *new_ge, mfn_t sl1mfn, void *se)
|
||||
perfc_incr(shadow_validate_gl1e_calls);
|
||||
|
||||
gfn = guest_l1e_get_gfn(new_gl1e);
|
||||
gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m, gfn, &p2mt);
|
||||
|
||||
l1e_propagate_from_guest(v, new_gl1e, gmfn, &new_sl1e, ft_prefetch, p2mt);
|
||||
result |= shadow_set_l1e(v, sl1p, new_sl1e, p2mt, sl1mfn);
|
||||
@@ -2484,7 +2488,7 @@ void sh_resync_l1(struct vcpu *v, mfn_t gl1mfn, mfn_t snpmfn)
|
||||
shadow_l1e_t nsl1e;
|
||||
|
||||
gfn = guest_l1e_get_gfn(gl1e);
|
||||
gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), gfn, &p2mt);
|
||||
l1e_propagate_from_guest(v, gl1e, gmfn, &nsl1e, ft_prefetch, p2mt);
|
||||
rc |= shadow_set_l1e(v, sl1p, nsl1e, p2mt, sl1mfn);
|
||||
|
||||
@@ -2810,7 +2814,7 @@ static void sh_prefetch(struct vcpu *v, walk_t *gw,
|
||||
|
||||
/* Look at the gfn that the l1e is pointing at */
|
||||
gfn = guest_l1e_get_gfn(gl1e);
|
||||
gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), gfn, &p2mt);
|
||||
|
||||
/* Propagate the entry. */
|
||||
l1e_propagate_from_guest(v, gl1e, gmfn, &sl1e, ft_prefetch, p2mt);
|
||||
@@ -3166,7 +3170,7 @@ static int sh_page_fault(struct vcpu *v,
|
||||
|
||||
/* What mfn is the guest trying to access? */
|
||||
gfn = guest_l1e_get_gfn(gw.l1e);
|
||||
gmfn = gfn_to_mfn_guest(d, gfn, &p2mt);
|
||||
gmfn = gfn_to_mfn_guest(p2m_get_hostp2m(d), gfn, &p2mt);
|
||||
|
||||
if ( shadow_mode_refcounts(d) &&
|
||||
((!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) ||
|
||||
@@ -4272,7 +4276,7 @@ sh_update_cr3(struct vcpu *v, int do_locking)
|
||||
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
|
||||
{
|
||||
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
|
||||
gl2mfn = gfn_to_mfn_query(d, gl2gfn, &p2mt);
|
||||
gl2mfn = gfn_to_mfn_query(p2m_get_hostp2m(d), gl2gfn, &p2mt);
|
||||
if ( p2m_is_ram(p2mt) )
|
||||
flush |= sh_remove_write_access(v, gl2mfn, 2, 0);
|
||||
}
|
||||
@@ -4285,7 +4289,7 @@ sh_update_cr3(struct vcpu *v, int do_locking)
|
||||
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
|
||||
{
|
||||
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
|
||||
gl2mfn = gfn_to_mfn_query(d, gl2gfn, &p2mt);
|
||||
gl2mfn = gfn_to_mfn_query(p2m_get_hostp2m(d), gl2gfn, &p2mt);
|
||||
if ( p2m_is_ram(p2mt) )
|
||||
sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3)
|
||||
? SH_type_l2h_shadow
|
||||
@@ -4682,7 +4686,7 @@ static void sh_pagetable_dying(struct vcpu *v, paddr_t gpa)
|
||||
if ( gcr3 == gpa )
|
||||
fast_path = 1;
|
||||
|
||||
gmfn = gfn_to_mfn_query(v->domain, _gfn(gpa >> PAGE_SHIFT), &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), _gfn(gpa >> PAGE_SHIFT), &p2mt);
|
||||
if ( !mfn_valid(gmfn) || !p2m_is_ram(p2mt) )
|
||||
{
|
||||
printk(XENLOG_DEBUG "sh_pagetable_dying: gpa not valid %"PRIpaddr"\n",
|
||||
@@ -4702,7 +4706,7 @@ static void sh_pagetable_dying(struct vcpu *v, paddr_t gpa)
|
||||
{
|
||||
/* retrieving the l2s */
|
||||
gl2a = guest_l3e_get_paddr(gl3e[i]);
|
||||
gmfn = gfn_to_mfn_query(v->domain, _gfn(gl2a >> PAGE_SHIFT), &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), _gfn(gl2a >> PAGE_SHIFT), &p2mt);
|
||||
smfn = shadow_hash_lookup(v, mfn_x(gmfn), SH_type_l2_pae_shadow);
|
||||
}
|
||||
|
||||
@@ -4737,7 +4741,7 @@ static void sh_pagetable_dying(struct vcpu *v, paddr_t gpa)
|
||||
|
||||
shadow_lock(v->domain);
|
||||
|
||||
gmfn = gfn_to_mfn_query(v->domain, _gfn(gpa >> PAGE_SHIFT), &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), _gfn(gpa >> PAGE_SHIFT), &p2mt);
|
||||
#if GUEST_PAGING_LEVELS == 2
|
||||
smfn = shadow_hash_lookup(v, mfn_x(gmfn), SH_type_l2_32_shadow);
|
||||
#else
|
||||
@@ -4777,6 +4781,7 @@ static mfn_t emulate_gva_to_mfn(struct vcpu *v,
|
||||
mfn_t mfn;
|
||||
p2m_type_t p2mt;
|
||||
uint32_t pfec = PFEC_page_present | PFEC_write_access;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
|
||||
/* Translate the VA to a GFN */
|
||||
gfn = sh_gva_to_gfn(v, vaddr, &pfec);
|
||||
@@ -4792,9 +4797,9 @@ static mfn_t emulate_gva_to_mfn(struct vcpu *v,
|
||||
/* Translate the GFN to an MFN */
|
||||
/* PoD: query only if shadow lock is held (to avoid deadlock) */
|
||||
if ( shadow_locked_by_me(v->domain) )
|
||||
mfn = gfn_to_mfn_query(v->domain, _gfn(gfn), &p2mt);
|
||||
mfn = gfn_to_mfn_query(p2m, _gfn(gfn), &p2mt);
|
||||
else
|
||||
mfn = gfn_to_mfn(v->domain, _gfn(gfn), &p2mt);
|
||||
mfn = gfn_to_mfn(p2m, _gfn(gfn), &p2mt);
|
||||
|
||||
if ( p2m_is_readonly(p2mt) )
|
||||
return _mfn(READONLY_GFN);
|
||||
@@ -5199,7 +5204,7 @@ int sh_audit_l1_table(struct vcpu *v, mfn_t sl1mfn, mfn_t x)
|
||||
{
|
||||
gfn = guest_l1e_get_gfn(*gl1e);
|
||||
mfn = shadow_l1e_get_mfn(*sl1e);
|
||||
gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
|
||||
gmfn = gfn_to_mfn_query(p2m_get_hostp2m(v->domain), gfn, &p2mt);
|
||||
if ( !p2m_is_grant(p2mt) && mfn_x(gmfn) != mfn_x(mfn) )
|
||||
AUDIT_FAIL(1, "bad translation: gfn %" SH_PRI_gfn
|
||||
" --> %" PRI_mfn " != mfn %" PRI_mfn,
|
||||
@@ -5243,6 +5248,7 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
|
||||
shadow_l2e_t *sl2e;
|
||||
mfn_t mfn, gmfn, gl2mfn;
|
||||
gfn_t gfn;
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
|
||||
p2m_type_t p2mt;
|
||||
char *s;
|
||||
int done = 0;
|
||||
@@ -5269,7 +5275,7 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
|
||||
mfn = shadow_l2e_get_mfn(*sl2e);
|
||||
gmfn = (guest_l2e_get_flags(*gl2e) & _PAGE_PSE)
|
||||
? get_fl1_shadow_status(v, gfn)
|
||||
: get_shadow_status(v, gfn_to_mfn_query(v->domain, gfn, &p2mt),
|
||||
: get_shadow_status(v, gfn_to_mfn_query(p2m, gfn, &p2mt),
|
||||
SH_type_l1_shadow);
|
||||
if ( mfn_x(gmfn) != mfn_x(mfn) )
|
||||
AUDIT_FAIL(2, "bad translation: gfn %" SH_PRI_gfn
|
||||
@@ -5277,8 +5283,8 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
|
||||
" --> %" PRI_mfn " != mfn %" PRI_mfn,
|
||||
gfn_x(gfn),
|
||||
(guest_l2e_get_flags(*gl2e) & _PAGE_PSE) ? 0
|
||||
: mfn_x(gfn_to_mfn_query(v->domain, gfn, &p2mt)),
|
||||
mfn_x(gmfn), mfn_x(mfn));
|
||||
: mfn_x(gfn_to_mfn_query(p2m,
|
||||
gfn, &p2mt)), mfn_x(gmfn), mfn_x(mfn));
|
||||
}
|
||||
});
|
||||
sh_unmap_domain_page(gp);
|
||||
@@ -5316,7 +5322,7 @@ int sh_audit_l3_table(struct vcpu *v, mfn_t sl3mfn, mfn_t x)
|
||||
{
|
||||
gfn = guest_l3e_get_gfn(*gl3e);
|
||||
mfn = shadow_l3e_get_mfn(*sl3e);
|
||||
gmfn = get_shadow_status(v, gfn_to_mfn_query(v->domain, gfn, &p2mt),
|
||||
gmfn = get_shadow_status(v, gfn_to_mfn_query(p2m_get_hostp2m(v->domain), gfn, &p2mt),
|
||||
((GUEST_PAGING_LEVELS == 3 ||
|
||||
is_pv_32on64_vcpu(v))
|
||||
&& !shadow_mode_external(v->domain)
|
||||
@@ -5363,7 +5369,8 @@ int sh_audit_l4_table(struct vcpu *v, mfn_t sl4mfn, mfn_t x)
|
||||
{
|
||||
gfn = guest_l4e_get_gfn(*gl4e);
|
||||
mfn = shadow_l4e_get_mfn(*sl4e);
|
||||
gmfn = get_shadow_status(v, gfn_to_mfn_query(v->domain, gfn, &p2mt),
|
||||
gmfn = get_shadow_status(v, gfn_to_mfn_query(p2m_get_hostp2m(v->domain),
|
||||
gfn, &p2mt),
|
||||
SH_type_l3_shadow);
|
||||
if ( mfn_x(gmfn) != mfn_x(mfn) )
|
||||
AUDIT_FAIL(4, "bad translation: gfn %" SH_PRI_gfn
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "op_x86_model.h"
|
||||
|
||||
struct op_counter_config counter_config[OP_MAX_COUNTER];
|
||||
struct op_ibs_config ibs_config;
|
||||
|
||||
static struct op_x86_model_spec const *__read_mostly model;
|
||||
static struct op_msrs cpu_msrs[NR_CPUS];
|
||||
@@ -430,6 +431,7 @@ static int __init nmi_init(void)
|
||||
case 0x10:
|
||||
model = &op_athlon_spec;
|
||||
cpu_type = "x86-64/family10";
|
||||
ibs_caps = ibs_init();
|
||||
break;
|
||||
case 0x11:
|
||||
model = &op_athlon_spec;
|
||||
|
||||
@@ -26,4 +26,16 @@ struct op_counter_config {
|
||||
|
||||
extern struct op_counter_config counter_config[];
|
||||
|
||||
/* AMD IBS configuration */
|
||||
struct op_ibs_config {
|
||||
unsigned long op_enabled;
|
||||
unsigned long fetch_enabled;
|
||||
unsigned long max_cnt_fetch;
|
||||
unsigned long max_cnt_op;
|
||||
unsigned long rand_en;
|
||||
unsigned long dispatched_ops;
|
||||
};
|
||||
|
||||
extern struct op_ibs_config ibs_config;
|
||||
|
||||
#endif /* OP_COUNTER_H */
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <asm/regs.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/hvm/support.h>
|
||||
#include <xen/pci_regs.h>
|
||||
|
||||
#include "op_x86_model.h"
|
||||
#include "op_counter.h"
|
||||
@@ -47,6 +48,116 @@ static unsigned long reset_value[NUM_COUNTERS];
|
||||
|
||||
extern char svm_stgi_label[];
|
||||
|
||||
u32 ibs_caps = 0;
|
||||
static u64 ibs_op_ctl;
|
||||
|
||||
/* IBS cpuid feature detection */
|
||||
#define IBS_CPUID_FEATURES 0x8000001b
|
||||
|
||||
/* IBS MSRs */
|
||||
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
|
||||
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
|
||||
#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032
|
||||
#define MSR_AMD64_IBSOPCTL 0xc0011033
|
||||
#define MSR_AMD64_IBSOPRIP 0xc0011034
|
||||
#define MSR_AMD64_IBSOPDATA 0xc0011035
|
||||
#define MSR_AMD64_IBSOPDATA2 0xc0011036
|
||||
#define MSR_AMD64_IBSOPDATA3 0xc0011037
|
||||
#define MSR_AMD64_IBSDCLINAD 0xc0011038
|
||||
#define MSR_AMD64_IBSDCPHYSAD 0xc0011039
|
||||
#define MSR_AMD64_IBSCTL 0xc001103a
|
||||
|
||||
/*
|
||||
* Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
|
||||
* bit 0 is used to indicate the existence of IBS.
|
||||
*/
|
||||
#define IBS_CAPS_AVAIL (1LL<<0)
|
||||
#define IBS_CAPS_RDWROPCNT (1LL<<3)
|
||||
#define IBS_CAPS_OPCNT (1LL<<4)
|
||||
|
||||
/* IBS randomization macros */
|
||||
#define IBS_RANDOM_BITS 12
|
||||
#define IBS_RANDOM_MASK ((1ULL << IBS_RANDOM_BITS) - 1)
|
||||
#define IBS_RANDOM_MAXCNT_OFFSET (1ULL << (IBS_RANDOM_BITS - 5))
|
||||
|
||||
/* IbsFetchCtl bits/masks */
|
||||
#define IBS_FETCH_RAND_EN (1ULL<<57)
|
||||
#define IBS_FETCH_VAL (1ULL<<49)
|
||||
#define IBS_FETCH_ENABLE (1ULL<<48)
|
||||
#define IBS_FETCH_CNT 0xFFFF0000ULL
|
||||
#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
|
||||
|
||||
/* IbsOpCtl bits */
|
||||
#define IBS_OP_CNT_CTL (1ULL<<19)
|
||||
#define IBS_OP_VAL (1ULL<<18)
|
||||
#define IBS_OP_ENABLE (1ULL<<17)
|
||||
#define IBS_OP_MAX_CNT 0x0000FFFFULL
|
||||
|
||||
/* IBS sample identifier */
|
||||
#define IBS_FETCH_CODE 13
|
||||
#define IBS_OP_CODE 14
|
||||
|
||||
#define clamp(val, min, max) ({ \
|
||||
typeof(val) __val = (val); \
|
||||
typeof(min) __min = (min); \
|
||||
typeof(max) __max = (max); \
|
||||
(void) (&__val == &__min); \
|
||||
(void) (&__val == &__max); \
|
||||
__val = __val < __min ? __min: __val; \
|
||||
__val > __max ? __max: __val; })
|
||||
|
||||
/*
|
||||
* 16-bit Linear Feedback Shift Register (LFSR)
|
||||
*/
|
||||
static unsigned int lfsr_random(void)
|
||||
{
|
||||
static unsigned int lfsr_value = 0xF00D;
|
||||
unsigned int bit;
|
||||
|
||||
/* Compute next bit to shift in */
|
||||
bit = ((lfsr_value >> 0) ^
|
||||
(lfsr_value >> 2) ^
|
||||
(lfsr_value >> 3) ^
|
||||
(lfsr_value >> 5)) & 0x0001;
|
||||
|
||||
/* Advance to next register value */
|
||||
lfsr_value = (lfsr_value >> 1) | (bit << 15);
|
||||
|
||||
return lfsr_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* IBS software randomization
|
||||
*
|
||||
* The IBS periodic op counter is randomized in software. The lower 12
|
||||
* bits of the 20 bit counter are randomized. IbsOpCurCnt is
|
||||
* initialized with a 12 bit random value.
|
||||
*/
|
||||
static inline u64 op_amd_randomize_ibs_op(u64 val)
|
||||
{
|
||||
unsigned int random = lfsr_random();
|
||||
|
||||
if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
|
||||
/*
|
||||
* Work around if the hw can not write to IbsOpCurCnt
|
||||
*
|
||||
* Randomize the lower 8 bits of the 16 bit
|
||||
* IbsOpMaxCnt [15:0] value in the range of -128 to
|
||||
* +127 by adding/subtracting an offset to the
|
||||
* maximum count (IbsOpMaxCnt).
|
||||
*
|
||||
* To avoid over or underflows and protect upper bits
|
||||
* starting at bit 16, the initial value for
|
||||
* IbsOpMaxCnt must fit in the range from 0x0081 to
|
||||
* 0xff80.
|
||||
*/
|
||||
val += (s8)(random >> 4);
|
||||
else
|
||||
val |= (u64)(random & IBS_RANDOM_MASK) << 32;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void athlon_fill_in_addresses(struct op_msrs * const msrs)
|
||||
{
|
||||
msrs->counters[0].addr = MSR_K7_PERFCTR0;
|
||||
@@ -101,6 +212,78 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
ibs_log_event(u64 data, struct cpu_user_regs * const regs, int mode)
|
||||
{
|
||||
struct vcpu *v = current;
|
||||
u32 temp = 0;
|
||||
|
||||
temp = data & 0xFFFFFFFF;
|
||||
xenoprof_log_event(v, regs, temp, mode, 0);
|
||||
|
||||
temp = (data >> 32) & 0xFFFFFFFF;
|
||||
xenoprof_log_event(v, regs, temp, mode, 0);
|
||||
|
||||
}
|
||||
|
||||
static inline int handle_ibs(int mode, struct cpu_user_regs * const regs)
|
||||
{
|
||||
u64 val, ctl;
|
||||
struct vcpu *v = current;
|
||||
|
||||
if (!ibs_caps)
|
||||
return 1;
|
||||
|
||||
if (ibs_config.fetch_enabled) {
|
||||
rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
|
||||
if (ctl & IBS_FETCH_VAL) {
|
||||
rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
|
||||
xenoprof_log_event(v, regs, IBS_FETCH_CODE, mode, 0);
|
||||
xenoprof_log_event(v, regs, val, mode, 0);
|
||||
|
||||
ibs_log_event(val, regs, mode);
|
||||
ibs_log_event(ctl, regs, mode);
|
||||
|
||||
rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
|
||||
/* reenable the IRQ */
|
||||
ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
|
||||
ctl |= IBS_FETCH_ENABLE;
|
||||
wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
|
||||
}
|
||||
}
|
||||
|
||||
if (ibs_config.op_enabled) {
|
||||
rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
|
||||
if (ctl & IBS_OP_VAL) {
|
||||
|
||||
rdmsrl(MSR_AMD64_IBSOPRIP, val);
|
||||
xenoprof_log_event(v, regs, IBS_OP_CODE, mode, 0);
|
||||
xenoprof_log_event(v, regs, val, mode, 0);
|
||||
|
||||
ibs_log_event(val, regs, mode);
|
||||
|
||||
rdmsrl(MSR_AMD64_IBSOPDATA, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
rdmsrl(MSR_AMD64_IBSOPDATA2, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
rdmsrl(MSR_AMD64_IBSOPDATA3, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
rdmsrl(MSR_AMD64_IBSDCLINAD, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
|
||||
ibs_log_event(val, regs, mode);
|
||||
|
||||
/* reenable the IRQ */
|
||||
ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
|
||||
wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int athlon_check_ctrs(unsigned int const cpu,
|
||||
struct op_msrs const * const msrs,
|
||||
struct cpu_user_regs * const regs)
|
||||
@@ -134,10 +317,51 @@ static int athlon_check_ctrs(unsigned int const cpu,
|
||||
}
|
||||
}
|
||||
|
||||
ovf = handle_ibs(mode, regs);
|
||||
/* See op_model_ppro.c */
|
||||
return ovf;
|
||||
}
|
||||
|
||||
static inline void start_ibs(void)
|
||||
{
|
||||
u64 val = 0;
|
||||
|
||||
if (!ibs_caps)
|
||||
return;
|
||||
|
||||
if (ibs_config.fetch_enabled) {
|
||||
val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
|
||||
val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
|
||||
val |= IBS_FETCH_ENABLE;
|
||||
wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
|
||||
}
|
||||
|
||||
if (ibs_config.op_enabled) {
|
||||
ibs_op_ctl = ibs_config.max_cnt_op >> 4;
|
||||
if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
|
||||
/*
|
||||
* IbsOpCurCnt not supported. See
|
||||
* op_amd_randomize_ibs_op() for details.
|
||||
*/
|
||||
ibs_op_ctl = clamp((unsigned long long)ibs_op_ctl,
|
||||
0x0081ULL, 0xFF80ULL);
|
||||
} else {
|
||||
/*
|
||||
* The start value is randomized with a
|
||||
* positive offset, we need to compensate it
|
||||
* with the half of the randomized range. Also
|
||||
* avoid underflows.
|
||||
*/
|
||||
ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
|
||||
IBS_OP_MAX_CNT);
|
||||
}
|
||||
if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
|
||||
ibs_op_ctl |= IBS_OP_CNT_CTL;
|
||||
ibs_op_ctl |= IBS_OP_ENABLE;
|
||||
val = op_amd_randomize_ibs_op(ibs_op_ctl);
|
||||
wrmsrl(MSR_AMD64_IBSOPCTL, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void athlon_start(struct op_msrs const * const msrs)
|
||||
{
|
||||
@@ -150,8 +374,22 @@ static void athlon_start(struct op_msrs const * const msrs)
|
||||
CTRL_WRITE(msr_content, msrs, i);
|
||||
}
|
||||
}
|
||||
start_ibs();
|
||||
}
|
||||
|
||||
static void stop_ibs(void)
|
||||
{
|
||||
if (!ibs_caps)
|
||||
return;
|
||||
|
||||
if (ibs_config.fetch_enabled)
|
||||
/* clear max count and enable */
|
||||
wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
|
||||
|
||||
if (ibs_config.op_enabled)
|
||||
/* clear max count and enable */
|
||||
wrmsrl(MSR_AMD64_IBSOPCTL, 0);
|
||||
}
|
||||
|
||||
static void athlon_stop(struct op_msrs const * const msrs)
|
||||
{
|
||||
@@ -165,8 +403,118 @@ static void athlon_stop(struct op_msrs const * const msrs)
|
||||
CTRL_SET_INACTIVE(msr_content);
|
||||
CTRL_WRITE(msr_content, msrs, i);
|
||||
}
|
||||
|
||||
stop_ibs();
|
||||
}
|
||||
|
||||
#define IBSCTL_LVTOFFSETVAL (1 << 8)
|
||||
#define APIC_EILVT_MSG_NMI 0x4
|
||||
#define APIC_EILVT_LVTOFF_IBS 1
|
||||
#define APIC_EILVTn(n) (0x500 + 0x10 * n)
|
||||
static inline void init_ibs_nmi_per_cpu(void *arg)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
reg = (APIC_EILVT_LVTOFF_IBS << 4) + APIC_EILVTn(0);
|
||||
apic_write(reg, APIC_EILVT_MSG_NMI << 8);
|
||||
}
|
||||
|
||||
#define PCI_VENDOR_ID_AMD 0x1022
|
||||
#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203
|
||||
#define IBSCTL 0x1cc
|
||||
static int init_ibs_nmi(void)
|
||||
{
|
||||
int bus, dev, func;
|
||||
u32 id, value;
|
||||
u16 vendor_id, dev_id;
|
||||
int nodes;
|
||||
|
||||
/* per CPU setup */
|
||||
on_each_cpu(init_ibs_nmi_per_cpu, NULL, 1);
|
||||
|
||||
nodes = 0;
|
||||
for (bus = 0; bus < 256; bus++) {
|
||||
for (dev = 0; dev < 32; dev++) {
|
||||
for (func = 0; func < 8; func++) {
|
||||
id = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
|
||||
|
||||
if ((id == 0xffffffff) || (id == 0x00000000) ||
|
||||
(id == 0x0000ffff) || (id == 0xffff0000))
|
||||
continue;
|
||||
|
||||
vendor_id = id & 0xffff;
|
||||
dev_id = (id >> 16) & 0xffff;
|
||||
|
||||
if ((vendor_id == PCI_VENDOR_ID_AMD) &&
|
||||
(dev_id == PCI_DEVICE_ID_AMD_10H_NB_MISC)) {
|
||||
|
||||
pci_conf_write32(bus, dev, func, IBSCTL,
|
||||
IBSCTL_LVTOFFSETVAL | APIC_EILVT_LVTOFF_IBS);
|
||||
|
||||
value = pci_conf_read32(bus, dev, func, IBSCTL);
|
||||
|
||||
if (value != (IBSCTL_LVTOFFSETVAL |
|
||||
APIC_EILVT_LVTOFF_IBS)) {
|
||||
printk("Xenoprofile: Failed to setup IBS LVT offset, "
|
||||
"IBSCTL = 0x%08x", value);
|
||||
return 1;
|
||||
}
|
||||
nodes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nodes) {
|
||||
printk("Xenoprofile: No CPU node configured for IBS");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 get_ibs_caps(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_32
|
||||
return 0;
|
||||
#else
|
||||
unsigned int max_level;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_IBS))
|
||||
return 0;
|
||||
|
||||
/* check IBS cpuid feature flags */
|
||||
max_level = cpuid_eax(0x80000000);
|
||||
if (max_level < IBS_CPUID_FEATURES)
|
||||
return IBS_CAPS_AVAIL;
|
||||
|
||||
ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
|
||||
if (!(ibs_caps & IBS_CAPS_AVAIL))
|
||||
/* cpuid flags not valid */
|
||||
return IBS_CAPS_AVAIL;
|
||||
|
||||
return ibs_caps;
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 ibs_init(void)
|
||||
{
|
||||
u32 ibs_caps = 0;
|
||||
|
||||
ibs_caps = get_ibs_caps();
|
||||
|
||||
if ( !ibs_caps )
|
||||
return 0;
|
||||
|
||||
if (init_ibs_nmi()) {
|
||||
ibs_caps = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk("Xenoprofile: AMD IBS detected (0x%08x)\n",
|
||||
(unsigned)ibs_caps);
|
||||
return ibs_caps;
|
||||
}
|
||||
|
||||
struct op_x86_model_spec const op_athlon_spec = {
|
||||
.num_counters = NUM_COUNTERS,
|
||||
|
||||
@@ -38,6 +38,23 @@ int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xenoprof_arch_ibs_counter(XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct xenoprof_ibs_counter ibs_counter;
|
||||
|
||||
if ( copy_from_guest(&ibs_counter, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
ibs_config.op_enabled = ibs_counter.op_enabled;
|
||||
ibs_config.fetch_enabled = ibs_counter.fetch_enabled;
|
||||
ibs_config.max_cnt_fetch = ibs_counter.max_cnt_fetch;
|
||||
ibs_config.max_cnt_op = ibs_counter.max_cnt_op;
|
||||
ibs_config.rand_en = ibs_counter.rand_en;
|
||||
ibs_config.dispatched_ops = ibs_counter.dispatched_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
int compat_oprof_arch_counter(XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
|
||||
+56
-2
@@ -205,6 +205,58 @@ void __devinit srat_detect_node(int cpu)
|
||||
printk("CPU %d APIC %d -> Node %d\n", cpu, apicid, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort CPUs by <node,package,core,thread> tuple. Fortunately this hierarchy is
|
||||
* reflected in the structure of modern APIC identifiers, so we sort based on
|
||||
* those. This is slightly complicated by the fact that the BSP must remain
|
||||
* CPU 0. Hence we do a variation on longest-prefix matching to do the best we
|
||||
* can while keeping CPU 0 static.
|
||||
*/
|
||||
static void __init normalise_cpu_order(void)
|
||||
{
|
||||
unsigned int i, j, min_cpu;
|
||||
uint32_t apicid, diff, min_diff;
|
||||
|
||||
for_each_present_cpu ( i )
|
||||
{
|
||||
apicid = x86_cpu_to_apicid[i];
|
||||
min_diff = min_cpu = ~0u;
|
||||
|
||||
/*
|
||||
* Find remaining CPU with longest-prefix match on APIC ID.
|
||||
* Among identical longest-prefix matches, pick the smallest APIC ID.
|
||||
*/
|
||||
for ( j = next_cpu(i, cpu_present_map);
|
||||
j < NR_CPUS;
|
||||
j = next_cpu(j, cpu_present_map) )
|
||||
{
|
||||
diff = x86_cpu_to_apicid[j] ^ apicid;
|
||||
while ( diff & (diff-1) )
|
||||
diff &= diff-1;
|
||||
if ( (diff < min_diff) ||
|
||||
((diff == min_diff) &&
|
||||
(x86_cpu_to_apicid[j] < x86_cpu_to_apicid[min_cpu])) )
|
||||
{
|
||||
min_diff = diff;
|
||||
min_cpu = j;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no match then there must be no CPUs remaining to consider. */
|
||||
if ( min_cpu >= NR_CPUS )
|
||||
{
|
||||
BUG_ON(next_cpu(i, cpu_present_map) < NR_CPUS);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Switch the best-matching CPU with the next CPU in logical order. */
|
||||
j = next_cpu(i, cpu_present_map);
|
||||
apicid = x86_cpu_to_apicid[min_cpu];
|
||||
x86_cpu_to_apicid[min_cpu] = x86_cpu_to_apicid[j];
|
||||
x86_cpu_to_apicid[j] = apicid;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure a given physical memory range is present in the bootstrap mappings.
|
||||
* Use superpage mappings to ensure that pagetable memory needn't be allocated.
|
||||
@@ -952,8 +1004,6 @@ void __init __start_xen(unsigned long mbi_p)
|
||||
|
||||
acpi_boot_init();
|
||||
|
||||
init_cpu_to_node();
|
||||
|
||||
if ( smp_found_config )
|
||||
get_smp_config();
|
||||
|
||||
@@ -964,6 +1014,10 @@ void __init __start_xen(unsigned long mbi_p)
|
||||
|
||||
init_apic_mappings();
|
||||
|
||||
normalise_cpu_order();
|
||||
|
||||
init_cpu_to_node();
|
||||
|
||||
if ( x2apic_is_available() )
|
||||
enable_x2apic();
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ process_mce:
|
||||
ALIGN
|
||||
/* %ebx: struct vcpu */
|
||||
process_nmi:
|
||||
cmpw $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%ebx)
|
||||
testb $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%ebx)
|
||||
jnz test_guest_events
|
||||
sti
|
||||
movb $0,VCPU_nmi_pending(%ebx)
|
||||
|
||||
@@ -137,7 +137,7 @@ compat_process_mce:
|
||||
ALIGN
|
||||
/* %rbx: struct vcpu */
|
||||
compat_process_nmi:
|
||||
cmpw $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx)
|
||||
testb $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx)
|
||||
jnz compat_test_guest_events
|
||||
sti
|
||||
movb $0,VCPU_nmi_pending(%rbx)
|
||||
|
||||
@@ -239,7 +239,7 @@ process_mce:
|
||||
ALIGN
|
||||
/* %rbx: struct vcpu */
|
||||
process_nmi:
|
||||
cmpw $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx)
|
||||
testb $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx)
|
||||
jnz test_guest_events
|
||||
sti
|
||||
movb $0,VCPU_nmi_pending(%rbx)
|
||||
|
||||
@@ -191,6 +191,8 @@ struct vcpu *alloc_vcpu(
|
||||
/* Must be called after making new vcpu visible to for_each_vcpu(). */
|
||||
vcpu_check_shutdown(v);
|
||||
|
||||
domain_update_node_affinity(d);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -235,6 +237,8 @@ struct domain *domain_create(
|
||||
INIT_PAGE_LIST_HEAD(&d->page_list);
|
||||
INIT_PAGE_LIST_HEAD(&d->xenpage_list);
|
||||
|
||||
spin_lock_init(&d->node_affinity_lock);
|
||||
|
||||
spin_lock_init(&d->shutdown_lock);
|
||||
d->shutdown_code = -1;
|
||||
|
||||
@@ -341,6 +345,27 @@ struct domain *domain_create(
|
||||
}
|
||||
|
||||
|
||||
void domain_update_node_affinity(struct domain *d)
|
||||
{
|
||||
cpumask_t cpumask = CPU_MASK_NONE;
|
||||
nodemask_t nodemask = NODE_MASK_NONE;
|
||||
struct vcpu *v;
|
||||
unsigned int node;
|
||||
|
||||
spin_lock(&d->node_affinity_lock);
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
cpus_or(cpumask, cpumask, v->cpu_affinity);
|
||||
|
||||
for_each_online_node ( node )
|
||||
if ( cpus_intersects(node_to_cpumask(node), cpumask) )
|
||||
node_set(node, nodemask);
|
||||
|
||||
d->node_affinity = nodemask;
|
||||
spin_unlock(&d->node_affinity_lock);
|
||||
}
|
||||
|
||||
|
||||
struct domain *get_domain_by_id(domid_t dom)
|
||||
{
|
||||
struct domain *d;
|
||||
|
||||
@@ -109,7 +109,7 @@ static unsigned inline int max_nr_maptrack_frames(void)
|
||||
#define gfn_to_mfn_private(_d, _gfn) ({ \
|
||||
p2m_type_t __p2mt; \
|
||||
unsigned long __x; \
|
||||
__x = mfn_x(gfn_to_mfn_unshare(_d, _gfn, &__p2mt, 1)); \
|
||||
__x = mfn_x(gfn_to_mfn_unshare(p2m_get_hostp2m(_d), _gfn, &__p2mt, 1)); \
|
||||
if ( !p2m_is_valid(__p2mt) ) \
|
||||
__x = INVALID_MFN; \
|
||||
__x; })
|
||||
@@ -1933,12 +1933,13 @@ __gnttab_copy(
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
p2m_type_t p2mt;
|
||||
s_frame = mfn_x(gfn_to_mfn(sd, op->source.u.gmfn, &p2mt));
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(sd);
|
||||
s_frame = mfn_x(gfn_to_mfn(p2m, op->source.u.gmfn, &p2mt));
|
||||
if ( !p2m_is_valid(p2mt) )
|
||||
s_frame = INVALID_MFN;
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(sd, op->source.u.gmfn);
|
||||
p2m_mem_paging_populate(p2m, op->source.u.gmfn);
|
||||
rc = -ENOENT;
|
||||
goto error_out;
|
||||
}
|
||||
@@ -1979,12 +1980,13 @@ __gnttab_copy(
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
p2m_type_t p2mt;
|
||||
d_frame = mfn_x(gfn_to_mfn_unshare(dd, op->dest.u.gmfn, &p2mt, 1));
|
||||
struct p2m_domain *p2m = p2m_get_hostp2m(dd);
|
||||
d_frame = mfn_x(gfn_to_mfn_unshare(p2m, op->dest.u.gmfn, &p2mt, 1));
|
||||
if ( !p2m_is_valid(p2mt) )
|
||||
d_frame = INVALID_MFN;
|
||||
if ( p2m_is_paging(p2mt) )
|
||||
{
|
||||
p2m_mem_paging_populate(dd, op->dest.u.gmfn);
|
||||
p2m_mem_paging_populate(p2m, op->dest.u.gmfn);
|
||||
rc = -ENOENT;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
+5
-8
@@ -161,7 +161,7 @@ int guest_remove_page(struct domain *d, unsigned long gmfn)
|
||||
unsigned long mfn;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt));
|
||||
mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(d), gmfn, &p2mt));
|
||||
#else
|
||||
mfn = gmfn_to_mfn(d, gmfn);
|
||||
#endif
|
||||
@@ -259,7 +259,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
|
||||
unsigned long in_chunk_order, out_chunk_order;
|
||||
xen_pfn_t gpfn, gmfn, mfn;
|
||||
unsigned long i, j, k;
|
||||
unsigned int node, memflags = 0;
|
||||
unsigned int memflags = 0;
|
||||
long rc = 0;
|
||||
struct domain *d;
|
||||
struct page_info *page;
|
||||
@@ -324,10 +324,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
|
||||
d,
|
||||
XENMEMF_get_address_bits(exch.out.mem_flags) ? :
|
||||
(BITS_PER_LONG+PAGE_SHIFT)));
|
||||
node = XENMEMF_get_node(exch.out.mem_flags);
|
||||
if ( node == NUMA_NO_NODE )
|
||||
node = domain_to_node(d);
|
||||
memflags |= MEMF_node(node);
|
||||
memflags |= MEMF_node(XENMEMF_get_node(exch.out.mem_flags));
|
||||
|
||||
for ( i = (exch.nr_exchanged >> in_chunk_order);
|
||||
i < (exch.in.nr_extents >> in_chunk_order);
|
||||
@@ -359,7 +356,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
|
||||
p2m_type_t p2mt;
|
||||
|
||||
/* Shared pages cannot be exchanged */
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(d, gmfn + k, &p2mt, 0));
|
||||
mfn = mfn_x(gfn_to_mfn_unshare(p2m_get_hostp2m(d), gmfn + k, &p2mt, 0));
|
||||
if ( p2m_is_shared(p2mt) )
|
||||
{
|
||||
rc = -ENOMEM;
|
||||
@@ -545,7 +542,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
}
|
||||
|
||||
args.memflags |= MEMF_node(XENMEMF_get_node(reservation.mem_flags));
|
||||
if (reservation.mem_flags & XENMEMF_exact_node_request)
|
||||
if ( reservation.mem_flags & XENMEMF_exact_node_request )
|
||||
args.memflags |= MEMF_exact_node;
|
||||
|
||||
if ( op == XENMEM_populate_physmap
|
||||
|
||||
+47
-21
@@ -295,20 +295,29 @@ static unsigned long init_node_heap(int node, unsigned long mfn,
|
||||
/* Allocate 2^@order contiguous pages. */
|
||||
static struct page_info *alloc_heap_pages(
|
||||
unsigned int zone_lo, unsigned int zone_hi,
|
||||
unsigned int node, unsigned int order, unsigned int memflags)
|
||||
unsigned int order, unsigned int memflags,
|
||||
struct domain *d)
|
||||
{
|
||||
unsigned int i, j, zone = 0;
|
||||
unsigned int num_nodes = num_online_nodes();
|
||||
unsigned int first_node, i, j, zone = 0, nodemask_retry = 0;
|
||||
unsigned int node = (uint8_t)((memflags >> _MEMF_node) - 1);
|
||||
unsigned long request = 1UL << order;
|
||||
bool_t exact_node_request = !!(memflags & MEMF_exact_node);
|
||||
cpumask_t extra_cpus_mask, mask;
|
||||
struct page_info *pg;
|
||||
nodemask_t nodemask = (d != NULL ) ? d->node_affinity : node_online_map;
|
||||
|
||||
if ( node == NUMA_NO_NODE )
|
||||
{
|
||||
node = cpu_to_node(smp_processor_id());
|
||||
exact_node_request = 0;
|
||||
memflags &= ~MEMF_exact_node;
|
||||
if ( d != NULL )
|
||||
{
|
||||
node = next_node(d->last_alloc_node, nodemask);
|
||||
if ( node >= MAX_NUMNODES )
|
||||
node = first_node(nodemask);
|
||||
}
|
||||
if ( node >= MAX_NUMNODES )
|
||||
node = cpu_to_node(smp_processor_id());
|
||||
}
|
||||
first_node = node;
|
||||
|
||||
ASSERT(node >= 0);
|
||||
ASSERT(zone_lo <= zone_hi);
|
||||
@@ -335,7 +344,7 @@ static struct page_info *alloc_heap_pages(
|
||||
* zone before failing, only calc new node value if we fail to find memory
|
||||
* in target node, this avoids needless computation on fast-path.
|
||||
*/
|
||||
for ( i = 0; i < num_nodes; i++ )
|
||||
for ( ; ; )
|
||||
{
|
||||
zone = zone_hi;
|
||||
do {
|
||||
@@ -349,18 +358,35 @@ static struct page_info *alloc_heap_pages(
|
||||
goto found;
|
||||
} while ( zone-- > zone_lo ); /* careful: unsigned zone may wrap */
|
||||
|
||||
if ( exact_node_request )
|
||||
if ( memflags & MEMF_exact_node )
|
||||
goto not_found;
|
||||
|
||||
/* Pick next node, wrapping around if needed. */
|
||||
node = next_node(node, node_online_map);
|
||||
if (node == MAX_NUMNODES)
|
||||
node = first_node(node_online_map);
|
||||
/* Pick next node. */
|
||||
if ( !node_isset(node, nodemask) )
|
||||
{
|
||||
/* Very first node may be caller-specified and outside nodemask. */
|
||||
ASSERT(!nodemask_retry);
|
||||
first_node = node = first_node(nodemask);
|
||||
if ( node < MAX_NUMNODES )
|
||||
continue;
|
||||
}
|
||||
else if ( (node = next_node(node, nodemask)) >= MAX_NUMNODES )
|
||||
node = first_node(nodemask);
|
||||
if ( node == first_node )
|
||||
{
|
||||
/* When we have tried all in nodemask, we fall back to others. */
|
||||
if ( nodemask_retry++ )
|
||||
goto not_found;
|
||||
nodes_andnot(nodemask, node_online_map, nodemask);
|
||||
first_node = node = first_node(nodemask);
|
||||
if ( node >= MAX_NUMNODES )
|
||||
goto not_found;
|
||||
}
|
||||
}
|
||||
|
||||
try_tmem:
|
||||
/* Try to free memory from tmem */
|
||||
if ( (pg = tmem_relinquish_pages(order,memflags)) != NULL )
|
||||
if ( (pg = tmem_relinquish_pages(order, memflags)) != NULL )
|
||||
{
|
||||
/* reassigning an already allocated anonymous heap page */
|
||||
spin_unlock(&heap_lock);
|
||||
@@ -386,6 +412,9 @@ static struct page_info *alloc_heap_pages(
|
||||
total_avail_pages -= request;
|
||||
ASSERT(total_avail_pages >= 0);
|
||||
|
||||
if ( d != NULL )
|
||||
d->last_alloc_node = node;
|
||||
|
||||
spin_unlock(&heap_lock);
|
||||
|
||||
cpus_clear(mask);
|
||||
@@ -1010,7 +1039,7 @@ void *alloc_xenheap_pages(unsigned int order, unsigned int memflags)
|
||||
ASSERT(!in_irq());
|
||||
|
||||
pg = alloc_heap_pages(MEMZONE_XEN, MEMZONE_XEN,
|
||||
cpu_to_node(smp_processor_id()), order, memflags);
|
||||
order, memflags, NULL);
|
||||
if ( unlikely(pg == NULL) )
|
||||
return NULL;
|
||||
|
||||
@@ -1153,24 +1182,21 @@ struct page_info *alloc_domheap_pages(
|
||||
{
|
||||
struct page_info *pg = NULL;
|
||||
unsigned int bits = memflags >> _MEMF_bits, zone_hi = NR_ZONES - 1;
|
||||
unsigned int node = (uint8_t)((memflags >> _MEMF_node) - 1), dma_zone;
|
||||
unsigned int dma_zone;
|
||||
|
||||
ASSERT(!in_irq());
|
||||
|
||||
if ( (node == NUMA_NO_NODE) && (d != NULL) )
|
||||
node = domain_to_node(d);
|
||||
|
||||
bits = domain_clamp_alloc_bitsize(d, bits ? : (BITS_PER_LONG+PAGE_SHIFT));
|
||||
if ( (zone_hi = min_t(unsigned int, bits_to_zone(bits), zone_hi)) == 0 )
|
||||
return NULL;
|
||||
|
||||
if ( dma_bitsize && ((dma_zone = bits_to_zone(dma_bitsize)) < zone_hi) )
|
||||
pg = alloc_heap_pages(dma_zone + 1, zone_hi, node, order, memflags);
|
||||
pg = alloc_heap_pages(dma_zone + 1, zone_hi, order, memflags, d);
|
||||
|
||||
if ( (pg == NULL) &&
|
||||
((memflags & MEMF_no_dma) ||
|
||||
((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
|
||||
node, order, memflags)) == NULL)) )
|
||||
((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi, order,
|
||||
memflags, d)) == NULL)) )
|
||||
return NULL;
|
||||
|
||||
if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
/*
|
||||
* Flags
|
||||
*/
|
||||
#define CSCHED_FLAG_VCPU_PARKED 0x0001 /* VCPU over capped credits */
|
||||
#define CSCHED_FLAG_VCPU_PARKED 0x0001 /* VCPU over capped credits */
|
||||
#define CSCHED_FLAG_VCPU_YIELD 0x0002 /* VCPU yielding */
|
||||
|
||||
|
||||
/*
|
||||
@@ -107,6 +108,12 @@
|
||||
#endif /* CSCHED_STATS */
|
||||
|
||||
|
||||
/*
|
||||
* Boot parameters
|
||||
*/
|
||||
int sched_credit_default_yield = 0;
|
||||
boolean_param("sched_credit_default_yield", sched_credit_default_yield);
|
||||
|
||||
/*
|
||||
* Physical CPU
|
||||
*/
|
||||
@@ -202,6 +209,18 @@ __runq_insert(unsigned int cpu, struct csched_vcpu *svc)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the vcpu yielded, try to put it behind one lower-priority
|
||||
* runnable vcpu if we can. The next runq_sort will bring it forward
|
||||
* within 30ms if the queue too long. */
|
||||
if ( svc->flags & CSCHED_FLAG_VCPU_YIELD
|
||||
&& __runq_elem(iter)->pri > CSCHED_PRI_IDLE )
|
||||
{
|
||||
iter=iter->next;
|
||||
|
||||
/* Some sanity checks */
|
||||
BUG_ON(iter == runq);
|
||||
}
|
||||
|
||||
list_add_tail(&svc->runq_elem, iter);
|
||||
}
|
||||
|
||||
@@ -748,6 +767,18 @@ csched_vcpu_wake(const struct scheduler *ops, struct vcpu *vc)
|
||||
__runq_tickle(cpu, svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_yield(const struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const sv = CSCHED_VCPU(vc);
|
||||
|
||||
if ( !sched_credit_default_yield )
|
||||
{
|
||||
/* Let the scheduler know that this vcpu is trying to yield */
|
||||
sv->flags |= CSCHED_FLAG_VCPU_YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
csched_dom_cntl(
|
||||
const struct scheduler *ops,
|
||||
@@ -1069,7 +1100,9 @@ csched_acct(void* dummy)
|
||||
if ( credit > CSCHED_CREDITS_PER_TSLICE )
|
||||
{
|
||||
__csched_vcpu_acct_stop_locked(prv, svc);
|
||||
credit = 0;
|
||||
/* Divide credits in half, so that when it starts
|
||||
* accounting again, it starts a little bit "ahead" */
|
||||
credit /= 2;
|
||||
atomic_set(&svc->credit, credit);
|
||||
}
|
||||
}
|
||||
@@ -1281,6 +1314,12 @@ csched_schedule(
|
||||
snext->pri = CSCHED_PRI_TS_BOOST;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear YIELD flag before scheduling out
|
||||
*/
|
||||
if ( scurr->flags & CSCHED_FLAG_VCPU_YIELD )
|
||||
scurr->flags &= ~(CSCHED_FLAG_VCPU_YIELD);
|
||||
|
||||
/*
|
||||
* SMP Load balance:
|
||||
*
|
||||
@@ -1509,6 +1548,7 @@ const struct scheduler sched_credit_def = {
|
||||
|
||||
.sleep = csched_vcpu_sleep,
|
||||
.wake = csched_vcpu_wake,
|
||||
.yield = csched_vcpu_yield,
|
||||
|
||||
.adjust = csched_dom_cntl,
|
||||
|
||||
|
||||
+18
-1
@@ -276,6 +276,7 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
|
||||
|
||||
new_p = cycle_cpu(new_p, c->cpu_valid);
|
||||
}
|
||||
domain_update_node_affinity(d);
|
||||
|
||||
d->cpupool = c;
|
||||
SCHED_OP(DOM2OP(d), free_domdata, d->sched_priv);
|
||||
@@ -457,6 +458,7 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
struct vcpu *v;
|
||||
struct cpupool *c;
|
||||
int ret = 0;
|
||||
bool_t affinity_broken;
|
||||
|
||||
c = per_cpu(cpupool, cpu);
|
||||
if ( c == NULL )
|
||||
@@ -467,6 +469,8 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
if ( d->cpupool != c )
|
||||
continue;
|
||||
|
||||
affinity_broken = 0;
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
vcpu_schedule_lock_irq(v);
|
||||
@@ -477,6 +481,7 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
printk("Breaking vcpu affinity for domain %d vcpu %d\n",
|
||||
v->domain->domain_id, v->vcpu_id);
|
||||
cpus_setall(v->cpu_affinity);
|
||||
affinity_broken = 1;
|
||||
}
|
||||
|
||||
if ( v->processor == cpu )
|
||||
@@ -499,7 +504,11 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
if ( v->processor == cpu )
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
if ( affinity_broken )
|
||||
domain_update_node_affinity(d);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -525,6 +534,8 @@ int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity)
|
||||
|
||||
vcpu_schedule_unlock_irq(v);
|
||||
|
||||
domain_update_node_affinity(v->domain);
|
||||
|
||||
if ( test_bit(_VPF_migrating, &v->pause_flags) )
|
||||
{
|
||||
vcpu_sleep_nosync(v);
|
||||
@@ -631,6 +642,12 @@ static long do_poll(struct sched_poll *sched_poll)
|
||||
/* Voluntarily yield the processor for this allocation. */
|
||||
static long do_yield(void)
|
||||
{
|
||||
struct vcpu * v=current;
|
||||
|
||||
vcpu_schedule_lock_irq(v);
|
||||
SCHED_OP(VCPU2OP(v), yield, v);
|
||||
vcpu_schedule_unlock_irq(v);
|
||||
|
||||
TRACE_2D(TRC_SCHED_YIELD, current->domain->domain_id, current->vcpu_id);
|
||||
raise_softirq(SCHEDULE_SOFTIRQ);
|
||||
return 0;
|
||||
@@ -1296,7 +1313,7 @@ void schedule_cpu_switch(unsigned int cpu, struct cpupool *c)
|
||||
|
||||
spin_unlock_irqrestore(per_cpu(schedule_data, cpu).schedule_lock, flags);
|
||||
|
||||
SCHED_OP(old_ops, free_vdata, vpriv);
|
||||
SCHED_OP(old_ops, free_vdata, vpriv_old);
|
||||
SCHED_OP(old_ops, free_pdata, ppriv_old, cpu);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ static inline void *cli_mfn_to_va(tmem_cli_mfn_t cmfn, unsigned long *pcli_mfn)
|
||||
unsigned long cli_mfn;
|
||||
p2m_type_t t;
|
||||
|
||||
cli_mfn = mfn_x(gfn_to_mfn(current->domain, cmfn, &t));
|
||||
cli_mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(current->domain), cmfn, &t));
|
||||
if (t != p2m_ram_rw || cli_mfn == INVALID_MFN)
|
||||
return NULL;
|
||||
if (pcli_mfn != NULL)
|
||||
|
||||
@@ -881,6 +881,20 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
|
||||
case XENOPROF_ibs_counter:
|
||||
if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) ||
|
||||
(adomains == 0) )
|
||||
{
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = xenoprof_arch_ibs_counter(arg);
|
||||
break;
|
||||
|
||||
case XENOPROF_get_ibs_caps:
|
||||
ret = ibs_caps;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
@@ -440,14 +440,21 @@ void io_apic_write_remap_rte(
|
||||
{
|
||||
*IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
|
||||
*(IO_APIC_BASE(apic)+4) = value;
|
||||
|
||||
/* Recover the original value of 'mask' bit */
|
||||
if ( rte_upper )
|
||||
{
|
||||
*IO_APIC_BASE(apic) = reg;
|
||||
*(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* write new entry to ioapic */
|
||||
*IO_APIC_BASE(apic) = reg;
|
||||
*(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
|
||||
*IO_APIC_BASE(apic) = reg + 1;
|
||||
*(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
|
||||
*IO_APIC_BASE(apic) = reg;
|
||||
*(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
@@ -34,6 +34,13 @@ void xenoprof_arch_stop(void);
|
||||
void xenoprof_arch_disable_virq(void);
|
||||
void xenoprof_arch_release_counters(void);
|
||||
|
||||
static inline int xenoprof_arch_ibs_counter(XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
return -ENOSYS; /* not supported */
|
||||
}
|
||||
/* AMD IBS not supported */
|
||||
#define ibs_caps 0
|
||||
|
||||
struct vcpu;
|
||||
struct cpu_user_regs;
|
||||
int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
|
||||
|
||||
@@ -272,8 +272,8 @@ guest_walk_to_gpa(walk_t *gw)
|
||||
#define guest_walk_tables GPT_RENAME(guest_walk_tables, GUEST_PAGING_LEVELS)
|
||||
|
||||
extern uint32_t
|
||||
guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw,
|
||||
uint32_t pfec, mfn_t top_mfn, void *top_map);
|
||||
guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, unsigned long va,
|
||||
walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map);
|
||||
|
||||
/* Pretty-print the contents of a guest-walk */
|
||||
static inline void print_gw(walk_t *gw)
|
||||
|
||||
@@ -30,17 +30,17 @@
|
||||
typedef uint64_t shr_handle_t;
|
||||
|
||||
unsigned int mem_sharing_get_nr_saved_mfns(void);
|
||||
int mem_sharing_nominate_page(struct domain *d,
|
||||
int mem_sharing_nominate_page(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
int expected_refcnt,
|
||||
shr_handle_t *phandle);
|
||||
#define MEM_SHARING_MUST_SUCCEED (1<<0)
|
||||
#define MEM_SHARING_DESTROY_GFN (1<<1)
|
||||
int mem_sharing_unshare_page(struct domain *d,
|
||||
int mem_sharing_unshare_page(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
uint16_t flags);
|
||||
int mem_sharing_sharing_resume(struct domain *d);
|
||||
int mem_sharing_cache_resize(struct domain *d, int new_size);
|
||||
int mem_sharing_cache_resize(struct p2m_domain *p2m, int new_size);
|
||||
int mem_sharing_domctl(struct domain *d,
|
||||
xen_domctl_mem_sharing_op_t *mec);
|
||||
void mem_sharing_init(void);
|
||||
|
||||
+67
-53
@@ -172,23 +172,28 @@ struct p2m_domain {
|
||||
/* Shadow translated domain: p2m mapping */
|
||||
pagetable_t phys_table;
|
||||
|
||||
struct domain *domain; /* back pointer to domain */
|
||||
|
||||
/* Pages used to construct the p2m */
|
||||
struct page_list_head pages;
|
||||
|
||||
/* Functions to call to get or free pages for the p2m */
|
||||
struct page_info * (*alloc_page )(struct domain *d);
|
||||
void (*free_page )(struct domain *d,
|
||||
struct page_info * (*alloc_page )(struct p2m_domain *p2m);
|
||||
void (*free_page )(struct p2m_domain *p2m,
|
||||
struct page_info *pg);
|
||||
int (*set_entry )(struct domain *d, unsigned long gfn,
|
||||
int (*set_entry )(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
mfn_t mfn, unsigned int page_order,
|
||||
p2m_type_t p2mt);
|
||||
mfn_t (*get_entry )(struct domain *d, unsigned long gfn,
|
||||
mfn_t (*get_entry )(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
p2m_type_t *p2mt,
|
||||
p2m_query_t q);
|
||||
mfn_t (*get_entry_current)(unsigned long gfn,
|
||||
mfn_t (*get_entry_current)(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
p2m_type_t *p2mt,
|
||||
p2m_query_t q);
|
||||
void (*change_entry_type_global)(struct domain *d,
|
||||
void (*change_entry_type_global)(struct p2m_domain *p2m,
|
||||
p2m_type_t ot,
|
||||
p2m_type_t nt);
|
||||
|
||||
@@ -279,65 +284,64 @@ static inline p2m_type_t p2m_flags_to_type(unsigned long flags)
|
||||
}
|
||||
|
||||
/* Read the current domain's p2m table. Do not populate PoD pages. */
|
||||
static inline mfn_t gfn_to_mfn_type_current(unsigned long gfn, p2m_type_t *t,
|
||||
static inline mfn_t gfn_to_mfn_type_current(struct p2m_domain *p2m,
|
||||
unsigned long gfn, p2m_type_t *t,
|
||||
p2m_query_t q)
|
||||
{
|
||||
return current->domain->arch.p2m->get_entry_current(gfn, t, q);
|
||||
return p2m->get_entry_current(p2m, gfn, t, q);
|
||||
}
|
||||
|
||||
/* Read another domain's P2M table, mapping pages as we go.
|
||||
/* Read P2M table, mapping pages as we go.
|
||||
* Do not populate PoD pages. */
|
||||
static inline
|
||||
mfn_t gfn_to_mfn_type_foreign(struct domain *d, unsigned long gfn, p2m_type_t *t,
|
||||
p2m_query_t q)
|
||||
static inline mfn_t
|
||||
gfn_to_mfn_type_p2m(struct p2m_domain *p2m, unsigned long gfn,
|
||||
p2m_type_t *t, p2m_query_t q)
|
||||
{
|
||||
return d->arch.p2m->get_entry(d, gfn, t, q);
|
||||
return p2m->get_entry(p2m, gfn, t, q);
|
||||
}
|
||||
|
||||
|
||||
/* General conversion function from gfn to mfn */
|
||||
static inline mfn_t _gfn_to_mfn_type(struct domain *d,
|
||||
static inline mfn_t _gfn_to_mfn_type(struct p2m_domain *p2m,
|
||||
unsigned long gfn, p2m_type_t *t,
|
||||
p2m_query_t q)
|
||||
{
|
||||
if ( !paging_mode_translate(d) )
|
||||
if ( !p2m || !paging_mode_translate(p2m->domain) )
|
||||
{
|
||||
/* Not necessarily true, but for non-translated guests, we claim
|
||||
* it's the most generic kind of memory */
|
||||
*t = p2m_ram_rw;
|
||||
return _mfn(gfn);
|
||||
}
|
||||
if ( likely(current->domain == d) )
|
||||
return gfn_to_mfn_type_current(gfn, t, q);
|
||||
if ( likely(current->domain == p2m->domain) )
|
||||
return gfn_to_mfn_type_current(p2m, gfn, t, q);
|
||||
else
|
||||
return gfn_to_mfn_type_foreign(d, gfn, t, q);
|
||||
return gfn_to_mfn_type_p2m(p2m, gfn, t, q);
|
||||
}
|
||||
|
||||
#define gfn_to_mfn(d, g, t) _gfn_to_mfn_type((d), (g), (t), p2m_alloc)
|
||||
#define gfn_to_mfn_query(d, g, t) _gfn_to_mfn_type((d), (g), (t), p2m_query)
|
||||
#define gfn_to_mfn_guest(d, g, t) _gfn_to_mfn_type((d), (g), (t), p2m_guest)
|
||||
#define gfn_to_mfn(p2m, g, t) _gfn_to_mfn_type((p2m), (g), (t), p2m_alloc)
|
||||
#define gfn_to_mfn_query(p2m, g, t) _gfn_to_mfn_type((p2m), (g), (t), p2m_query)
|
||||
#define gfn_to_mfn_guest(p2m, g, t) _gfn_to_mfn_type((p2m), (g), (t), p2m_guest)
|
||||
|
||||
#define gfn_to_mfn_current(g, t) gfn_to_mfn_type_current((g), (t), p2m_alloc)
|
||||
#define gfn_to_mfn_foreign(d, g, t) gfn_to_mfn_type_foreign((d), (g), (t), p2m_alloc)
|
||||
|
||||
static inline mfn_t gfn_to_mfn_unshare(struct domain *d,
|
||||
static inline mfn_t gfn_to_mfn_unshare(struct p2m_domain *p2m,
|
||||
unsigned long gfn,
|
||||
p2m_type_t *p2mt,
|
||||
int must_succeed)
|
||||
{
|
||||
mfn_t mfn;
|
||||
|
||||
mfn = gfn_to_mfn(d, gfn, p2mt);
|
||||
mfn = gfn_to_mfn(p2m, gfn, p2mt);
|
||||
#ifdef __x86_64__
|
||||
if ( p2m_is_shared(*p2mt) )
|
||||
{
|
||||
if ( mem_sharing_unshare_page(d, gfn,
|
||||
if ( mem_sharing_unshare_page(p2m, gfn,
|
||||
must_succeed
|
||||
? MEM_SHARING_MUST_SUCCEED : 0) )
|
||||
{
|
||||
BUG_ON(must_succeed);
|
||||
return mfn;
|
||||
}
|
||||
mfn = gfn_to_mfn(d, gfn, p2mt);
|
||||
mfn = gfn_to_mfn(p2m, gfn, p2mt);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -350,7 +354,7 @@ static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gpfn)
|
||||
{
|
||||
mfn_t mfn;
|
||||
p2m_type_t t;
|
||||
mfn = gfn_to_mfn(d, gpfn, &t);
|
||||
mfn = gfn_to_mfn(d->arch.p2m, gpfn, &t);
|
||||
if ( p2m_is_valid(t) )
|
||||
return mfn_x(mfn);
|
||||
return INVALID_MFN;
|
||||
@@ -374,16 +378,16 @@ int p2m_init(struct domain *d);
|
||||
* build the p2m, and to release it again at the end of day.
|
||||
*
|
||||
* Returns 0 for success or -errno. */
|
||||
int p2m_alloc_table(struct domain *d,
|
||||
struct page_info * (*alloc_page)(struct domain *d),
|
||||
void (*free_page)(struct domain *d, struct page_info *pg));
|
||||
int p2m_alloc_table(struct p2m_domain *p2m,
|
||||
struct page_info * (*alloc_page)(struct p2m_domain *p2m),
|
||||
void (*free_page)(struct p2m_domain *p2m, struct page_info *pg));
|
||||
|
||||
/* Return all the p2m resources to Xen. */
|
||||
void p2m_teardown(struct domain *d);
|
||||
void p2m_teardown(struct p2m_domain *p2m);
|
||||
void p2m_final_teardown(struct domain *d);
|
||||
|
||||
/* Dump PoD information about the domain */
|
||||
void p2m_pod_dump_data(struct domain *d);
|
||||
void p2m_pod_dump_data(struct p2m_domain *p2m);
|
||||
|
||||
/* Move all pages from the populate-on-demand cache to the domain page_list
|
||||
* (usually in preparation for domain destruction) */
|
||||
@@ -402,15 +406,19 @@ p2m_pod_decrease_reservation(struct domain *d,
|
||||
|
||||
/* Called by p2m code when demand-populating a PoD page */
|
||||
int
|
||||
p2m_pod_demand_populate(struct domain *d, unsigned long gfn,
|
||||
p2m_pod_demand_populate(struct p2m_domain *p2m, unsigned long gfn,
|
||||
unsigned int order,
|
||||
p2m_query_t q);
|
||||
|
||||
/* Add a page to a domain's p2m table */
|
||||
int guest_physmap_add_entry(struct domain *d, unsigned long gfn,
|
||||
int guest_physmap_add_entry(struct p2m_domain *p2m, unsigned long gfn,
|
||||
unsigned long mfn, unsigned int page_order,
|
||||
p2m_type_t t);
|
||||
|
||||
/* Remove a page from a domain's p2m table */
|
||||
void guest_physmap_remove_entry(struct p2m_domain *p2m, unsigned long gfn,
|
||||
unsigned long mfn, unsigned int page_order);
|
||||
|
||||
/* Set a p2m range as populate-on-demand */
|
||||
int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
|
||||
unsigned int order);
|
||||
@@ -419,49 +427,55 @@ int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
|
||||
*
|
||||
* Return 0 for success
|
||||
*/
|
||||
static inline int guest_physmap_add_page(struct domain *d, unsigned long gfn,
|
||||
static inline int guest_physmap_add_page(struct domain *d,
|
||||
unsigned long gfn,
|
||||
unsigned long mfn,
|
||||
unsigned int page_order)
|
||||
{
|
||||
return guest_physmap_add_entry(d, gfn, mfn, page_order, p2m_ram_rw);
|
||||
return guest_physmap_add_entry(d->arch.p2m, 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 int page_order);
|
||||
static inline void guest_physmap_remove_page(struct domain *d,
|
||||
unsigned long gfn,
|
||||
unsigned long mfn, unsigned int page_order)
|
||||
{
|
||||
guest_physmap_remove_entry(d->arch.p2m, gfn, mfn, 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);
|
||||
void p2m_change_entry_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt);
|
||||
void p2m_change_type_global(struct p2m_domain *p2m, p2m_type_t ot, p2m_type_t nt);
|
||||
void p2m_change_entry_type_global(struct p2m_domain *p2m, p2m_type_t ot, p2m_type_t nt);
|
||||
|
||||
/* Compare-exchange the type of a single p2m entry */
|
||||
p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,
|
||||
p2m_type_t p2m_change_type(struct p2m_domain *p2m, unsigned long gfn,
|
||||
p2m_type_t ot, p2m_type_t nt);
|
||||
|
||||
/* Set mmio addresses in the p2m table (for pass-through) */
|
||||
int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn);
|
||||
int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn);
|
||||
int set_mmio_p2m_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn);
|
||||
int clear_mmio_p2m_entry(struct p2m_domain *p2m, unsigned long gfn);
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* Modify p2m table for shared gfn */
|
||||
int set_shared_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn);
|
||||
int set_shared_p2m_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn);
|
||||
|
||||
/* Check if a nominated gfn is valid to be paged out */
|
||||
int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn);
|
||||
int p2m_mem_paging_nominate(struct p2m_domain *p2m, unsigned long gfn);
|
||||
/* Evict a frame */
|
||||
int p2m_mem_paging_evict(struct domain *d, unsigned long gfn);
|
||||
int p2m_mem_paging_evict(struct p2m_domain *p2m, unsigned long gfn);
|
||||
/* Start populating a paged out frame */
|
||||
void p2m_mem_paging_populate(struct domain *d, unsigned long gfn);
|
||||
void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn);
|
||||
/* Prepare the p2m for paging a frame in */
|
||||
int p2m_mem_paging_prep(struct domain *d, unsigned long gfn);
|
||||
int p2m_mem_paging_prep(struct p2m_domain *p2m, unsigned long gfn);
|
||||
/* Resume normal operation (in case a domain was paused) */
|
||||
void p2m_mem_paging_resume(struct domain *d);
|
||||
void p2m_mem_paging_resume(struct p2m_domain *p2m);
|
||||
#else
|
||||
static inline void p2m_mem_paging_populate(struct domain *d, unsigned long gfn)
|
||||
static inline void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
struct page_info *p2m_alloc_ptp(struct domain *d, unsigned long type);
|
||||
struct page_info *p2m_alloc_ptp(struct p2m_domain *p2m, unsigned long type);
|
||||
|
||||
#endif /* _XEN_P2M_H */
|
||||
|
||||
|
||||
@@ -42,10 +42,15 @@ int xenoprof_arch_init(int *num_events, char *cpu_type);
|
||||
|
||||
int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
|
||||
int compat_oprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
|
||||
int xenoprof_arch_ibs_counter(XEN_GUEST_HANDLE(void) arg);
|
||||
|
||||
struct vcpu;
|
||||
struct cpu_user_regs;
|
||||
|
||||
/* AMD IBS support */
|
||||
u32 ibs_init(void);
|
||||
extern u32 ibs_caps;
|
||||
|
||||
int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
|
||||
|
||||
static inline int xenoprof_backtrace_supported(void)
|
||||
|
||||
@@ -50,7 +50,11 @@
|
||||
#define XENOPROF_shutdown 13
|
||||
#define XENOPROF_get_buffer 14
|
||||
#define XENOPROF_set_backtrace 15
|
||||
#define XENOPROF_last_op 15
|
||||
|
||||
/* AMD IBS support */
|
||||
#define XENOPROF_get_ibs_caps 16
|
||||
#define XENOPROF_ibs_counter 17
|
||||
#define XENOPROF_last_op 17
|
||||
|
||||
#define MAX_OPROF_EVENTS 32
|
||||
#define MAX_OPROF_DOMAINS 25
|
||||
@@ -124,6 +128,16 @@ typedef struct xenoprof_passive {
|
||||
} xenoprof_passive_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t);
|
||||
|
||||
struct xenoprof_ibs_counter {
|
||||
uint64_t op_enabled;
|
||||
uint64_t fetch_enabled;
|
||||
uint64_t max_cnt_fetch;
|
||||
uint64_t max_cnt_op;
|
||||
uint64_t rand_en;
|
||||
uint64_t dispatched_ops;
|
||||
};
|
||||
typedef struct xenoprof_ibs_counter xenoprof_ibs_counter_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xenoprof_ibs_counter_t);
|
||||
|
||||
#endif /* __XEN_PUBLIC_XENOPROF_H__ */
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ struct scheduler {
|
||||
|
||||
void (*sleep) (const struct scheduler *, struct vcpu *);
|
||||
void (*wake) (const struct scheduler *, struct vcpu *);
|
||||
void (*yield) (const struct scheduler *, struct vcpu *);
|
||||
void (*context_saved) (const struct scheduler *, struct vcpu *);
|
||||
|
||||
struct task_slice (*do_schedule) (const struct scheduler *, s_time_t,
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <xen/mm.h>
|
||||
#include <xen/tasklet.h>
|
||||
#include <public/mem_event.h>
|
||||
#include <xen/cpumask.h>
|
||||
#include <xen/nodemask.h>
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <compat/vcpu.h>
|
||||
@@ -326,6 +328,11 @@ struct domain
|
||||
|
||||
/* Memory paging support */
|
||||
struct mem_event_domain mem_event;
|
||||
|
||||
/* Currently computed from union of all vcpu cpu-affinity masks. */
|
||||
nodemask_t node_affinity;
|
||||
unsigned int last_alloc_node;
|
||||
spinlock_t node_affinity_lock;
|
||||
};
|
||||
|
||||
struct domain_setup_info
|
||||
@@ -393,6 +400,8 @@ static inline void get_knownalive_domain(struct domain *d)
|
||||
ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTROYED));
|
||||
}
|
||||
|
||||
void domain_update_node_affinity(struct domain *d);
|
||||
|
||||
struct domain *domain_create(
|
||||
domid_t domid, unsigned int domcr_flags, ssidref_t ssidref);
|
||||
/* DOMCRF_hvm: Create an HVM domain, as opposed to a PV domain. */
|
||||
|
||||