1 /*	$NetBSD: page_track.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $	*/
2 
3 /*
4  * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 #include <sys/cdefs.h>
26 __KERNEL_RCSID(0, "$NetBSD: page_track.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $");
27 
28 #include "i915_drv.h"
29 #include "gvt.h"
30 
31 /**
32  * intel_vgpu_find_page_track - find page track rcord of guest page
33  * @vgpu: a vGPU
34  * @gfn: the gfn of guest page
35  *
36  * Returns:
37  * A pointer to struct intel_vgpu_page_track if found, else NULL returned.
38  */
intel_vgpu_find_page_track(struct intel_vgpu * vgpu,unsigned long gfn)39 struct intel_vgpu_page_track *intel_vgpu_find_page_track(
40 		struct intel_vgpu *vgpu, unsigned long gfn)
41 {
42 	return radix_tree_lookup(&vgpu->page_track_tree, gfn);
43 }
44 
45 /**
46  * intel_vgpu_register_page_track - register a guest page to be tacked
47  * @vgpu: a vGPU
48  * @gfn: the gfn of guest page
49  * @handler: page track handler
50  * @priv: tracker private
51  *
52  * Returns:
53  * zero on success, negative error code if failed.
54  */
intel_vgpu_register_page_track(struct intel_vgpu * vgpu,unsigned long gfn,gvt_page_track_handler_t handler,void * priv)55 int intel_vgpu_register_page_track(struct intel_vgpu *vgpu, unsigned long gfn,
56 		gvt_page_track_handler_t handler, void *priv)
57 {
58 	struct intel_vgpu_page_track *track;
59 	int ret;
60 
61 	track = intel_vgpu_find_page_track(vgpu, gfn);
62 	if (track)
63 		return -EEXIST;
64 
65 	track = kzalloc(sizeof(*track), GFP_KERNEL);
66 	if (!track)
67 		return -ENOMEM;
68 
69 	track->handler = handler;
70 	track->priv_data = priv;
71 
72 	ret = radix_tree_insert(&vgpu->page_track_tree, gfn, track);
73 	if (ret) {
74 		kfree(track);
75 		return ret;
76 	}
77 
78 	return 0;
79 }
80 
81 /**
82  * intel_vgpu_unregister_page_track - unregister the tracked guest page
83  * @vgpu: a vGPU
84  * @gfn: the gfn of guest page
85  *
86  */
intel_vgpu_unregister_page_track(struct intel_vgpu * vgpu,unsigned long gfn)87 void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,
88 		unsigned long gfn)
89 {
90 	struct intel_vgpu_page_track *track;
91 
92 	track = radix_tree_delete(&vgpu->page_track_tree, gfn);
93 	if (track) {
94 		if (track->tracked)
95 			intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
96 		kfree(track);
97 	}
98 }
99 
100 /**
101  * intel_vgpu_enable_page_track - set write-protection on guest page
102  * @vgpu: a vGPU
103  * @gfn: the gfn of guest page
104  *
105  * Returns:
106  * zero on success, negative error code if failed.
107  */
intel_vgpu_enable_page_track(struct intel_vgpu * vgpu,unsigned long gfn)108 int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
109 {
110 	struct intel_vgpu_page_track *track;
111 	int ret;
112 
113 	track = intel_vgpu_find_page_track(vgpu, gfn);
114 	if (!track)
115 		return -ENXIO;
116 
117 	if (track->tracked)
118 		return 0;
119 
120 	ret = intel_gvt_hypervisor_enable_page_track(vgpu, gfn);
121 	if (ret)
122 		return ret;
123 	track->tracked = true;
124 	return 0;
125 }
126 
127 /**
128  * intel_vgpu_enable_page_track - cancel write-protection on guest page
129  * @vgpu: a vGPU
130  * @gfn: the gfn of guest page
131  *
132  * Returns:
133  * zero on success, negative error code if failed.
134  */
intel_vgpu_disable_page_track(struct intel_vgpu * vgpu,unsigned long gfn)135 int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
136 {
137 	struct intel_vgpu_page_track *track;
138 	int ret;
139 
140 	track = intel_vgpu_find_page_track(vgpu, gfn);
141 	if (!track)
142 		return -ENXIO;
143 
144 	if (!track->tracked)
145 		return 0;
146 
147 	ret = intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
148 	if (ret)
149 		return ret;
150 	track->tracked = false;
151 	return 0;
152 }
153 
154 /**
155  * intel_vgpu_page_track_handler - called when write to write-protected page
156  * @vgpu: a vGPU
157  * @gpa: the gpa of this write
158  * @data: the writed data
159  * @bytes: the length of this write
160  *
161  * Returns:
162  * zero on success, negative error code if failed.
163  */
intel_vgpu_page_track_handler(struct intel_vgpu * vgpu,u64 gpa,void * data,unsigned int bytes)164 int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,
165 		void *data, unsigned int bytes)
166 {
167 	struct intel_vgpu_page_track *page_track;
168 	int ret = 0;
169 
170 	mutex_lock(&vgpu->vgpu_lock);
171 
172 	page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT);
173 	if (!page_track) {
174 		ret = -ENXIO;
175 		goto out;
176 	}
177 
178 	if (unlikely(vgpu->failsafe)) {
179 		/* Remove write protection to prevent furture traps. */
180 		intel_vgpu_disable_page_track(vgpu, gpa >> PAGE_SHIFT);
181 	} else {
182 		ret = page_track->handler(page_track, gpa, data, bytes);
183 		if (ret)
184 			gvt_err("guest page write error, gpa %llx\n", gpa);
185 	}
186 
187 out:
188 	mutex_unlock(&vgpu->vgpu_lock);
189 	return ret;
190 }
191