| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 3 | | - * it under the terms of the GNU General Public License, version 2, as |
|---|
| 4 | | - * published by the Free Software Foundation. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 7 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 8 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 9 | | - * GNU General Public License for more details. |
|---|
| 10 | | - * |
|---|
| 11 | | - * You should have received a copy of the GNU General Public License |
|---|
| 12 | | - * along with this program; if not, write to the Free Software |
|---|
| 13 | | - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|---|
| 14 | 3 | * |
|---|
| 15 | 4 | * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> |
|---|
| 16 | 5 | * Copyright 2011 David Gibson, IBM Corporation <dwg@au1.ibm.com> |
|---|
| .. | .. |
|---|
| 35 | 24 | #include <asm/hvcall.h> |
|---|
| 36 | 25 | #include <asm/synch.h> |
|---|
| 37 | 26 | #include <asm/ppc-opcode.h> |
|---|
| 38 | | -#include <asm/kvm_host.h> |
|---|
| 39 | 27 | #include <asm/udbg.h> |
|---|
| 40 | 28 | #include <asm/iommu.h> |
|---|
| 41 | 29 | #include <asm/tce.h> |
|---|
| .. | .. |
|---|
| 44 | 32 | #ifdef CONFIG_BUG |
|---|
| 45 | 33 | |
|---|
| 46 | 34 | #define WARN_ON_ONCE_RM(condition) ({ \ |
|---|
| 47 | | - static bool __section(.data.unlikely) __warned; \ |
|---|
| 35 | + static bool __section(".data.unlikely") __warned; \ |
|---|
| 48 | 36 | int __ret_warn_once = !!(condition); \ |
|---|
| 49 | 37 | \ |
|---|
| 50 | 38 | if (unlikely(__ret_warn_once && !__warned)) { \ |
|---|
| .. | .. |
|---|
| 66 | 54 | |
|---|
| 67 | 55 | #endif |
|---|
| 68 | 56 | |
|---|
| 69 | | -#define TCES_PER_PAGE (PAGE_SIZE / sizeof(u64)) |
|---|
| 70 | | - |
|---|
| 71 | 57 | /* |
|---|
| 72 | 58 | * Finds a TCE table descriptor by LIOBN. |
|---|
| 73 | 59 | * |
|---|
| .. | .. |
|---|
| 87 | 73 | } |
|---|
| 88 | 74 | EXPORT_SYMBOL_GPL(kvmppc_find_table); |
|---|
| 89 | 75 | |
|---|
| 76 | +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE |
|---|
| 77 | +static long kvmppc_rm_tce_to_ua(struct kvm *kvm, |
|---|
| 78 | + unsigned long tce, unsigned long *ua) |
|---|
| 79 | +{ |
|---|
| 80 | + unsigned long gfn = tce >> PAGE_SHIFT; |
|---|
| 81 | + struct kvm_memory_slot *memslot; |
|---|
| 82 | + |
|---|
| 83 | + memslot = search_memslots(kvm_memslots_raw(kvm), gfn); |
|---|
| 84 | + if (!memslot) |
|---|
| 85 | + return -EINVAL; |
|---|
| 86 | + |
|---|
| 87 | + *ua = __gfn_to_hva_memslot(memslot, gfn) | |
|---|
| 88 | + (tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE)); |
|---|
| 89 | + |
|---|
| 90 | + return 0; |
|---|
| 91 | +} |
|---|
| 92 | + |
|---|
| 90 | 93 | /* |
|---|
| 91 | 94 | * Validates TCE address. |
|---|
| 92 | 95 | * At the moment flags and page mask are validated. |
|---|
| .. | .. |
|---|
| 94 | 97 | * to the table and user space is supposed to process them), we can skip |
|---|
| 95 | 98 | * checking other things (such as TCE is a guest RAM address or the page |
|---|
| 96 | 99 | * was actually allocated). |
|---|
| 97 | | - * |
|---|
| 98 | | - * WARNING: This will be called in real-mode on HV KVM and virtual |
|---|
| 99 | | - * mode on PR KVM |
|---|
| 100 | 100 | */ |
|---|
| 101 | | -long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, unsigned long tce) |
|---|
| 101 | +static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt, |
|---|
| 102 | + unsigned long tce) |
|---|
| 102 | 103 | { |
|---|
| 103 | 104 | unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE); |
|---|
| 104 | 105 | enum dma_data_direction dir = iommu_tce_direction(tce); |
|---|
| 106 | + struct kvmppc_spapr_tce_iommu_table *stit; |
|---|
| 107 | + unsigned long ua = 0; |
|---|
| 105 | 108 | |
|---|
| 106 | 109 | /* Allow userspace to poison TCE table */ |
|---|
| 107 | 110 | if (dir == DMA_NONE) |
|---|
| .. | .. |
|---|
| 110 | 113 | if (iommu_tce_check_gpa(stt->page_shift, gpa)) |
|---|
| 111 | 114 | return H_PARAMETER; |
|---|
| 112 | 115 | |
|---|
| 116 | + if (kvmppc_rm_tce_to_ua(stt->kvm, tce, &ua)) |
|---|
| 117 | + return H_TOO_HARD; |
|---|
| 118 | + |
|---|
| 119 | + list_for_each_entry_lockless(stit, &stt->iommu_tables, next) { |
|---|
| 120 | + unsigned long hpa = 0; |
|---|
| 121 | + struct mm_iommu_table_group_mem_t *mem; |
|---|
| 122 | + long shift = stit->tbl->it_page_shift; |
|---|
| 123 | + |
|---|
| 124 | + mem = mm_iommu_lookup_rm(stt->kvm->mm, ua, 1ULL << shift); |
|---|
| 125 | + if (!mem) |
|---|
| 126 | + return H_TOO_HARD; |
|---|
| 127 | + |
|---|
| 128 | + if (mm_iommu_ua_to_hpa_rm(mem, ua, shift, &hpa)) |
|---|
| 129 | + return H_TOO_HARD; |
|---|
| 130 | + } |
|---|
| 131 | + |
|---|
| 113 | 132 | return H_SUCCESS; |
|---|
| 114 | 133 | } |
|---|
| 115 | | -EXPORT_SYMBOL_GPL(kvmppc_tce_validate); |
|---|
| 116 | 134 | |
|---|
| 117 | 135 | /* Note on the use of page_address() in real mode, |
|---|
| 118 | 136 | * |
|---|
| .. | .. |
|---|
| 144 | 162 | /* |
|---|
| 145 | 163 | * Handles TCE requests for emulated devices. |
|---|
| 146 | 164 | * Puts guest TCE values to the table and expects user space to convert them. |
|---|
| 147 | | - * Called in both real and virtual modes. |
|---|
| 148 | | - * Cannot fail so kvmppc_tce_validate must be called before it. |
|---|
| 149 | | - * |
|---|
| 150 | | - * WARNING: This will be called in real-mode on HV KVM and virtual |
|---|
| 151 | | - * mode on PR KVM |
|---|
| 165 | + * Cannot fail so kvmppc_rm_tce_validate must be called before it. |
|---|
| 152 | 166 | */ |
|---|
| 153 | | -void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt, |
|---|
| 167 | +static void kvmppc_rm_tce_put(struct kvmppc_spapr_tce_table *stt, |
|---|
| 154 | 168 | unsigned long idx, unsigned long tce) |
|---|
| 155 | 169 | { |
|---|
| 156 | 170 | struct page *page; |
|---|
| .. | .. |
|---|
| 158 | 172 | |
|---|
| 159 | 173 | idx -= stt->offset; |
|---|
| 160 | 174 | page = stt->pages[idx / TCES_PER_PAGE]; |
|---|
| 175 | + /* |
|---|
| 176 | + * kvmppc_rm_ioba_validate() allows pages not be allocated if TCE is |
|---|
| 177 | + * being cleared, otherwise it returns H_TOO_HARD and we skip this. |
|---|
| 178 | + */ |
|---|
| 179 | + if (!page) { |
|---|
| 180 | + WARN_ON_ONCE_RM(tce != 0); |
|---|
| 181 | + return; |
|---|
| 182 | + } |
|---|
| 161 | 183 | tbl = kvmppc_page_address(page); |
|---|
| 162 | 184 | |
|---|
| 163 | 185 | tbl[idx % TCES_PER_PAGE] = tce; |
|---|
| 164 | 186 | } |
|---|
| 165 | | -EXPORT_SYMBOL_GPL(kvmppc_tce_put); |
|---|
| 166 | 187 | |
|---|
| 167 | | -long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, |
|---|
| 168 | | - unsigned long *ua, unsigned long **prmap) |
|---|
| 188 | +/* |
|---|
| 189 | + * TCEs pages are allocated in kvmppc_rm_tce_put() which won't be able to do so |
|---|
| 190 | + * in real mode. |
|---|
| 191 | + * Check if kvmppc_rm_tce_put() can succeed in real mode, i.e. a TCEs page is |
|---|
| 192 | + * allocated or not required (when clearing a tce entry). |
|---|
| 193 | + */ |
|---|
| 194 | +static long kvmppc_rm_ioba_validate(struct kvmppc_spapr_tce_table *stt, |
|---|
| 195 | + unsigned long ioba, unsigned long npages, bool clearing) |
|---|
| 169 | 196 | { |
|---|
| 170 | | - unsigned long gfn = gpa >> PAGE_SHIFT; |
|---|
| 171 | | - struct kvm_memory_slot *memslot; |
|---|
| 197 | + unsigned long i, idx, sttpage, sttpages; |
|---|
| 198 | + unsigned long ret = kvmppc_ioba_validate(stt, ioba, npages); |
|---|
| 172 | 199 | |
|---|
| 173 | | - memslot = search_memslots(kvm_memslots(kvm), gfn); |
|---|
| 174 | | - if (!memslot) |
|---|
| 175 | | - return -EINVAL; |
|---|
| 200 | + if (ret) |
|---|
| 201 | + return ret; |
|---|
| 202 | + /* |
|---|
| 203 | + * clearing==true says kvmppc_rm_tce_put won't be allocating pages |
|---|
| 204 | + * for empty tces. |
|---|
| 205 | + */ |
|---|
| 206 | + if (clearing) |
|---|
| 207 | + return H_SUCCESS; |
|---|
| 176 | 208 | |
|---|
| 177 | | - *ua = __gfn_to_hva_memslot(memslot, gfn) | |
|---|
| 178 | | - (gpa & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE)); |
|---|
| 209 | + idx = (ioba >> stt->page_shift) - stt->offset; |
|---|
| 210 | + sttpage = idx / TCES_PER_PAGE; |
|---|
| 211 | + sttpages = ALIGN(idx % TCES_PER_PAGE + npages, TCES_PER_PAGE) / |
|---|
| 212 | + TCES_PER_PAGE; |
|---|
| 213 | + for (i = sttpage; i < sttpage + sttpages; ++i) |
|---|
| 214 | + if (!stt->pages[i]) |
|---|
| 215 | + return H_TOO_HARD; |
|---|
| 179 | 216 | |
|---|
| 180 | | -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE |
|---|
| 181 | | - if (prmap) |
|---|
| 182 | | - *prmap = &memslot->arch.rmap[gfn - memslot->base_gfn]; |
|---|
| 183 | | -#endif |
|---|
| 184 | | - |
|---|
| 185 | | - return 0; |
|---|
| 217 | + return H_SUCCESS; |
|---|
| 186 | 218 | } |
|---|
| 187 | | -EXPORT_SYMBOL_GPL(kvmppc_gpa_to_ua); |
|---|
| 188 | 219 | |
|---|
| 189 | | -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE |
|---|
| 190 | | -static long iommu_tce_xchg_rm(struct mm_struct *mm, struct iommu_table *tbl, |
|---|
| 220 | +static long iommu_tce_xchg_no_kill_rm(struct mm_struct *mm, |
|---|
| 221 | + struct iommu_table *tbl, |
|---|
| 191 | 222 | unsigned long entry, unsigned long *hpa, |
|---|
| 192 | 223 | enum dma_data_direction *direction) |
|---|
| 193 | 224 | { |
|---|
| 194 | 225 | long ret; |
|---|
| 195 | 226 | |
|---|
| 196 | | - ret = tbl->it_ops->exchange_rm(tbl, entry, hpa, direction); |
|---|
| 227 | + ret = tbl->it_ops->xchg_no_kill(tbl, entry, hpa, direction, true); |
|---|
| 197 | 228 | |
|---|
| 198 | 229 | if (!ret && ((*direction == DMA_FROM_DEVICE) || |
|---|
| 199 | 230 | (*direction == DMA_BIDIRECTIONAL))) { |
|---|
| 200 | | - __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry); |
|---|
| 231 | + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry); |
|---|
| 201 | 232 | /* |
|---|
| 202 | 233 | * kvmppc_rm_tce_iommu_do_map() updates the UA cache after |
|---|
| 203 | 234 | * calling this so we still get here a valid UA. |
|---|
| .. | .. |
|---|
| 209 | 240 | return ret; |
|---|
| 210 | 241 | } |
|---|
| 211 | 242 | |
|---|
| 212 | | -static void kvmppc_rm_clear_tce(struct kvm *kvm, struct iommu_table *tbl, |
|---|
| 213 | | - unsigned long entry) |
|---|
| 243 | +static void iommu_tce_kill_rm(struct iommu_table *tbl, |
|---|
| 244 | + unsigned long entry, unsigned long pages) |
|---|
| 214 | 245 | { |
|---|
| 215 | | - unsigned long hpa = 0; |
|---|
| 216 | | - enum dma_data_direction dir = DMA_NONE; |
|---|
| 246 | + if (tbl->it_ops->tce_kill) |
|---|
| 247 | + tbl->it_ops->tce_kill(tbl, entry, pages, true); |
|---|
| 248 | +} |
|---|
| 217 | 249 | |
|---|
| 218 | | - iommu_tce_xchg_rm(kvm->mm, tbl, entry, &hpa, &dir); |
|---|
| 250 | +static void kvmppc_rm_clear_tce(struct kvm *kvm, struct kvmppc_spapr_tce_table *stt, |
|---|
| 251 | + struct iommu_table *tbl, unsigned long entry) |
|---|
| 252 | +{ |
|---|
| 253 | + unsigned long i; |
|---|
| 254 | + unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift); |
|---|
| 255 | + unsigned long io_entry = entry << (stt->page_shift - tbl->it_page_shift); |
|---|
| 256 | + |
|---|
| 257 | + for (i = 0; i < subpages; ++i) { |
|---|
| 258 | + unsigned long hpa = 0; |
|---|
| 259 | + enum dma_data_direction dir = DMA_NONE; |
|---|
| 260 | + |
|---|
| 261 | + iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, io_entry + i, &hpa, &dir); |
|---|
| 262 | + } |
|---|
| 219 | 263 | } |
|---|
| 220 | 264 | |
|---|
| 221 | 265 | static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm, |
|---|
| .. | .. |
|---|
| 223 | 267 | { |
|---|
| 224 | 268 | struct mm_iommu_table_group_mem_t *mem = NULL; |
|---|
| 225 | 269 | const unsigned long pgsize = 1ULL << tbl->it_page_shift; |
|---|
| 226 | | - __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry); |
|---|
| 270 | + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry); |
|---|
| 227 | 271 | |
|---|
| 228 | 272 | if (!pua) |
|---|
| 229 | 273 | /* it_userspace allocation might be delayed */ |
|---|
| .. | .. |
|---|
| 247 | 291 | unsigned long hpa = 0; |
|---|
| 248 | 292 | long ret; |
|---|
| 249 | 293 | |
|---|
| 250 | | - if (iommu_tce_xchg_rm(kvm->mm, tbl, entry, &hpa, &dir)) |
|---|
| 294 | + if (iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, entry, &hpa, &dir)) |
|---|
| 251 | 295 | /* |
|---|
| 252 | 296 | * real mode xchg can fail if struct page crosses |
|---|
| 253 | 297 | * a page boundary |
|---|
| .. | .. |
|---|
| 259 | 303 | |
|---|
| 260 | 304 | ret = kvmppc_rm_tce_iommu_mapped_dec(kvm, tbl, entry); |
|---|
| 261 | 305 | if (ret) |
|---|
| 262 | | - iommu_tce_xchg_rm(kvm->mm, tbl, entry, &hpa, &dir); |
|---|
| 306 | + iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, entry, &hpa, &dir); |
|---|
| 263 | 307 | |
|---|
| 264 | 308 | return ret; |
|---|
| 265 | 309 | } |
|---|
| .. | .. |
|---|
| 278 | 322 | break; |
|---|
| 279 | 323 | } |
|---|
| 280 | 324 | |
|---|
| 325 | + iommu_tce_kill_rm(tbl, io_entry, subpages); |
|---|
| 326 | + |
|---|
| 281 | 327 | return ret; |
|---|
| 282 | 328 | } |
|---|
| 283 | 329 | |
|---|
| .. | .. |
|---|
| 287 | 333 | { |
|---|
| 288 | 334 | long ret; |
|---|
| 289 | 335 | unsigned long hpa = 0; |
|---|
| 290 | | - __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry); |
|---|
| 336 | + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry); |
|---|
| 291 | 337 | struct mm_iommu_table_group_mem_t *mem; |
|---|
| 292 | 338 | |
|---|
| 293 | 339 | if (!pua) |
|---|
| .. | .. |
|---|
| 305 | 351 | if (WARN_ON_ONCE_RM(mm_iommu_mapped_inc(mem))) |
|---|
| 306 | 352 | return H_TOO_HARD; |
|---|
| 307 | 353 | |
|---|
| 308 | | - ret = iommu_tce_xchg_rm(kvm->mm, tbl, entry, &hpa, &dir); |
|---|
| 354 | + ret = iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, entry, &hpa, &dir); |
|---|
| 309 | 355 | if (ret) { |
|---|
| 310 | 356 | mm_iommu_mapped_dec(mem); |
|---|
| 311 | 357 | /* |
|---|
| .. | .. |
|---|
| 341 | 387 | break; |
|---|
| 342 | 388 | } |
|---|
| 343 | 389 | |
|---|
| 390 | + iommu_tce_kill_rm(tbl, io_entry, subpages); |
|---|
| 391 | + |
|---|
| 344 | 392 | return ret; |
|---|
| 345 | 393 | } |
|---|
| 346 | 394 | |
|---|
| .. | .. |
|---|
| 364 | 412 | if (!stt) |
|---|
| 365 | 413 | return H_TOO_HARD; |
|---|
| 366 | 414 | |
|---|
| 367 | | - ret = kvmppc_ioba_validate(stt, ioba, 1); |
|---|
| 415 | + ret = kvmppc_rm_ioba_validate(stt, ioba, 1, tce == 0); |
|---|
| 368 | 416 | if (ret != H_SUCCESS) |
|---|
| 369 | 417 | return ret; |
|---|
| 370 | 418 | |
|---|
| 371 | | - ret = kvmppc_tce_validate(stt, tce); |
|---|
| 419 | + ret = kvmppc_rm_tce_validate(stt, tce); |
|---|
| 372 | 420 | if (ret != H_SUCCESS) |
|---|
| 373 | 421 | return ret; |
|---|
| 374 | 422 | |
|---|
| 375 | 423 | dir = iommu_tce_direction(tce); |
|---|
| 376 | | - if ((dir != DMA_NONE) && kvmppc_gpa_to_ua(vcpu->kvm, |
|---|
| 377 | | - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), &ua, NULL)) |
|---|
| 424 | + if ((dir != DMA_NONE) && kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua)) |
|---|
| 378 | 425 | return H_PARAMETER; |
|---|
| 379 | 426 | |
|---|
| 380 | 427 | entry = ioba >> stt->page_shift; |
|---|
| .. | .. |
|---|
| 387 | 434 | ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt, |
|---|
| 388 | 435 | stit->tbl, entry, ua, dir); |
|---|
| 389 | 436 | |
|---|
| 390 | | - if (ret == H_SUCCESS) |
|---|
| 391 | | - continue; |
|---|
| 392 | | - |
|---|
| 393 | | - if (ret == H_TOO_HARD) |
|---|
| 437 | + if (ret != H_SUCCESS) { |
|---|
| 438 | + kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry); |
|---|
| 394 | 439 | return ret; |
|---|
| 395 | | - |
|---|
| 396 | | - WARN_ON_ONCE_RM(1); |
|---|
| 397 | | - kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); |
|---|
| 440 | + } |
|---|
| 398 | 441 | } |
|---|
| 399 | 442 | |
|---|
| 400 | | - kvmppc_tce_put(stt, entry, tce); |
|---|
| 443 | + kvmppc_rm_tce_put(stt, entry, tce); |
|---|
| 401 | 444 | |
|---|
| 402 | 445 | return H_SUCCESS; |
|---|
| 403 | 446 | } |
|---|
| 404 | 447 | |
|---|
| 405 | | -static long kvmppc_rm_ua_to_hpa(struct kvm_vcpu *vcpu, |
|---|
| 406 | | - unsigned long ua, unsigned long *phpa) |
|---|
| 448 | +static long kvmppc_rm_ua_to_hpa(struct kvm_vcpu *vcpu, unsigned long mmu_seq, |
|---|
| 449 | + unsigned long ua, unsigned long *phpa) |
|---|
| 407 | 450 | { |
|---|
| 408 | 451 | pte_t *ptep, pte; |
|---|
| 409 | 452 | unsigned shift = 0; |
|---|
| .. | .. |
|---|
| 417 | 460 | * to exit which will agains result in the below page table walk |
|---|
| 418 | 461 | * to finish. |
|---|
| 419 | 462 | */ |
|---|
| 420 | | - ptep = __find_linux_pte(vcpu->arch.pgdir, ua, NULL, &shift); |
|---|
| 421 | | - if (!ptep || !pte_present(*ptep)) |
|---|
| 463 | + /* an rmap lock won't make it safe. because that just ensure hash |
|---|
| 464 | + * page table entries are removed with rmap lock held. After that |
|---|
| 465 | + * mmu notifier returns and we go ahead and removing ptes from Qemu page table. |
|---|
| 466 | + */ |
|---|
| 467 | + ptep = find_kvm_host_pte(vcpu->kvm, mmu_seq, ua, &shift); |
|---|
| 468 | + if (!ptep) |
|---|
| 422 | 469 | return -ENXIO; |
|---|
| 423 | | - pte = *ptep; |
|---|
| 470 | + |
|---|
| 471 | + pte = READ_ONCE(*ptep); |
|---|
| 472 | + if (!pte_present(pte)) |
|---|
| 473 | + return -ENXIO; |
|---|
| 424 | 474 | |
|---|
| 425 | 475 | if (!shift) |
|---|
| 426 | 476 | shift = PAGE_SHIFT; |
|---|
| .. | .. |
|---|
| 442 | 492 | unsigned long liobn, unsigned long ioba, |
|---|
| 443 | 493 | unsigned long tce_list, unsigned long npages) |
|---|
| 444 | 494 | { |
|---|
| 495 | + struct kvm *kvm = vcpu->kvm; |
|---|
| 445 | 496 | struct kvmppc_spapr_tce_table *stt; |
|---|
| 446 | 497 | long i, ret = H_SUCCESS; |
|---|
| 447 | 498 | unsigned long tces, entry, ua = 0; |
|---|
| 448 | | - unsigned long *rmap = NULL; |
|---|
| 499 | + unsigned long mmu_seq; |
|---|
| 449 | 500 | bool prereg = false; |
|---|
| 450 | 501 | struct kvmppc_spapr_tce_iommu_table *stit; |
|---|
| 451 | 502 | |
|---|
| 452 | 503 | /* For radix, we might be in virtual mode, so punt */ |
|---|
| 453 | 504 | if (kvm_is_radix(vcpu->kvm)) |
|---|
| 454 | 505 | return H_TOO_HARD; |
|---|
| 506 | + |
|---|
| 507 | + /* |
|---|
| 508 | + * used to check for invalidations in progress |
|---|
| 509 | + */ |
|---|
| 510 | + mmu_seq = kvm->mmu_notifier_seq; |
|---|
| 511 | + smp_rmb(); |
|---|
| 455 | 512 | |
|---|
| 456 | 513 | stt = kvmppc_find_table(vcpu->kvm, liobn); |
|---|
| 457 | 514 | if (!stt) |
|---|
| .. | .. |
|---|
| 468 | 525 | if (tce_list & (SZ_4K - 1)) |
|---|
| 469 | 526 | return H_PARAMETER; |
|---|
| 470 | 527 | |
|---|
| 471 | | - ret = kvmppc_ioba_validate(stt, ioba, npages); |
|---|
| 528 | + ret = kvmppc_rm_ioba_validate(stt, ioba, npages, false); |
|---|
| 472 | 529 | if (ret != H_SUCCESS) |
|---|
| 473 | 530 | return ret; |
|---|
| 474 | 531 | |
|---|
| .. | .. |
|---|
| 480 | 537 | */ |
|---|
| 481 | 538 | struct mm_iommu_table_group_mem_t *mem; |
|---|
| 482 | 539 | |
|---|
| 483 | | - if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) |
|---|
| 540 | + if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce_list, &ua)) |
|---|
| 484 | 541 | return H_TOO_HARD; |
|---|
| 485 | 542 | |
|---|
| 486 | 543 | mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K); |
|---|
| .. | .. |
|---|
| 496 | 553 | * We do not require memory to be preregistered in this case |
|---|
| 497 | 554 | * so lock rmap and do __find_linux_pte_or_hugepte(). |
|---|
| 498 | 555 | */ |
|---|
| 499 | | - if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, &rmap)) |
|---|
| 556 | + if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce_list, &ua)) |
|---|
| 500 | 557 | return H_TOO_HARD; |
|---|
| 501 | 558 | |
|---|
| 502 | | - rmap = (void *) vmalloc_to_phys(rmap); |
|---|
| 503 | | - if (WARN_ON_ONCE_RM(!rmap)) |
|---|
| 504 | | - return H_TOO_HARD; |
|---|
| 505 | | - |
|---|
| 506 | | - /* |
|---|
| 507 | | - * Synchronize with the MMU notifier callbacks in |
|---|
| 508 | | - * book3s_64_mmu_hv.c (kvm_unmap_hva_range_hv etc.). |
|---|
| 509 | | - * While we have the rmap lock, code running on other CPUs |
|---|
| 510 | | - * cannot finish unmapping the host real page that backs |
|---|
| 511 | | - * this guest real page, so we are OK to access the host |
|---|
| 512 | | - * real page. |
|---|
| 513 | | - */ |
|---|
| 514 | | - lock_rmap(rmap); |
|---|
| 515 | | - if (kvmppc_rm_ua_to_hpa(vcpu, ua, &tces)) { |
|---|
| 559 | + arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock); |
|---|
| 560 | + if (kvmppc_rm_ua_to_hpa(vcpu, mmu_seq, ua, &tces)) { |
|---|
| 516 | 561 | ret = H_TOO_HARD; |
|---|
| 517 | 562 | goto unlock_exit; |
|---|
| 518 | 563 | } |
|---|
| .. | .. |
|---|
| 521 | 566 | for (i = 0; i < npages; ++i) { |
|---|
| 522 | 567 | unsigned long tce = be64_to_cpu(((u64 *)tces)[i]); |
|---|
| 523 | 568 | |
|---|
| 524 | | - ret = kvmppc_tce_validate(stt, tce); |
|---|
| 569 | + ret = kvmppc_rm_tce_validate(stt, tce); |
|---|
| 525 | 570 | if (ret != H_SUCCESS) |
|---|
| 526 | 571 | goto unlock_exit; |
|---|
| 572 | + } |
|---|
| 573 | + |
|---|
| 574 | + for (i = 0; i < npages; ++i) { |
|---|
| 575 | + unsigned long tce = be64_to_cpu(((u64 *)tces)[i]); |
|---|
| 527 | 576 | |
|---|
| 528 | 577 | ua = 0; |
|---|
| 529 | | - if (kvmppc_gpa_to_ua(vcpu->kvm, |
|---|
| 530 | | - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), |
|---|
| 531 | | - &ua, NULL)) { |
|---|
| 578 | + if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua)) { |
|---|
| 532 | 579 | ret = H_PARAMETER; |
|---|
| 533 | 580 | goto unlock_exit; |
|---|
| 534 | 581 | } |
|---|
| .. | .. |
|---|
| 538 | 585 | stit->tbl, entry + i, ua, |
|---|
| 539 | 586 | iommu_tce_direction(tce)); |
|---|
| 540 | 587 | |
|---|
| 541 | | - if (ret == H_SUCCESS) |
|---|
| 542 | | - continue; |
|---|
| 543 | | - |
|---|
| 544 | | - if (ret == H_TOO_HARD) |
|---|
| 588 | + if (ret != H_SUCCESS) { |
|---|
| 589 | + kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, |
|---|
| 590 | + entry + i); |
|---|
| 545 | 591 | goto unlock_exit; |
|---|
| 546 | | - |
|---|
| 547 | | - WARN_ON_ONCE_RM(1); |
|---|
| 548 | | - kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); |
|---|
| 592 | + } |
|---|
| 549 | 593 | } |
|---|
| 550 | 594 | |
|---|
| 551 | | - kvmppc_tce_put(stt, entry + i, tce); |
|---|
| 595 | + kvmppc_rm_tce_put(stt, entry + i, tce); |
|---|
| 552 | 596 | } |
|---|
| 553 | 597 | |
|---|
| 554 | 598 | unlock_exit: |
|---|
| 555 | | - if (rmap) |
|---|
| 556 | | - unlock_rmap(rmap); |
|---|
| 557 | | - |
|---|
| 599 | + if (!prereg) |
|---|
| 600 | + arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock); |
|---|
| 558 | 601 | return ret; |
|---|
| 559 | 602 | } |
|---|
| 560 | 603 | |
|---|
| .. | .. |
|---|
| 574 | 617 | if (!stt) |
|---|
| 575 | 618 | return H_TOO_HARD; |
|---|
| 576 | 619 | |
|---|
| 577 | | - ret = kvmppc_ioba_validate(stt, ioba, npages); |
|---|
| 620 | + ret = kvmppc_rm_ioba_validate(stt, ioba, npages, tce_value == 0); |
|---|
| 578 | 621 | if (ret != H_SUCCESS) |
|---|
| 579 | 622 | return ret; |
|---|
| 580 | 623 | |
|---|
| .. | .. |
|---|
| 596 | 639 | return ret; |
|---|
| 597 | 640 | |
|---|
| 598 | 641 | WARN_ON_ONCE_RM(1); |
|---|
| 599 | | - kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); |
|---|
| 642 | + kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry + i); |
|---|
| 600 | 643 | } |
|---|
| 601 | 644 | } |
|---|
| 602 | 645 | |
|---|
| 603 | 646 | for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift)) |
|---|
| 604 | | - kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value); |
|---|
| 647 | + kvmppc_rm_tce_put(stt, ioba >> stt->page_shift, tce_value); |
|---|
| 605 | 648 | |
|---|
| 606 | | - return H_SUCCESS; |
|---|
| 649 | + return ret; |
|---|
| 607 | 650 | } |
|---|
| 608 | 651 | |
|---|
| 609 | 652 | /* This can be called in either virtual mode or real mode */ |
|---|
| .. | .. |
|---|
| 626 | 669 | |
|---|
| 627 | 670 | idx = (ioba >> stt->page_shift) - stt->offset; |
|---|
| 628 | 671 | page = stt->pages[idx / TCES_PER_PAGE]; |
|---|
| 672 | + if (!page) { |
|---|
| 673 | + vcpu->arch.regs.gpr[4] = 0; |
|---|
| 674 | + return H_SUCCESS; |
|---|
| 675 | + } |
|---|
| 629 | 676 | tbl = (u64 *)page_address(page); |
|---|
| 630 | 677 | |
|---|
| 631 | 678 | vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE]; |
|---|