Skip to content

Commit 82f0712

Browse files
suryasaimadhuMatt Fleming
authored andcommitted
x86/mm/cpa: Map in an arbitrary pgd
Add the ability to map pages in an arbitrary pgd. This wires in the remaining stuff so that there's a new interface with which you can map a region into an arbitrary PGD. Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
1 parent 52a628f commit 82f0712

File tree

1 file changed

+46
-7
lines changed

1 file changed

+46
-7
lines changed

arch/x86/mm/pageattr.c

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
453453
* Check for races, another CPU might have split this page
454454
* up already:
455455
*/
456-
tmp = lookup_address(address, &level);
456+
tmp = _lookup_address_cpa(cpa, address, &level);
457457
if (tmp != kpte)
458458
goto out_unlock;
459459

@@ -559,7 +559,8 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
559559
}
560560

561561
static int
562-
__split_large_page(pte_t *kpte, unsigned long address, struct page *base)
562+
__split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
563+
struct page *base)
563564
{
564565
pte_t *pbase = (pte_t *)page_address(base);
565566
unsigned long pfn, pfninc = 1;
@@ -572,7 +573,7 @@ __split_large_page(pte_t *kpte, unsigned long address, struct page *base)
572573
* Check for races, another CPU might have split this page
573574
* up for us already:
574575
*/
575-
tmp = lookup_address(address, &level);
576+
tmp = _lookup_address_cpa(cpa, address, &level);
576577
if (tmp != kpte) {
577578
spin_unlock(&pgd_lock);
578579
return 1;
@@ -648,7 +649,8 @@ __split_large_page(pte_t *kpte, unsigned long address, struct page *base)
648649
return 0;
649650
}
650651

651-
static int split_large_page(pte_t *kpte, unsigned long address)
652+
static int split_large_page(struct cpa_data *cpa, pte_t *kpte,
653+
unsigned long address)
652654
{
653655
struct page *base;
654656

@@ -660,7 +662,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
660662
if (!base)
661663
return -ENOMEM;
662664

663-
if (__split_large_page(kpte, address, base))
665+
if (__split_large_page(cpa, kpte, address, base))
664666
__free_page(base);
665667

666668
return 0;
@@ -1041,6 +1043,9 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
10411043
static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr,
10421044
int primary)
10431045
{
1046+
if (cpa->pgd)
1047+
return populate_pgd(cpa, vaddr);
1048+
10441049
/*
10451050
* Ignore all non primary paths.
10461051
*/
@@ -1085,7 +1090,7 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)
10851090
else
10861091
address = *cpa->vaddr;
10871092
repeat:
1088-
kpte = lookup_address(address, &level);
1093+
kpte = _lookup_address_cpa(cpa, address, &level);
10891094
if (!kpte)
10901095
return __cpa_process_fault(cpa, address, primary);
10911096

@@ -1149,7 +1154,7 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)
11491154
/*
11501155
* We have to split the large page:
11511156
*/
1152-
err = split_large_page(kpte, address);
1157+
err = split_large_page(cpa, kpte, address);
11531158
if (!err) {
11541159
/*
11551160
* Do a global flush tlb after splitting the large page
@@ -1298,6 +1303,8 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
12981303
int ret, cache, checkalias;
12991304
unsigned long baddr = 0;
13001305

1306+
memset(&cpa, 0, sizeof(cpa));
1307+
13011308
/*
13021309
* Check, if we are requested to change a not supported
13031310
* feature:
@@ -1744,6 +1751,7 @@ static int __set_pages_p(struct page *page, int numpages)
17441751
{
17451752
unsigned long tempaddr = (unsigned long) page_address(page);
17461753
struct cpa_data cpa = { .vaddr = &tempaddr,
1754+
.pgd = NULL,
17471755
.numpages = numpages,
17481756
.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
17491757
.mask_clr = __pgprot(0),
@@ -1762,6 +1770,7 @@ static int __set_pages_np(struct page *page, int numpages)
17621770
{
17631771
unsigned long tempaddr = (unsigned long) page_address(page);
17641772
struct cpa_data cpa = { .vaddr = &tempaddr,
1773+
.pgd = NULL,
17651774
.numpages = numpages,
17661775
.mask_set = __pgprot(0),
17671776
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW),
@@ -1822,6 +1831,36 @@ bool kernel_page_present(struct page *page)
18221831

18231832
#endif /* CONFIG_DEBUG_PAGEALLOC */
18241833

1834+
int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
1835+
unsigned numpages, unsigned long page_flags)
1836+
{
1837+
int retval = -EINVAL;
1838+
1839+
struct cpa_data cpa = {
1840+
.vaddr = &address,
1841+
.pfn = pfn,
1842+
.pgd = pgd,
1843+
.numpages = numpages,
1844+
.mask_set = __pgprot(0),
1845+
.mask_clr = __pgprot(0),
1846+
.flags = 0,
1847+
};
1848+
1849+
if (!(__supported_pte_mask & _PAGE_NX))
1850+
goto out;
1851+
1852+
if (!(page_flags & _PAGE_NX))
1853+
cpa.mask_clr = __pgprot(_PAGE_NX);
1854+
1855+
cpa.mask_set = __pgprot(_PAGE_PRESENT | page_flags);
1856+
1857+
retval = __change_page_attr_set_clr(&cpa, 0);
1858+
__flush_tlb_all();
1859+
1860+
out:
1861+
return retval;
1862+
}
1863+
18251864
/*
18261865
* The testcases use internal knowledge of the implementation that shouldn't
18271866
* be exposed to the rest of the kernel. Include these directly here.

0 commit comments

Comments
 (0)