static void vmx_ctxt_switch_from(struct vcpu *v);
static void vmx_ctxt_switch_to(struct vcpu *v);
-static int vmx_alloc_vlapic_mapping(struct domain *d);
-static void vmx_free_vlapic_mapping(struct domain *d);
+static int alloc_vlapic_mapping(void);
static void vmx_install_vlapic_mapping(struct vcpu *v);
static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr,
unsigned int flags);
static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content);
static void vmx_invlpg(struct vcpu *v, unsigned long linear);
+static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER;
+
/* Values for domain's ->arch.hvm_domain.pi_ops.flags. */
#define PI_CSW_FROM (1u << 0)
#define PI_CSW_TO (1u << 1)
.to = vmx_ctxt_switch_to,
.tail = vmx_do_resume,
};
- int rc;
d->arch.ctxt_switch = &csw;
*/
d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp;
- if ( !has_vlapic(d) )
- return 0;
-
- if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
- return rc;
-
return 0;
}
-static void vmx_domain_relinquish_resources(struct domain *d)
+static void domain_creation_finished(struct domain *d)
{
- if ( !has_vlapic(d) )
+ gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE);
+ uint8_t ipat;
+
+ if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) )
return;
- vmx_free_vlapic_mapping(d);
-}
+ ASSERT(epte_get_entry_emt(d, gfn_x(gfn), apic_access_mfn, 0, &ipat,
+ true) == MTRR_TYPE_WRBACK);
+ ASSERT(ipat);
-static void domain_creation_finished(struct domain *d)
-{
- if ( has_vlapic(d) && !mfn_eq(d->arch.hvm.vmx.apic_access_mfn, _mfn(0)) &&
- set_mmio_p2m_entry(d, gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE),
- d->arch.hvm.vmx.apic_access_mfn, PAGE_ORDER_4K) )
+ if ( set_mmio_p2m_entry(d, gfn, apic_access_mfn, PAGE_ORDER_4K) )
domain_crash(d);
}
.cpu_up_prepare = vmx_cpu_up_prepare,
.cpu_dead = vmx_cpu_dead,
.domain_initialise = vmx_domain_initialise,
- .domain_relinquish_resources = vmx_domain_relinquish_resources,
.domain_creation_finished = domain_creation_finished,
.vcpu_initialise = vmx_vcpu_initialise,
.vcpu_destroy = vmx_vcpu_destroy,
{
set_in_cr4(X86_CR4_VMXE);
- if ( vmx_vmcs_init() )
+ if ( vmx_vmcs_init() || alloc_vlapic_mapping() )
{
printk("VMX: failed to initialise.\n");
return NULL;
return X86EMUL_EXCEPTION;
}
-static int vmx_alloc_vlapic_mapping(struct domain *d)
+static int __init alloc_vlapic_mapping(void)
{
struct page_info *pg;
mfn_t mfn;
if ( !cpu_has_vmx_virtualize_apic_accesses )
return 0;
- pg = alloc_domheap_page(d, MEMF_no_refcount);
+ pg = alloc_domheap_page(NULL, 0);
if ( !pg )
return -ENOMEM;
- if ( !get_page_and_type(pg, d, PGT_writable_page) )
- {
- /*
- * The domain can't possibly know about this page yet, so failure
- * here is a clear indication of something fishy going on.
- */
- domain_crash(d);
- return -ENODATA;
- }
+ /*
+ * Signal to shadow code that this page cannot be refcounted. This also
+ * makes epte_get_entry_emt() recognize this page as "special".
+ */
+ page_suppress_refcounting(pg);
mfn = page_to_mfn(pg);
clear_domain_page(mfn);
- d->arch.hvm.vmx.apic_access_mfn = mfn;
+ apic_access_mfn = mfn;
return 0;
}
-static void vmx_free_vlapic_mapping(struct domain *d)
-{
- mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn;
-
- d->arch.hvm.vmx.apic_access_mfn = _mfn(0);
- if ( !mfn_eq(mfn, _mfn(0)) )
- {
- struct page_info *pg = mfn_to_page(mfn);
-
- put_page_alloc_ref(pg);
- put_page_and_type(pg);
- }
-}
-
static void vmx_install_vlapic_mapping(struct vcpu *v)
{
paddr_t virt_page_ma, apic_page_ma;
- if ( mfn_eq(v->domain->arch.hvm.vmx.apic_access_mfn, _mfn(0)) )
+ if ( !has_vlapic(v->domain) || mfn_eq(apic_access_mfn, INVALID_MFN) )
return;
ASSERT(cpu_has_vmx_virtualize_apic_accesses);
virt_page_ma = page_to_maddr(vcpu_vlapic(v)->regs_page);
- apic_page_ma = mfn_to_maddr(v->domain->arch.hvm.vmx.apic_access_mfn);
+ apic_page_ma = mfn_to_maddr(apic_access_mfn);
vmx_vmcs_enter(v);
__vmwrite(VIRTUAL_APIC_PAGE_ADDR, virt_page_ma);
#define PGC_state_offlined PG_mask(2, 9)
#define PGC_state_free PG_mask(3, 9)
#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
-/* Page is not reference counted */
+/* Page is not reference counted (see below for caveats) */
#define _PGC_extra PG_shift(10)
#define PGC_extra PG_mask(1, 10)
bool is_iomem_page(mfn_t mfn);
+/*
+ * Pages with no owner which may get passed to functions wanting to
+ * refcount them can be marked PGC_extra to bypass this refcounting (which
+ * would fail due to the lack of an owner).
+ *
+ * (For pages with owner PGC_extra has different meaning.)
+ */
+static inline void page_suppress_refcounting(struct page_info *pg)
+{
+ ASSERT(!page_get_owner(pg));
+ pg->count_info |= PGC_extra;
+}
+
+static inline bool page_refcounting_suppressed(const struct page_info *pg)
+{
+ return !page_get_owner(pg) && (pg->count_info & PGC_extra);
+}
+
struct platform_bad_page {
unsigned long mfn;
unsigned int order;