1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Secure VM platform
4 *
5 * Copyright 2018 IBM Corporation
6 * Author: Anshuman Khandual <khandual@linux.vnet.ibm.com>
7 */
8
9#include <linux/mm.h>
10#include <linux/memblock.h>
11#include <linux/cc_platform.h>
12#include <asm/machdep.h>
13#include <asm/svm.h>
14#include <asm/swiotlb.h>
15#include <asm/ultravisor.h>
16#include <asm/dtl.h>
17
18static int __init init_svm(void)
19{
20	if (!is_secure_guest())
21		return 0;
22
23	/* Don't release the SWIOTLB buffer. */
24	ppc_swiotlb_enable = 1;
25
26	/*
27	 * Since the guest memory is inaccessible to the host, devices always
28	 * need to use the SWIOTLB buffer for DMA even if dma_capable() says
29	 * otherwise.
30	 */
31	ppc_swiotlb_flags |= SWIOTLB_ANY | SWIOTLB_FORCE;
32
33	/* Share the SWIOTLB buffer with the host. */
34	swiotlb_update_mem_attributes();
35
36	return 0;
37}
38machine_early_initcall(pseries, init_svm);
39
40int set_memory_encrypted(unsigned long addr, int numpages)
41{
42	if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT))
43		return 0;
44
45	if (!PAGE_ALIGNED(addr))
46		return -EINVAL;
47
48	uv_unshare_page(PHYS_PFN(__pa(addr)), numpages);
49
50	return 0;
51}
52
53int set_memory_decrypted(unsigned long addr, int numpages)
54{
55	if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT))
56		return 0;
57
58	if (!PAGE_ALIGNED(addr))
59		return -EINVAL;
60
61	uv_share_page(PHYS_PFN(__pa(addr)), numpages);
62
63	return 0;
64}
65
66/* There's one dispatch log per CPU. */
67#define NR_DTL_PAGE (DISPATCH_LOG_BYTES * CONFIG_NR_CPUS / PAGE_SIZE)
68
69static struct page *dtl_page_store[NR_DTL_PAGE];
70static long dtl_nr_pages;
71
72static bool is_dtl_page_shared(struct page *page)
73{
74	long i;
75
76	for (i = 0; i < dtl_nr_pages; i++)
77		if (dtl_page_store[i] == page)
78			return true;
79
80	return false;
81}
82
83void dtl_cache_ctor(void *addr)
84{
85	unsigned long pfn = PHYS_PFN(__pa(addr));
86	struct page *page = pfn_to_page(pfn);
87
88	if (!is_dtl_page_shared(page)) {
89		dtl_page_store[dtl_nr_pages] = page;
90		dtl_nr_pages++;
91		WARN_ON(dtl_nr_pages >= NR_DTL_PAGE);
92		uv_share_page(pfn, 1);
93	}
94}
95