Home | History | Annotate | Line # | Download | only in gvt
      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  */
     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  */
     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  */
     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  */
    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  */
    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  */
    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