diff options
Diffstat (limited to 'arch/x86/mm/mem_encrypt.c')
| -rw-r--r-- | arch/x86/mm/mem_encrypt.c | 72 | 
1 files changed, 63 insertions, 9 deletions
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 23d54b810f08..35487305d8af 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -229,28 +229,75 @@ void __init sev_setup_arch(void)  	swiotlb_adjust_size(size);  } -static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc) +static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot)  { -	pgprot_t old_prot, new_prot; -	unsigned long pfn, pa, size; -	pte_t new_pte; +	unsigned long pfn = 0; +	pgprot_t prot;  	switch (level) {  	case PG_LEVEL_4K:  		pfn = pte_pfn(*kpte); -		old_prot = pte_pgprot(*kpte); +		prot = pte_pgprot(*kpte);  		break;  	case PG_LEVEL_2M:  		pfn = pmd_pfn(*(pmd_t *)kpte); -		old_prot = pmd_pgprot(*(pmd_t *)kpte); +		prot = pmd_pgprot(*(pmd_t *)kpte);  		break;  	case PG_LEVEL_1G:  		pfn = pud_pfn(*(pud_t *)kpte); -		old_prot = pud_pgprot(*(pud_t *)kpte); +		prot = pud_pgprot(*(pud_t *)kpte);  		break;  	default: -		return; +		WARN_ONCE(1, "Invalid level for kpte\n"); +		return 0; +	} + +	if (ret_prot) +		*ret_prot = prot; + +	return pfn; +} + +void notify_range_enc_status_changed(unsigned long vaddr, int npages, bool enc) +{ +#ifdef CONFIG_PARAVIRT +	unsigned long sz = npages << PAGE_SHIFT; +	unsigned long vaddr_end = vaddr + sz; + +	while (vaddr < vaddr_end) { +		int psize, pmask, level; +		unsigned long pfn; +		pte_t *kpte; + +		kpte = lookup_address(vaddr, &level); +		if (!kpte || pte_none(*kpte)) { +			WARN_ONCE(1, "kpte lookup for vaddr\n"); +			return; +		} + +		pfn = pg_level_to_pfn(level, kpte, NULL); +		if (!pfn) +			continue; + +		psize = page_level_size(level); +		pmask = page_level_mask(level); + +		notify_page_enc_status_changed(pfn, psize >> PAGE_SHIFT, enc); + +		vaddr = (vaddr & pmask) + psize;  	} +#endif +} + +static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc) +{ +	pgprot_t old_prot, new_prot; +	unsigned long pfn, pa, size; +	pte_t new_pte; + +	pfn = pg_level_to_pfn(level, kpte, &old_prot); +	if (!pfn) +		return;  	new_prot = old_prot;  	if (enc) @@ -286,12 +333,13 @@ static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)  static int __init early_set_memory_enc_dec(unsigned long vaddr,  					   unsigned long size, bool enc)  { -	unsigned long vaddr_end, vaddr_next; +	unsigned long vaddr_end, vaddr_next, start;  	unsigned long psize, pmask;  	int split_page_size_mask;  	int level, ret;  	pte_t *kpte; +	start = vaddr;  	vaddr_next = vaddr;  	vaddr_end = vaddr + size; @@ -346,6 +394,7 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr,  	ret = 0; +	notify_range_enc_status_changed(start, PAGE_ALIGN(size) >> PAGE_SHIFT, enc);  out:  	__flush_tlb_all();  	return ret; @@ -361,6 +410,11 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size)  	return early_set_memory_enc_dec(vaddr, size, true);  } +void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) +{ +	notify_range_enc_status_changed(vaddr, npages, enc); +} +  /* Override for DMA direct allocation check - ARCH_HAS_FORCE_DMA_UNENCRYPTED */  bool force_dma_unencrypted(struct device *dev)  {  | 
