x86: populating PML4e and PDPTe is now lock-free

This commit is contained in:
NAKAMURA Gou
2016-01-22 15:57:30 +09:00
parent 368f155328
commit f093786bec

View File

@@ -1653,15 +1653,18 @@ out:
int set_range_l3(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start, int set_range_l3(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start,
uintptr_t end) uintptr_t end)
{ {
struct set_range_args *args = args0; struct page_table *newpt = NULL;
pte_t pte;
struct page_table *pt; struct page_table *pt;
int error; int error;
#ifdef USE_LARGE_PAGES #ifdef USE_LARGE_PAGES
struct set_range_args *args = args0;
uintptr_t phys; uintptr_t phys;
#endif #endif
dkprintf("set_range_l3(%lx,%lx,%lx)\n", base, start, end); dkprintf("set_range_l3(%lx,%lx,%lx)\n", base, start, end);
retry:
if (*ptep == PTE_NULL) { if (*ptep == PTE_NULL) {
#ifdef USE_LARGE_PAGES #ifdef USE_LARGE_PAGES
if ((start <= base) && ((base + PTL3_SIZE) <= end) if ((start <= base) && ((base + PTL3_SIZE) <= end)
@@ -1678,24 +1681,32 @@ int set_range_l3(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start,
} }
#endif #endif
pt = __alloc_new_pt(IHK_MC_AP_NOWAIT); if (!newpt) {
if (pt == NULL) { newpt = __alloc_new_pt(IHK_MC_AP_NOWAIT);
error = -ENOMEM; if (newpt == NULL) {
ekprintf("set_range_l3(%lx,%lx,%lx):" error = -ENOMEM;
"__alloc_new_pt failed. %d %lx\n", ekprintf("set_range_l3(%lx,%lx,%lx):"
base, start, end, error, *ptep); "__alloc_new_pt failed. %d %lx\n",
(void)clear_range(args->pt, args->vm, start, base, base, start, end, error, *ptep);
KEEP_PHYSICAL, NULL); goto out;
goto out; }
} }
*ptep = virt_to_phys(pt) | PFL3_PDIR_ATTR;
pte = virt_to_phys(newpt) | PFL3_PDIR_ATTR;
pte = atomic_cmpxchg8(ptep, PTE_NULL, pte);
if (pte != PTE_NULL) {
/* failed to set PDPTe */
goto retry;
}
pt = newpt;
newpt = NULL;
} }
else if (*ptep & PFL3_SIZE) { else if (*ptep & PFL3_SIZE) {
error = -EBUSY; error = -EBUSY;
ekprintf("set_range_l3(%lx,%lx,%lx):" ekprintf("set_range_l3(%lx,%lx,%lx):"
"page exists. %d %lx\n", "page exists. %d %lx\n",
base, start, end, error, *ptep); base, start, end, error, *ptep);
(void)clear_range(args->pt, args->vm, start, base, KEEP_PHYSICAL, NULL);
goto out; goto out;
} }
else { else {
@@ -1712,6 +1723,9 @@ int set_range_l3(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start,
error = 0; error = 0;
out: out:
if (newpt) {
arch_free_page(newpt);
}
dkprintf("set_range_l3(%lx,%lx,%lx): %d\n", dkprintf("set_range_l3(%lx,%lx,%lx): %d\n",
base, start, end, error, *ptep); base, start, end, error, *ptep);
return error; return error;
@@ -1720,24 +1734,35 @@ out:
int set_range_l4(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start, int set_range_l4(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start,
uintptr_t end) uintptr_t end)
{ {
struct set_range_args *args = args0; struct page_table *newpt = NULL;
pte_t pte;
struct page_table *pt; struct page_table *pt;
int error; int error;
dkprintf("set_range_l4(%lx,%lx,%lx)\n", base, start, end); dkprintf("set_range_l4(%lx,%lx,%lx)\n", base, start, end);
retry:
if (*ptep == PTE_NULL) { if (*ptep == PTE_NULL) {
pt = __alloc_new_pt(IHK_MC_AP_NOWAIT); if (!newpt) {
if (pt == NULL) { newpt = __alloc_new_pt(IHK_MC_AP_NOWAIT);
error = -ENOMEM; if (newpt == NULL) {
ekprintf("set_range_l4(%lx,%lx,%lx):" error = -ENOMEM;
"__alloc_new_pt failed. %d %lx\n", ekprintf("set_range_l4(%lx,%lx,%lx):"
base, start, end, error, *ptep); "__alloc_new_pt failed. %d %lx\n",
(void)clear_range(args->pt, args->vm, start, base, base, start, end, error, *ptep);
KEEP_PHYSICAL, NULL); goto out;
goto out; }
} }
*ptep = virt_to_phys(pt) | PFL4_PDIR_ATTR;
pte = virt_to_phys(newpt) | PFL4_PDIR_ATTR;
pte = atomic_cmpxchg8(ptep, PTE_NULL, pte);
if (pte != PTE_NULL) {
/* failed to set PML4e */
goto retry;
}
pt = newpt;
newpt = NULL;
} }
else { else {
pt = phys_to_virt(*ptep & PT_PHYSMASK); pt = phys_to_virt(*ptep & PT_PHYSMASK);
@@ -1753,6 +1778,9 @@ int set_range_l4(void *args0, pte_t *ptep, uintptr_t base, uintptr_t start,
error = 0; error = 0;
out: out:
if (newpt) {
arch_free_page(newpt);
}
dkprintf("set_range_l4(%lx,%lx,%lx): %d %lx\n", dkprintf("set_range_l4(%lx,%lx,%lx): %d %lx\n",
base, start, end, error, *ptep); base, start, end, error, *ptep);
return error; return error;