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