180 lines · c
1/*2 * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice (including the next12 * paragraph) shall be included in all copies or substantial portions of the13 * Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21 * SOFTWARE.22 */23#include "i915_drv.h"24#include "gvt.h"25 26/**27 * intel_vgpu_find_page_track - find page track rcord of guest page28 * @vgpu: a vGPU29 * @gfn: the gfn of guest page30 *31 * Returns:32 * A pointer to struct intel_vgpu_page_track if found, else NULL returned.33 */34struct intel_vgpu_page_track *intel_vgpu_find_page_track(35 struct intel_vgpu *vgpu, unsigned long gfn)36{37 return radix_tree_lookup(&vgpu->page_track_tree, gfn);38}39 40/**41 * intel_vgpu_register_page_track - register a guest page to be tacked42 * @vgpu: a vGPU43 * @gfn: the gfn of guest page44 * @handler: page track handler45 * @priv: tracker private46 *47 * Returns:48 * zero on success, negative error code if failed.49 */50int intel_vgpu_register_page_track(struct intel_vgpu *vgpu, unsigned long gfn,51 gvt_page_track_handler_t handler, void *priv)52{53 struct intel_vgpu_page_track *track;54 int ret;55 56 track = intel_vgpu_find_page_track(vgpu, gfn);57 if (track)58 return -EEXIST;59 60 track = kzalloc(sizeof(*track), GFP_KERNEL);61 if (!track)62 return -ENOMEM;63 64 track->handler = handler;65 track->priv_data = priv;66 67 ret = radix_tree_insert(&vgpu->page_track_tree, gfn, track);68 if (ret) {69 kfree(track);70 return ret;71 }72 73 return 0;74}75 76/**77 * intel_vgpu_unregister_page_track - unregister the tracked guest page78 * @vgpu: a vGPU79 * @gfn: the gfn of guest page80 *81 */82void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,83 unsigned long gfn)84{85 struct intel_vgpu_page_track *track;86 87 track = radix_tree_delete(&vgpu->page_track_tree, gfn);88 if (track) {89 if (track->tracked)90 intel_gvt_page_track_remove(vgpu, gfn);91 kfree(track);92 }93}94 95/**96 * intel_vgpu_enable_page_track - set write-protection on guest page97 * @vgpu: a vGPU98 * @gfn: the gfn of guest page99 *100 * Returns:101 * zero on success, negative error code if failed.102 */103int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)104{105 struct intel_vgpu_page_track *track;106 int ret;107 108 track = intel_vgpu_find_page_track(vgpu, gfn);109 if (!track)110 return -ENXIO;111 112 if (track->tracked)113 return 0;114 115 ret = intel_gvt_page_track_add(vgpu, gfn);116 if (ret)117 return ret;118 track->tracked = true;119 return 0;120}121 122/**123 * intel_vgpu_disable_page_track - cancel write-protection on guest page124 * @vgpu: a vGPU125 * @gfn: the gfn of guest page126 *127 * Returns:128 * zero on success, negative error code if failed.129 */130int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)131{132 struct intel_vgpu_page_track *track;133 int ret;134 135 track = intel_vgpu_find_page_track(vgpu, gfn);136 if (!track)137 return -ENXIO;138 139 if (!track->tracked)140 return 0;141 142 ret = intel_gvt_page_track_remove(vgpu, gfn);143 if (ret)144 return ret;145 track->tracked = false;146 return 0;147}148 149/**150 * intel_vgpu_page_track_handler - called when write to write-protected page151 * @vgpu: a vGPU152 * @gpa: the gpa of this write153 * @data: the writed data154 * @bytes: the length of this write155 *156 * Returns:157 * zero on success, negative error code if failed.158 */159int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,160 void *data, unsigned int bytes)161{162 struct intel_vgpu_page_track *page_track;163 int ret = 0;164 165 page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT);166 if (!page_track)167 return -ENXIO;168 169 if (unlikely(vgpu->failsafe)) {170 /* Remove write protection to prevent furture traps. */171 intel_gvt_page_track_remove(vgpu, gpa >> PAGE_SHIFT);172 } else {173 ret = page_track->handler(page_track, gpa, data, bytes);174 if (ret)175 gvt_err("guest page write error, gpa %llx\n", gpa);176 }177 178 return ret;179}180