aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadim Krčmář <rkrcmar@redhat.com>2017-11-16 08:39:46 -0500
committerRadim Krčmář <rkrcmar@redhat.com>2017-11-16 08:39:46 -0500
commita6014f1ab7088dc02b58991cfb6b32a34afdbf12 (patch)
tree9076c27473660cd1ede44be8c8c5835836114e1b
parent61d750773df388632b11a6170098e2865977e1f6 (diff)
parentda9a1446d248f673a8560ce46251ff620214ab7b (diff)
Merge tag 'kvm-s390-next-4.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux
KVM: s390: fixes and improvements for 4.15 - Some initial preparation patches for exitless interrupts and crypto - New capability for AIS migration - Fixes - merge of the sthyi tree from the base s390 team, which moves the sthyi out of KVM into a shared function also for non-KVM
-rw-r--r--Documentation/virtual/kvm/api.txt9
-rw-r--r--Documentation/virtual/kvm/devices/s390_flic.txt5
-rw-r--r--arch/s390/include/asm/kvm_host.h26
-rw-r--r--arch/s390/include/asm/sysinfo.h1
-rw-r--r--arch/s390/include/uapi/asm/sthyi.h6
-rw-r--r--arch/s390/include/uapi/asm/unistd.h3
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/compat_wrapper.c1
-rw-r--r--arch/s390/kernel/entry.h1
-rw-r--r--arch/s390/kernel/sthyi.c (renamed from arch/s390/kvm/sthyi.c)172
-rw-r--r--arch/s390/kernel/syscalls.S1
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/intercept.c56
-rw-r--r--arch/s390/kvm/interrupt.c26
-rw-r--r--arch/s390/kvm/kvm-s390.c3
-rw-r--r--arch/s390/kvm/kvm-s390.h5
-rw-r--r--arch/s390/kvm/vsie.c50
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--include/uapi/linux/kvm.h1
-rw-r--r--virt/kvm/kvm_main.c4
20 files changed, 262 insertions, 113 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index dd2dd96927b8..f670e4b9e7f3 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -4351,3 +4351,12 @@ This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr. Its
4351value is used to denote the target vcpu for a SynIC interrupt. For 4351value is used to denote the target vcpu for a SynIC interrupt. For
4352compatibilty, KVM initializes this msr to KVM's internal vcpu index. When this 4352compatibilty, KVM initializes this msr to KVM's internal vcpu index. When this
4353capability is absent, userspace can still query this msr's value. 4353capability is absent, userspace can still query this msr's value.
4354
43558.13 KVM_CAP_S390_AIS_MIGRATION
4356
4357Architectures: s390
4358Parameters: none
4359
4360This capability indicates if the flic device will be able to get/set the
4361AIS states for migration via the KVM_DEV_FLIC_AISM_ALL attribute and allows
4362to discover this without having to create a flic device.
diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt
index 2f1cbf1301d2..a4e20a090174 100644
--- a/Documentation/virtual/kvm/devices/s390_flic.txt
+++ b/Documentation/virtual/kvm/devices/s390_flic.txt
@@ -151,8 +151,13 @@ struct kvm_s390_ais_all {
151 to an ISC (MSB0 bit 0 to ISC 0 and so on). The combination of simm bit and 151 to an ISC (MSB0 bit 0 to ISC 0 and so on). The combination of simm bit and
152 nimm bit presents AIS mode for a ISC. 152 nimm bit presents AIS mode for a ISC.
153 153
154 KVM_DEV_FLIC_AISM_ALL is indicated by KVM_CAP_S390_AIS_MIGRATION.
155
154Note: The KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR device ioctls executed on 156Note: The KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR device ioctls executed on
155FLIC with an unknown group or attribute gives the error code EINVAL (instead of 157FLIC with an unknown group or attribute gives the error code EINVAL (instead of
156ENXIO, as specified in the API documentation). It is not possible to conclude 158ENXIO, as specified in the API documentation). It is not possible to conclude
157that a FLIC operation is unavailable based on the error code resulting from a 159that a FLIC operation is unavailable based on the error code resulting from a
158usage attempt. 160usage attempt.
161
162Note: The KVM_DEV_FLIC_CLEAR_IO_IRQ ioctl will return EINVAL in case a zero
163schid is specified.
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 51375e766e90..f3a9b5a445b6 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -685,11 +685,28 @@ struct kvm_s390_crypto {
685 __u8 dea_kw; 685 __u8 dea_kw;
686}; 686};
687 687
688#define APCB0_MASK_SIZE 1
689struct kvm_s390_apcb0 {
690 __u64 apm[APCB0_MASK_SIZE]; /* 0x0000 */
691 __u64 aqm[APCB0_MASK_SIZE]; /* 0x0008 */
692 __u64 adm[APCB0_MASK_SIZE]; /* 0x0010 */
693 __u64 reserved18; /* 0x0018 */
694};
695
696#define APCB1_MASK_SIZE 4
697struct kvm_s390_apcb1 {
698 __u64 apm[APCB1_MASK_SIZE]; /* 0x0000 */
699 __u64 aqm[APCB1_MASK_SIZE]; /* 0x0020 */
700 __u64 adm[APCB1_MASK_SIZE]; /* 0x0040 */
701 __u64 reserved60[4]; /* 0x0060 */
702};
703
688struct kvm_s390_crypto_cb { 704struct kvm_s390_crypto_cb {
689 __u8 reserved00[72]; /* 0x0000 */ 705 struct kvm_s390_apcb0 apcb0; /* 0x0000 */
690 __u8 dea_wrapping_key_mask[24]; /* 0x0048 */ 706 __u8 reserved20[0x0048 - 0x0020]; /* 0x0020 */
691 __u8 aes_wrapping_key_mask[32]; /* 0x0060 */ 707 __u8 dea_wrapping_key_mask[24]; /* 0x0048 */
692 __u8 reserved80[128]; /* 0x0080 */ 708 __u8 aes_wrapping_key_mask[32]; /* 0x0060 */
709 struct kvm_s390_apcb1 apcb1; /* 0x0080 */
693}; 710};
694 711
695/* 712/*
@@ -736,7 +753,6 @@ struct kvm_arch{
736 wait_queue_head_t ipte_wq; 753 wait_queue_head_t ipte_wq;
737 int ipte_lock_count; 754 int ipte_lock_count;
738 struct mutex ipte_mutex; 755 struct mutex ipte_mutex;
739 struct ratelimit_state sthyi_limit;
740 spinlock_t start_stop_lock; 756 spinlock_t start_stop_lock;
741 struct sie_page2 *sie_page2; 757 struct sie_page2 *sie_page2;
742 struct kvm_s390_cpu_model model; 758 struct kvm_s390_cpu_model model;
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index 2b498e58b914..e4a28307bc5d 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -198,4 +198,5 @@ struct service_level {
198int register_service_level(struct service_level *); 198int register_service_level(struct service_level *);
199int unregister_service_level(struct service_level *); 199int unregister_service_level(struct service_level *);
200 200
201int sthyi_fill(void *dst, u64 *rc);
201#endif /* __ASM_S390_SYSINFO_H */ 202#endif /* __ASM_S390_SYSINFO_H */
diff --git a/arch/s390/include/uapi/asm/sthyi.h b/arch/s390/include/uapi/asm/sthyi.h
new file mode 100644
index 000000000000..ec113db4eb7e
--- /dev/null
+++ b/arch/s390/include/uapi/asm/sthyi.h
@@ -0,0 +1,6 @@
1#ifndef _UAPI_ASM_STHYI_H
2#define _UAPI_ASM_STHYI_H
3
4#define STHYI_FC_CP_IFL_CAP 0
5
6#endif /* _UAPI_ASM_STHYI_H */
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
index ea42290e7d51..61c64f543769 100644
--- a/arch/s390/include/uapi/asm/unistd.h
+++ b/arch/s390/include/uapi/asm/unistd.h
@@ -315,7 +315,8 @@
315#define __NR_pwritev2 377 315#define __NR_pwritev2 377
316#define __NR_s390_guarded_storage 378 316#define __NR_s390_guarded_storage 378
317#define __NR_statx 379 317#define __NR_statx 379
318#define NR_syscalls 380 318#define __NR_s390_sthyi 380
319#define NR_syscalls 381
319 320
320/* 321/*
321 * There are some system calls that are not present on 64 bit, some 322 * There are some system calls that are not present on 64 bit, some
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index adb3fe2e3d42..1fefb7f9216f 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -55,7 +55,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
55obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o 55obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
56obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o 56obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
57obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o 57obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
58obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o 58obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
59obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o 59obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o
60 60
61extra-y += head.o head64.o vmlinux.lds 61extra-y += head.o head64.o vmlinux.lds
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
index 986642a3543b..eb0b17ed95b6 100644
--- a/arch/s390/kernel/compat_wrapper.c
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -180,3 +180,4 @@ COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
180COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); 180COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
181COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); 181COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
182COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); 182COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
183COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags);
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index dbf5f7e18246..bb5301eeb4f4 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -77,6 +77,7 @@ long sys_s390_runtime_instr(int command, int signum);
77long sys_s390_guarded_storage(int command, struct gs_cb __user *); 77long sys_s390_guarded_storage(int command, struct gs_cb __user *);
78long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); 78long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
79long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); 79long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
80long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags);
80 81
81DECLARE_PER_CPU(u64, mt_cycles[8]); 82DECLARE_PER_CPU(u64, mt_cycles[8]);
82 83
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kernel/sthyi.c
index 395926b8c1ed..12981e197f01 100644
--- a/arch/s390/kvm/sthyi.c
+++ b/arch/s390/kernel/sthyi.c
@@ -8,22 +8,19 @@
8 * Copyright IBM Corp. 2016 8 * Copyright IBM Corp. 2016
9 * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com> 9 * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com>
10 */ 10 */
11#include <linux/kvm_host.h>
12#include <linux/errno.h> 11#include <linux/errno.h>
13#include <linux/pagemap.h> 12#include <linux/pagemap.h>
14#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
15#include <linux/ratelimit.h> 14#include <linux/syscalls.h>
16 15#include <linux/mutex.h>
17#include <asm/kvm_host.h>
18#include <asm/asm-offsets.h> 16#include <asm/asm-offsets.h>
19#include <asm/sclp.h> 17#include <asm/sclp.h>
20#include <asm/diag.h> 18#include <asm/diag.h>
21#include <asm/sysinfo.h> 19#include <asm/sysinfo.h>
22#include <asm/ebcdic.h> 20#include <asm/ebcdic.h>
23 21#include <asm/facility.h>
24#include "kvm-s390.h" 22#include <asm/sthyi.h>
25#include "gaccess.h" 23#include "entry.h"
26#include "trace.h"
27 24
28#define DED_WEIGHT 0xffff 25#define DED_WEIGHT 0xffff
29/* 26/*
@@ -144,6 +141,21 @@ struct lpar_cpu_inf {
144 struct cpu_inf ifl; 141 struct cpu_inf ifl;
145}; 142};
146 143
144/*
145 * STHYI requires extensive locking in the higher hypervisors
146 * and is very computational/memory expensive. Therefore we
147 * cache the retrieved data whose valid period is 1s.
148 */
149#define CACHE_VALID_JIFFIES HZ
150
151struct sthyi_info {
152 void *info;
153 unsigned long end;
154};
155
156static DEFINE_MUTEX(sthyi_mutex);
157static struct sthyi_info sthyi_cache;
158
147static inline u64 cpu_id(u8 ctidx, void *diag224_buf) 159static inline u64 cpu_id(u8 ctidx, void *diag224_buf)
148{ 160{
149 return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN)); 161 return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN));
@@ -382,88 +394,124 @@ out:
382 vfree(diag204_buf); 394 vfree(diag204_buf);
383} 395}
384 396
385static int sthyi(u64 vaddr) 397static int sthyi(u64 vaddr, u64 *rc)
386{ 398{
387 register u64 code asm("0") = 0; 399 register u64 code asm("0") = 0;
388 register u64 addr asm("2") = vaddr; 400 register u64 addr asm("2") = vaddr;
401 register u64 rcode asm("3");
389 int cc; 402 int cc;
390 403
391 asm volatile( 404 asm volatile(
392 ".insn rre,0xB2560000,%[code],%[addr]\n" 405 ".insn rre,0xB2560000,%[code],%[addr]\n"
393 "ipm %[cc]\n" 406 "ipm %[cc]\n"
394 "srl %[cc],28\n" 407 "srl %[cc],28\n"
395 : [cc] "=d" (cc) 408 : [cc] "=d" (cc), "=d" (rcode)
396 : [code] "d" (code), [addr] "a" (addr) 409 : [code] "d" (code), [addr] "a" (addr)
397 : "3", "memory", "cc"); 410 : "memory", "cc");
411 *rc = rcode;
398 return cc; 412 return cc;
399} 413}
400 414
401int handle_sthyi(struct kvm_vcpu *vcpu) 415static int fill_dst(void *dst, u64 *rc)
402{ 416{
403 int reg1, reg2, r = 0; 417 struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst;
404 u64 code, addr, cc = 0;
405 struct sthyi_sctns *sctns = NULL;
406
407 if (!test_kvm_facility(vcpu->kvm, 74))
408 return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
409 418
410 /* 419 /*
411 * STHYI requires extensive locking in the higher hypervisors 420 * If the facility is on, we don't want to emulate the instruction.
412 * and is very computational/memory expensive. Therefore we 421 * We ask the hypervisor to provide the data.
413 * ratelimit the executions per VM.
414 */ 422 */
415 if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) { 423 if (test_facility(74))
416 kvm_s390_retry_instr(vcpu); 424 return sthyi((u64)dst, rc);
425
426 fill_hdr(sctns);
427 fill_stsi(sctns);
428 fill_diag(sctns);
429 *rc = 0;
430 return 0;
431}
432
433static int sthyi_init_cache(void)
434{
435 if (sthyi_cache.info)
417 return 0; 436 return 0;
418 } 437 sthyi_cache.info = (void *)get_zeroed_page(GFP_KERNEL);
438 if (!sthyi_cache.info)
439 return -ENOMEM;
440 sthyi_cache.end = jiffies - 1; /* expired */
441 return 0;
442}
419 443
420 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2); 444static int sthyi_update_cache(u64 *rc)
421 code = vcpu->run->s.regs.gprs[reg1]; 445{
422 addr = vcpu->run->s.regs.gprs[reg2]; 446 int r;
423 447
424 vcpu->stat.instruction_sthyi++; 448 memset(sthyi_cache.info, 0, PAGE_SIZE);
425 VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr); 449 r = fill_dst(sthyi_cache.info, rc);
426 trace_kvm_s390_handle_sthyi(vcpu, code, addr); 450 if (r)
451 return r;
452 sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
453 return r;
454}
427 455
428 if (reg1 == reg2 || reg1 & 1 || reg2 & 1) 456/*
429 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 457 * sthyi_fill - Fill page with data returned by the STHYI instruction
458 *
459 * @dst: Pointer to zeroed page
460 * @rc: Pointer for storing the return code of the instruction
461 *
462 * Fills the destination with system information returned by the STHYI
463 * instruction. The data is generated by emulation or execution of STHYI,
464 * if available. The return value is the condition code that would be
465 * returned, the rc parameter is the return code which is passed in
466 * register R2 + 1.
467 */
468int sthyi_fill(void *dst, u64 *rc)
469{
470 int r;
430 471
431 if (code & 0xffff) { 472 mutex_lock(&sthyi_mutex);
432 cc = 3; 473 r = sthyi_init_cache();
474 if (r)
433 goto out; 475 goto out;
434 }
435 476
436 if (addr & ~PAGE_MASK) 477 if (time_is_before_jiffies(sthyi_cache.end)) {
437 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 478 /* cache expired */
479 r = sthyi_update_cache(rc);
480 if (r)
481 goto out;
482 }
483 *rc = 0;
484 memcpy(dst, sthyi_cache.info, PAGE_SIZE);
485out:
486 mutex_unlock(&sthyi_mutex);
487 return r;
488}
489EXPORT_SYMBOL_GPL(sthyi_fill);
438 490
439 sctns = (void *)get_zeroed_page(GFP_KERNEL); 491SYSCALL_DEFINE4(s390_sthyi, unsigned long, function_code, void __user *, buffer,
440 if (!sctns) 492 u64 __user *, return_code, unsigned long, flags)
493{
494 u64 sthyi_rc;
495 void *info;
496 int r;
497
498 if (flags)
499 return -EINVAL;
500 if (function_code != STHYI_FC_CP_IFL_CAP)
501 return -EOPNOTSUPP;
502 info = (void *)get_zeroed_page(GFP_KERNEL);
503 if (!info)
441 return -ENOMEM; 504 return -ENOMEM;
442 505 r = sthyi_fill(info, &sthyi_rc);
443 /* 506 if (r < 0)
444 * If we are a guest, we don't want to emulate an emulated 507 goto out;
445 * instruction. We ask the hypervisor to provide the data. 508 if (return_code && put_user(sthyi_rc, return_code)) {
446 */ 509 r = -EFAULT;
447 if (test_facility(74)) {
448 cc = sthyi((u64)sctns);
449 goto out; 510 goto out;
450 } 511 }
451 512 if (copy_to_user(buffer, info, PAGE_SIZE))
452 fill_hdr(sctns); 513 r = -EFAULT;
453 fill_stsi(sctns);
454 fill_diag(sctns);
455
456out: 514out:
457 if (!cc) { 515 free_page((unsigned long)info);
458 r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
459 if (r) {
460 free_page((unsigned long)sctns);
461 return kvm_s390_inject_prog_cond(vcpu, r);
462 }
463 }
464
465 free_page((unsigned long)sctns);
466 vcpu->run->s.regs.gprs[reg2 + 1] = cc ? 4 : 0;
467 kvm_s390_set_psw_cc(vcpu, cc);
468 return r; 516 return r;
469} 517}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 54fce7b065de..0fb407ebbf46 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -388,3 +388,4 @@ SYSCALL(sys_preadv2,compat_sys_preadv2)
388SYSCALL(sys_pwritev2,compat_sys_pwritev2) 388SYSCALL(sys_pwritev2,compat_sys_pwritev2)
389SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */ 389SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */
390SYSCALL(sys_statx,compat_sys_statx) 390SYSCALL(sys_statx,compat_sys_statx)
391SYSCALL(sys_s390_sthyi,compat_sys_s390_sthyi)
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 09a9e6dfc09f..6048b1c6e580 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -12,6 +12,6 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqch
12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm 12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
13 13
14kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o 14kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
15kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o 15kvm-objs += diag.o gaccess.o guestdbg.o vsie.o
16 16
17obj-$(CONFIG_KVM) += kvm.o 17obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index a4752bf6b526..8fe034beb623 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -18,6 +18,7 @@
18#include <asm/kvm_host.h> 18#include <asm/kvm_host.h>
19#include <asm/asm-offsets.h> 19#include <asm/asm-offsets.h>
20#include <asm/irq.h> 20#include <asm/irq.h>
21#include <asm/sysinfo.h>
21 22
22#include "kvm-s390.h" 23#include "kvm-s390.h"
23#include "gaccess.h" 24#include "gaccess.h"
@@ -360,6 +361,61 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
360 return -EOPNOTSUPP; 361 return -EOPNOTSUPP;
361} 362}
362 363
364/*
365 * Handle the sthyi instruction that provides the guest with system
366 * information, like current CPU resources available at each level of
367 * the machine.
368 */
369int handle_sthyi(struct kvm_vcpu *vcpu)
370{
371 int reg1, reg2, r = 0;
372 u64 code, addr, cc = 0, rc = 0;
373 struct sthyi_sctns *sctns = NULL;
374
375 if (!test_kvm_facility(vcpu->kvm, 74))
376 return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
377
378 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
379 code = vcpu->run->s.regs.gprs[reg1];
380 addr = vcpu->run->s.regs.gprs[reg2];
381
382 vcpu->stat.instruction_sthyi++;
383 VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
384 trace_kvm_s390_handle_sthyi(vcpu, code, addr);
385
386 if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
387 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
388
389 if (code & 0xffff) {
390 cc = 3;
391 rc = 4;
392 goto out;
393 }
394
395 if (addr & ~PAGE_MASK)
396 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
397
398 sctns = (void *)get_zeroed_page(GFP_KERNEL);
399 if (!sctns)
400 return -ENOMEM;
401
402 cc = sthyi_fill(sctns, &rc);
403
404out:
405 if (!cc) {
406 r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
407 if (r) {
408 free_page((unsigned long)sctns);
409 return kvm_s390_inject_prog_cond(vcpu, r);
410 }
411 }
412
413 free_page((unsigned long)sctns);
414 vcpu->run->s.regs.gprs[reg2 + 1] = rc;
415 kvm_s390_set_psw_cc(vcpu, cc);
416 return r;
417}
418
363static int handle_operexc(struct kvm_vcpu *vcpu) 419static int handle_operexc(struct kvm_vcpu *vcpu)
364{ 420{
365 psw_t oldpsw, newpsw; 421 psw_t oldpsw, newpsw;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index a832ad031cee..c8aacced23fb 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -213,6 +213,16 @@ static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
213 vcpu->arch.local_int.pending_irqs; 213 vcpu->arch.local_int.pending_irqs;
214} 214}
215 215
216static inline int isc_to_irq_type(unsigned long isc)
217{
218 return IRQ_PEND_IO_ISC_0 + isc;
219}
220
221static inline int irq_type_to_isc(unsigned long irq_type)
222{
223 return irq_type - IRQ_PEND_IO_ISC_0;
224}
225
216static unsigned long disable_iscs(struct kvm_vcpu *vcpu, 226static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
217 unsigned long active_mask) 227 unsigned long active_mask)
218{ 228{
@@ -220,7 +230,7 @@ static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
220 230
221 for (i = 0; i <= MAX_ISC; i++) 231 for (i = 0; i <= MAX_ISC; i++)
222 if (!(vcpu->arch.sie_block->gcr[6] & isc_to_isc_bits(i))) 232 if (!(vcpu->arch.sie_block->gcr[6] & isc_to_isc_bits(i)))
223 active_mask &= ~(1UL << (IRQ_PEND_IO_ISC_0 + i)); 233 active_mask &= ~(1UL << (isc_to_irq_type(i)));
224 234
225 return active_mask; 235 return active_mask;
226} 236}
@@ -901,7 +911,7 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
901 fi = &vcpu->kvm->arch.float_int; 911 fi = &vcpu->kvm->arch.float_int;
902 912
903 spin_lock(&fi->lock); 913 spin_lock(&fi->lock);
904 isc_list = &fi->lists[irq_type - IRQ_PEND_IO_ISC_0]; 914 isc_list = &fi->lists[irq_type_to_isc(irq_type)];
905 inti = list_first_entry_or_null(isc_list, 915 inti = list_first_entry_or_null(isc_list,
906 struct kvm_s390_interrupt_info, 916 struct kvm_s390_interrupt_info,
907 list); 917 list);
@@ -1074,6 +1084,12 @@ void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
1074 * in kvm_vcpu_block without having the waitqueue set (polling) 1084 * in kvm_vcpu_block without having the waitqueue set (polling)
1075 */ 1085 */
1076 vcpu->valid_wakeup = true; 1086 vcpu->valid_wakeup = true;
1087 /*
1088 * This is mostly to document, that the read in swait_active could
1089 * be moved before other stores, leading to subtle races.
1090 * All current users do not store or use an atomic like update
1091 */
1092 smp_mb__after_atomic();
1077 if (swait_active(&vcpu->wq)) { 1093 if (swait_active(&vcpu->wq)) {
1078 /* 1094 /*
1079 * The vcpu gave up the cpu voluntarily, mark it as a good 1095 * The vcpu gave up the cpu voluntarily, mark it as a good
@@ -1395,7 +1411,7 @@ static struct kvm_s390_interrupt_info *get_io_int(struct kvm *kvm,
1395 list_del_init(&iter->list); 1411 list_del_init(&iter->list);
1396 fi->counters[FIRQ_CNTR_IO] -= 1; 1412 fi->counters[FIRQ_CNTR_IO] -= 1;
1397 if (list_empty(isc_list)) 1413 if (list_empty(isc_list))
1398 clear_bit(IRQ_PEND_IO_ISC_0 + isc, &fi->pending_irqs); 1414 clear_bit(isc_to_irq_type(isc), &fi->pending_irqs);
1399 spin_unlock(&fi->lock); 1415 spin_unlock(&fi->lock);
1400 return iter; 1416 return iter;
1401 } 1417 }
@@ -1522,7 +1538,7 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
1522 isc = int_word_to_isc(inti->io.io_int_word); 1538 isc = int_word_to_isc(inti->io.io_int_word);
1523 list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc]; 1539 list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc];
1524 list_add_tail(&inti->list, list); 1540 list_add_tail(&inti->list, list);
1525 set_bit(IRQ_PEND_IO_ISC_0 + isc, &fi->pending_irqs); 1541 set_bit(isc_to_irq_type(isc), &fi->pending_irqs);
1526 spin_unlock(&fi->lock); 1542 spin_unlock(&fi->lock);
1527 return 0; 1543 return 0;
1528} 1544}
@@ -2175,6 +2191,8 @@ static int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr)
2175 return -EINVAL; 2191 return -EINVAL;
2176 if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid))) 2192 if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid)))
2177 return -EFAULT; 2193 return -EFAULT;
2194 if (!schid)
2195 return -EINVAL;
2178 kfree(kvm_s390_get_io_int(kvm, isc_mask, schid)); 2196 kfree(kvm_s390_get_io_int(kvm, isc_mask, schid));
2179 /* 2197 /*
2180 * If userspace is conforming to the architecture, we can have at most 2198 * If userspace is conforming to the architecture, we can have at most
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 40d0a1a97889..8f4b655f65d7 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -395,6 +395,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
395 case KVM_CAP_S390_USER_INSTR0: 395 case KVM_CAP_S390_USER_INSTR0:
396 case KVM_CAP_S390_CMMA_MIGRATION: 396 case KVM_CAP_S390_CMMA_MIGRATION:
397 case KVM_CAP_S390_AIS: 397 case KVM_CAP_S390_AIS:
398 case KVM_CAP_S390_AIS_MIGRATION:
398 r = 1; 399 r = 1;
399 break; 400 break;
400 case KVM_CAP_S390_MEM_OP: 401 case KVM_CAP_S390_MEM_OP:
@@ -1884,8 +1885,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
1884 1885
1885 rc = -ENOMEM; 1886 rc = -ENOMEM;
1886 1887
1887 ratelimit_state_init(&kvm->arch.sthyi_limit, 5 * HZ, 500);
1888
1889 kvm->arch.use_esca = 0; /* start with basic SCA */ 1888 kvm->arch.use_esca = 0; /* start with basic SCA */
1890 if (!sclp.has_64bscao) 1889 if (!sclp.has_64bscao)
1891 alloc_flags |= GFP_DMA; 1890 alloc_flags |= GFP_DMA;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 9f8fdd7b2311..10d65dfbc306 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -242,6 +242,8 @@ static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
242 kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu)); 242 kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu));
243} 243}
244 244
245int handle_sthyi(struct kvm_vcpu *vcpu);
246
245/* implemented in priv.c */ 247/* implemented in priv.c */
246int is_valid_psw(psw_t *psw); 248int is_valid_psw(psw_t *psw);
247int kvm_s390_handle_aa(struct kvm_vcpu *vcpu); 249int kvm_s390_handle_aa(struct kvm_vcpu *vcpu);
@@ -268,9 +270,6 @@ void kvm_s390_vsie_destroy(struct kvm *kvm);
268int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); 270int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
269int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); 271int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
270 272
271/* implemented in sthyi.c */
272int handle_sthyi(struct kvm_vcpu *vcpu);
273
274/* implemented in kvm-s390.c */ 273/* implemented in kvm-s390.c */
275void kvm_s390_set_tod_clock_ext(struct kvm *kvm, 274void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
276 const struct kvm_s390_vm_tod_clock *gtod); 275 const struct kvm_s390_vm_tod_clock *gtod);
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index b18b5652e5c5..a311938b63b3 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -443,22 +443,14 @@ static int map_prefix(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
443 * 443 *
444 * Returns: - 0 on success 444 * Returns: - 0 on success
445 * - -EINVAL if the gpa is not valid guest storage 445 * - -EINVAL if the gpa is not valid guest storage
446 * - -ENOMEM if out of memory
447 */ 446 */
448static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa) 447static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
449{ 448{
450 struct page *page; 449 struct page *page;
451 hva_t hva;
452 int rc;
453 450
454 hva = gfn_to_hva(kvm, gpa_to_gfn(gpa)); 451 page = gfn_to_page(kvm, gpa_to_gfn(gpa));
455 if (kvm_is_error_hva(hva)) 452 if (is_error_page(page))
456 return -EINVAL; 453 return -EINVAL;
457 rc = get_user_pages_fast(hva, 1, 1, &page);
458 if (rc < 0)
459 return rc;
460 else if (rc != 1)
461 return -ENOMEM;
462 *hpa = (hpa_t) page_to_virt(page) + (gpa & ~PAGE_MASK); 454 *hpa = (hpa_t) page_to_virt(page) + (gpa & ~PAGE_MASK);
463 return 0; 455 return 0;
464} 456}
@@ -466,11 +458,7 @@ static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
466/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */ 458/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
467static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa) 459static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
468{ 460{
469 struct page *page; 461 kvm_release_pfn_dirty(hpa >> PAGE_SHIFT);
470
471 page = virt_to_page(hpa);
472 set_page_dirty_lock(page);
473 put_page(page);
474 /* mark the page always as dirty for migration */ 462 /* mark the page always as dirty for migration */
475 mark_page_dirty(kvm, gpa_to_gfn(gpa)); 463 mark_page_dirty(kvm, gpa_to_gfn(gpa));
476} 464}
@@ -557,7 +545,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
557 rc = set_validity_icpt(scb_s, 0x003bU); 545 rc = set_validity_icpt(scb_s, 0x003bU);
558 if (!rc) { 546 if (!rc) {
559 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 547 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
560 if (rc == -EINVAL) 548 if (rc)
561 rc = set_validity_icpt(scb_s, 0x0034U); 549 rc = set_validity_icpt(scb_s, 0x0034U);
562 } 550 }
563 if (rc) 551 if (rc)
@@ -574,10 +562,10 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
574 } 562 }
575 /* 256 bytes cannot cross page boundaries */ 563 /* 256 bytes cannot cross page boundaries */
576 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 564 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
577 if (rc == -EINVAL) 565 if (rc) {
578 rc = set_validity_icpt(scb_s, 0x0080U); 566 rc = set_validity_icpt(scb_s, 0x0080U);
579 if (rc)
580 goto unpin; 567 goto unpin;
568 }
581 scb_s->itdba = hpa; 569 scb_s->itdba = hpa;
582 } 570 }
583 571
@@ -592,10 +580,10 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
592 * if this block gets bigger, we have to shadow it. 580 * if this block gets bigger, we have to shadow it.
593 */ 581 */
594 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 582 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
595 if (rc == -EINVAL) 583 if (rc) {
596 rc = set_validity_icpt(scb_s, 0x1310U); 584 rc = set_validity_icpt(scb_s, 0x1310U);
597 if (rc)
598 goto unpin; 585 goto unpin;
586 }
599 scb_s->gvrd = hpa; 587 scb_s->gvrd = hpa;
600 } 588 }
601 589
@@ -607,11 +595,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
607 } 595 }
608 /* 64 bytes cannot cross page boundaries */ 596 /* 64 bytes cannot cross page boundaries */
609 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 597 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
610 if (rc == -EINVAL) 598 if (rc) {
611 rc = set_validity_icpt(scb_s, 0x0043U); 599 rc = set_validity_icpt(scb_s, 0x0043U);
612 /* Validity 0x0044 will be checked by SIE */
613 if (rc)
614 goto unpin; 600 goto unpin;
601 }
602 /* Validity 0x0044 will be checked by SIE */
615 scb_s->riccbd = hpa; 603 scb_s->riccbd = hpa;
616 } 604 }
617 if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { 605 if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) {
@@ -635,10 +623,10 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
635 * cross page boundaries 623 * cross page boundaries
636 */ 624 */
637 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 625 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
638 if (rc == -EINVAL) 626 if (rc) {
639 rc = set_validity_icpt(scb_s, 0x10b0U); 627 rc = set_validity_icpt(scb_s, 0x10b0U);
640 if (rc)
641 goto unpin; 628 goto unpin;
629 }
642 scb_s->sdnxo = hpa | sdnxc; 630 scb_s->sdnxo = hpa | sdnxc;
643 } 631 }
644 return 0; 632 return 0;
@@ -663,7 +651,6 @@ static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
663 * 651 *
664 * Returns: - 0 if the scb was pinned. 652 * Returns: - 0 if the scb was pinned.
665 * - > 0 if control has to be given to guest 2 653 * - > 0 if control has to be given to guest 2
666 * - -ENOMEM if out of memory
667 */ 654 */
668static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, 655static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
669 gpa_t gpa) 656 gpa_t gpa)
@@ -672,14 +659,13 @@ static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
672 int rc; 659 int rc;
673 660
674 rc = pin_guest_page(vcpu->kvm, gpa, &hpa); 661 rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
675 if (rc == -EINVAL) { 662 if (rc) {
676 rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 663 rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
677 if (!rc) 664 WARN_ON_ONCE(rc);
678 rc = 1; 665 return 1;
679 } 666 }
680 if (!rc) 667 vsie_page->scb_o = (struct kvm_s390_sie_block *) hpa;
681 vsie_page->scb_o = (struct kvm_s390_sie_block *) hpa; 668 return 0;
682 return rc;
683} 669}
684 670
685/* 671/*
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 6882538eda32..2e754b7c282c 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -667,6 +667,7 @@ kvm_pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn,
667 bool *writable); 667 bool *writable);
668 668
669void kvm_release_pfn_clean(kvm_pfn_t pfn); 669void kvm_release_pfn_clean(kvm_pfn_t pfn);
670void kvm_release_pfn_dirty(kvm_pfn_t pfn);
670void kvm_set_pfn_dirty(kvm_pfn_t pfn); 671void kvm_set_pfn_dirty(kvm_pfn_t pfn);
671void kvm_set_pfn_accessed(kvm_pfn_t pfn); 672void kvm_set_pfn_accessed(kvm_pfn_t pfn);
672void kvm_get_pfn(kvm_pfn_t pfn); 673void kvm_get_pfn(kvm_pfn_t pfn);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 838887587411..b60595696836 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -930,6 +930,7 @@ struct kvm_ppc_resize_hpt {
930#define KVM_CAP_PPC_SMT_POSSIBLE 147 930#define KVM_CAP_PPC_SMT_POSSIBLE 147
931#define KVM_CAP_HYPERV_SYNIC2 148 931#define KVM_CAP_HYPERV_SYNIC2 148
932#define KVM_CAP_HYPERV_VP_INDEX 149 932#define KVM_CAP_HYPERV_VP_INDEX 149
933#define KVM_CAP_S390_AIS_MIGRATION 150
933 934
934#ifdef KVM_CAP_IRQ_ROUTING 935#ifdef KVM_CAP_IRQ_ROUTING
935 936
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 3d73299e05f2..c114d7948743 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -122,7 +122,6 @@ static void hardware_disable_all(void);
122 122
123static void kvm_io_bus_destroy(struct kvm_io_bus *bus); 123static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
124 124
125static void kvm_release_pfn_dirty(kvm_pfn_t pfn);
126static void mark_page_dirty_in_slot(struct kvm_memory_slot *memslot, gfn_t gfn); 125static void mark_page_dirty_in_slot(struct kvm_memory_slot *memslot, gfn_t gfn);
127 126
128__visible bool kvm_rebooting; 127__visible bool kvm_rebooting;
@@ -1679,11 +1678,12 @@ void kvm_release_page_dirty(struct page *page)
1679} 1678}
1680EXPORT_SYMBOL_GPL(kvm_release_page_dirty); 1679EXPORT_SYMBOL_GPL(kvm_release_page_dirty);
1681 1680
1682static void kvm_release_pfn_dirty(kvm_pfn_t pfn) 1681void kvm_release_pfn_dirty(kvm_pfn_t pfn)
1683{ 1682{
1684 kvm_set_pfn_dirty(pfn); 1683 kvm_set_pfn_dirty(pfn);
1685 kvm_release_pfn_clean(pfn); 1684 kvm_release_pfn_clean(pfn);
1686} 1685}
1686EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty);
1687 1687
1688void kvm_set_pfn_dirty(kvm_pfn_t pfn) 1688void kvm_set_pfn_dirty(kvm_pfn_t pfn)
1689{ 1689{