• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021 - Google LLC
4  * Author: David Brazdil <dbrazdil@google.com>
5  */
6 
7 #include <linux/kvm_host.h>
8 #include <asm/kvm_s2mpu.h>
9 
init_s2mpu_driver(void)10 static int init_s2mpu_driver(void)
11 {
12 	static DEFINE_MUTEX(lock);
13 	static bool init_done;
14 
15 	struct mpt *mpt;
16 	unsigned int gb;
17 	unsigned long addr;
18 	u64 pfn;
19 	int ret = 0;
20 
21 	mutex_lock(&lock);
22 	if (init_done)
23 		goto out;
24 
25 	/* Allocate a page for driver data. Must fit MPT descriptor. */
26 	BUILD_BUG_ON(sizeof(*mpt) > PAGE_SIZE);
27 	addr = __get_free_page(GFP_KERNEL);
28 	if (!addr) {
29 		ret = -ENOMEM;
30 		goto out;
31 	}
32 
33 	mpt = (struct mpt *)addr;
34 
35 	/* Allocate SMPT buffers. */
36 	for_each_gb(gb) {
37 		addr = __get_free_pages(GFP_KERNEL, SMPT_ORDER);
38 		if (!addr) {
39 			ret = -ENOMEM;
40 			goto out_free;
41 		}
42 		mpt->fmpt[gb].smpt = (u32 *)addr;
43 	}
44 
45 	/* Share MPT descriptor with hyp. */
46 	pfn = __pa(mpt) >> PAGE_SHIFT;
47 	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
48 	if (ret)
49 		goto out_free;
50 
51 	/* Hypercall to initialize EL2 driver. */
52 	ret = pkvm_iommu_driver_init(PKVM_IOMMU_DRIVER_S2MPU, mpt, sizeof(*mpt));
53 	if (ret)
54 		goto out_unshare;
55 
56 	init_done = true;
57 
58 out_unshare:
59 	WARN_ON(kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn));
60 out_free:
61 	/* TODO - will driver return the memory? */
62 	if (ret) {
63 		for_each_gb(gb)
64 			free_pages((unsigned long)mpt->fmpt[gb].smpt, SMPT_ORDER);
65 		free_page((unsigned long)mpt);
66 	}
67 out:
68 	mutex_unlock(&lock);
69 	return ret;
70 }
71 
pkvm_iommu_s2mpu_register(struct device * dev,phys_addr_t addr)72 int pkvm_iommu_s2mpu_register(struct device *dev, phys_addr_t addr)
73 {
74 	int ret;
75 
76 	if (!is_protected_kvm_enabled())
77 		return -ENODEV;
78 
79 	ret = init_s2mpu_driver();
80 	if (ret)
81 		return ret;
82 
83 	return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_S2MPU,
84 				   addr, S2MPU_MMIO_SIZE, NULL);
85 }
86 EXPORT_SYMBOL_GPL(pkvm_iommu_s2mpu_register);
87 
init_sysmmu_sync_driver(void)88 static int init_sysmmu_sync_driver(void)
89 {
90 	static DEFINE_MUTEX(lock);
91 	static bool init_done;
92 
93 	int ret = 0;
94 
95 	mutex_lock(&lock);
96 	if (!init_done) {
97 		ret = pkvm_iommu_driver_init(PKVM_IOMMU_DRIVER_SYSMMU_SYNC, NULL, 0);
98 		init_done = !ret;
99 	}
100 	mutex_unlock(&lock);
101 	return ret;
102 }
103 
pkvm_iommu_sysmmu_sync_register(struct device * dev,phys_addr_t addr,struct device * parent)104 int pkvm_iommu_sysmmu_sync_register(struct device *dev, phys_addr_t addr,
105 				    struct device *parent)
106 {
107 	int ret;
108 
109 	if (!is_protected_kvm_enabled())
110 		return -ENODEV;
111 
112 	ret = init_sysmmu_sync_driver();
113 	if (ret)
114 		return ret;
115 
116 	return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_SYSMMU_SYNC,
117 				   addr + SYSMMU_SYNC_S2_OFFSET,
118 				   SYSMMU_SYNC_S2_MMIO_SIZE, parent);
119 }
120 EXPORT_SYMBOL_GPL(pkvm_iommu_sysmmu_sync_register);
121