x86: populating PML4e and PDPTe is now lock-free
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user