flush_area_local((const void *)v, f) : \
flush_area_all((const void *)v, f))
+/* Shatter an l3 entry and populate l2. If virt is passed in, also do flush. */
+static int shatter_l3e(l3_pgentry_t *pl3e, unsigned long virt, bool locking)
+{
+ unsigned int i;
+ l3_pgentry_t ol3e = *pl3e;
+ l2_pgentry_t l2e = l2e_from_intpte(l3e_get_intpte(ol3e));
+ l2_pgentry_t *l2t = alloc_xen_pagetable();
+
+ if ( !l2t )
+ return -ENOMEM;
+
+ for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
+ {
+ l2e_write(l2t + i, l2e);
+ l2e = l2e_from_intpte(
+ l2e_get_intpte(l2e) + (PAGE_SIZE << PAGETABLE_ORDER));
+ }
+
+ if ( locking )
+ spin_lock(&map_pgdir_lock);
+ if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) &&
+ (l3e_get_flags(*pl3e) & _PAGE_PSE) )
+ {
+ l3e_write_atomic(pl3e,
+ l3e_from_paddr((paddr_t)virt_to_maddr(l2t), __PAGE_HYPERVISOR));
+ l2t = NULL;
+ }
+ if ( locking )
+ spin_unlock(&map_pgdir_lock);
+
+ if ( virt )
+ {
+ unsigned int flush_flags =
+ FLUSH_TLB | FLUSH_ORDER(2 * PAGETABLE_ORDER);
+
+ if ( l3e_get_flags(ol3e) & _PAGE_GLOBAL )
+ flush_flags |= FLUSH_TLB_GLOBAL;
+ flush_area(virt, flush_flags);
+ }
+
+ if ( l2t )
+ free_xen_pagetable(l2t);
+
+ return 0;
+}
+
int map_pages_to_xen(
unsigned long virt,
mfn_t mfn,
if ( (l3e_get_flags(ol3e) & _PAGE_PRESENT) &&
(l3e_get_flags(ol3e) & _PAGE_PSE) )
{
- unsigned int flush_flags =
- FLUSH_TLB | FLUSH_ORDER(2 * PAGETABLE_ORDER);
-
/* Skip this PTE if there is no change. */
if ( ((l3e_get_pfn(ol3e) & ~(L2_PAGETABLE_ENTRIES *
L1_PAGETABLE_ENTRIES - 1)) +
continue;
}
- pl2e = alloc_xen_pagetable();
- if ( pl2e == NULL )
+ /* Pass virt to indicate we need to flush. */
+ if ( shatter_l3e(pl3e, virt, locking) )
return -ENOMEM;
-
- for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
- l2e_write(pl2e + i,
- l2e_from_pfn(l3e_get_pfn(ol3e) +
- (i << PAGETABLE_ORDER),
- l3e_get_flags(ol3e)));
-
- if ( l3e_get_flags(ol3e) & _PAGE_GLOBAL )
- flush_flags |= FLUSH_TLB_GLOBAL;
-
- if ( locking )
- spin_lock(&map_pgdir_lock);
- if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) &&
- (l3e_get_flags(*pl3e) & _PAGE_PSE) )
- {
- l3e_write_atomic(pl3e, l3e_from_mfn(virt_to_mfn(pl2e),
- __PAGE_HYPERVISOR));
- pl2e = NULL;
- }
- if ( locking )
- spin_unlock(&map_pgdir_lock);
- flush_area(virt, flush_flags);
- if ( pl2e )
- free_xen_pagetable(pl2e);
}
pl2e = virt_to_xen_l2e(virt);
}
/* PAGE1GB: shatter the superpage and fall through. */
- pl2e = alloc_xen_pagetable();
- if ( !pl2e )
+ if ( shatter_l3e(pl3e, 0, locking) )
return -ENOMEM;
- for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
- l2e_write(pl2e + i,
- l2e_from_pfn(l3e_get_pfn(*pl3e) +
- (i << PAGETABLE_ORDER),
- l3e_get_flags(*pl3e)));
- if ( locking )
- spin_lock(&map_pgdir_lock);
- if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) &&
- (l3e_get_flags(*pl3e) & _PAGE_PSE) )
- {
- l3e_write_atomic(pl3e, l3e_from_mfn(virt_to_mfn(pl2e),
- __PAGE_HYPERVISOR));
- pl2e = NULL;
- }
- if ( locking )
- spin_unlock(&map_pgdir_lock);
- if ( pl2e )
- free_xen_pagetable(pl2e);
}
/*