diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-04 14:36:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-04 14:36:19 -0500 |
commit | 2d62e0768d3c28536d4cfe4c40ba1e5e8e442a93 (patch) | |
tree | 333f8cbcdb3b650813d758711a9e4ceee7b6fbce | |
parent | be834aafdf5f8a37c191e697ac8ee6d53ab5020c (diff) | |
parent | 16ce771b93ab569490fd27415694132a7ade0d79 (diff) |
Merge tag 'kvm-4.11-2' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull more KVM updates from Radim Krčmář:
"Second batch of KVM changes for the 4.11 merge window:
PPC:
- correct assumption about ASDR on POWER9
- fix MMIO emulation on POWER9
x86:
- add a simple test for ioperm
- cleanup TSS (going through KVM tree as the whole undertaking was
caused by VMX's use of TSS)
- fix nVMX interrupt delivery
- fix some performance counters in the guest
... and two cleanup patches"
* tag 'kvm-4.11-2' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
KVM: nVMX: Fix pending events injection
x86/kvm/vmx: remove unused variable in segment_base()
selftests/x86: Add a basic selftest for ioperm
x86/asm: Tidy up TSS limit code
kvm: convert kvm.users_count from atomic_t to refcount_t
KVM: x86: never specify a sample period for virtualized in_tx_cp counters
KVM: PPC: Book3S HV: Don't use ASDR for real-mode HPT faults on POWER9
KVM: PPC: Book3S HV: Fix software walk of guest process page tables
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/mmu.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_64_mmu_radix.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 | ||||
-rw-r--r-- | arch/x86/include/asm/desc.h | 18 | ||||
-rw-r--r-- | arch/x86/kernel/ioport.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/pmu.c | 13 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 9 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 3 | ||||
-rw-r--r-- | tools/testing/selftests/x86/Makefile | 2 | ||||
-rw-r--r-- | tools/testing/selftests/x86/ioperm.c | 170 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 8 |
12 files changed, 223 insertions, 30 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h index 1145dc8e726d..805d4105e9bb 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu.h +++ b/arch/powerpc/include/asm/book3s/64/mmu.h | |||
@@ -46,7 +46,7 @@ extern struct patb_entry *partition_tb; | |||
46 | 46 | ||
47 | /* Bits in patb0 field */ | 47 | /* Bits in patb0 field */ |
48 | #define PATB_HR (1UL << 63) | 48 | #define PATB_HR (1UL << 63) |
49 | #define RPDB_MASK 0x0ffffffffffff00fUL | 49 | #define RPDB_MASK 0x0fffffffffffff00UL |
50 | #define RPDB_SHIFT (1UL << 8) | 50 | #define RPDB_SHIFT (1UL << 8) |
51 | #define RTS1_SHIFT 61 /* top 2 bits of radix tree size */ | 51 | #define RTS1_SHIFT 61 /* top 2 bits of radix tree size */ |
52 | #define RTS1_MASK (3UL << RTS1_SHIFT) | 52 | #define RTS1_MASK (3UL << RTS1_SHIFT) |
@@ -57,6 +57,7 @@ extern struct patb_entry *partition_tb; | |||
57 | /* Bits in patb1 field */ | 57 | /* Bits in patb1 field */ |
58 | #define PATB_GR (1UL << 63) /* guest uses radix; must match HR */ | 58 | #define PATB_GR (1UL << 63) /* guest uses radix; must match HR */ |
59 | #define PRTS_MASK 0x1f /* process table size field */ | 59 | #define PRTS_MASK 0x1f /* process table size field */ |
60 | #define PRTB_MASK 0x0ffffffffffff000UL | ||
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Limit process table to PAGE_SIZE table. This | 63 | * Limit process table to PAGE_SIZE table. This |
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 4344651f408c..f6b3e67c5762 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c | |||
@@ -32,6 +32,7 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
32 | u32 pid; | 32 | u32 pid; |
33 | int ret, level, ps; | 33 | int ret, level, ps; |
34 | __be64 prte, rpte; | 34 | __be64 prte, rpte; |
35 | unsigned long ptbl; | ||
35 | unsigned long root, pte, index; | 36 | unsigned long root, pte, index; |
36 | unsigned long rts, bits, offset; | 37 | unsigned long rts, bits, offset; |
37 | unsigned long gpa; | 38 | unsigned long gpa; |
@@ -53,8 +54,8 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
53 | return -EINVAL; | 54 | return -EINVAL; |
54 | 55 | ||
55 | /* Read partition table to find root of tree for effective PID */ | 56 | /* Read partition table to find root of tree for effective PID */ |
56 | ret = kvm_read_guest(kvm, kvm->arch.process_table + pid * 16, | 57 | ptbl = (kvm->arch.process_table & PRTB_MASK) + (pid * 16); |
57 | &prte, sizeof(prte)); | 58 | ret = kvm_read_guest(kvm, ptbl, &prte, sizeof(prte)); |
58 | if (ret) | 59 | if (ret) |
59 | return ret; | 60 | return ret; |
60 | 61 | ||
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 47414a6fe2dd..7c6477d1840a 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -1787,12 +1787,12 @@ kvmppc_hdsi: | |||
1787 | /* HPTE not found fault or protection fault? */ | 1787 | /* HPTE not found fault or protection fault? */ |
1788 | andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h | 1788 | andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h |
1789 | beq 1f /* if not, send it to the guest */ | 1789 | beq 1f /* if not, send it to the guest */ |
1790 | andi. r0, r11, MSR_DR /* data relocation enabled? */ | ||
1791 | beq 3f | ||
1790 | BEGIN_FTR_SECTION | 1792 | BEGIN_FTR_SECTION |
1791 | mfspr r5, SPRN_ASDR /* on POWER9, use ASDR to get VSID */ | 1793 | mfspr r5, SPRN_ASDR /* on POWER9, use ASDR to get VSID */ |
1792 | b 4f | 1794 | b 4f |
1793 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) | 1795 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) |
1794 | andi. r0, r11, MSR_DR /* data relocation enabled? */ | ||
1795 | beq 3f | ||
1796 | clrrdi r0, r4, 28 | 1796 | clrrdi r0, r4, 28 |
1797 | PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */ | 1797 | PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */ |
1798 | li r0, BOOK3S_INTERRUPT_DATA_SEGMENT | 1798 | li r0, BOOK3S_INTERRUPT_DATA_SEGMENT |
@@ -1879,12 +1879,12 @@ kvmppc_hisi: | |||
1879 | bne .Lradix_hisi /* for radix, just save ASDR */ | 1879 | bne .Lradix_hisi /* for radix, just save ASDR */ |
1880 | andis. r0, r11, SRR1_ISI_NOPT@h | 1880 | andis. r0, r11, SRR1_ISI_NOPT@h |
1881 | beq 1f | 1881 | beq 1f |
1882 | andi. r0, r11, MSR_IR /* instruction relocation enabled? */ | ||
1883 | beq 3f | ||
1882 | BEGIN_FTR_SECTION | 1884 | BEGIN_FTR_SECTION |
1883 | mfspr r5, SPRN_ASDR /* on POWER9, use ASDR to get VSID */ | 1885 | mfspr r5, SPRN_ASDR /* on POWER9, use ASDR to get VSID */ |
1884 | b 4f | 1886 | b 4f |
1885 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) | 1887 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) |
1886 | andi. r0, r11, MSR_IR /* instruction relocation enabled? */ | ||
1887 | beq 3f | ||
1888 | clrrdi r0, r10, 28 | 1888 | clrrdi r0, r10, 28 |
1889 | PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */ | 1889 | PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */ |
1890 | li r0, BOOK3S_INTERRUPT_INST_SEGMENT | 1890 | li r0, BOOK3S_INTERRUPT_INST_SEGMENT |
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index cb8f9149f6c8..1548ca92ad3f 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h | |||
@@ -205,6 +205,8 @@ static inline void native_load_tr_desc(void) | |||
205 | asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); | 205 | asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); |
206 | } | 206 | } |
207 | 207 | ||
208 | DECLARE_PER_CPU(bool, __tss_limit_invalid); | ||
209 | |||
208 | static inline void force_reload_TR(void) | 210 | static inline void force_reload_TR(void) |
209 | { | 211 | { |
210 | struct desc_struct *d = get_cpu_gdt_table(smp_processor_id()); | 212 | struct desc_struct *d = get_cpu_gdt_table(smp_processor_id()); |
@@ -220,18 +222,20 @@ static inline void force_reload_TR(void) | |||
220 | write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); | 222 | write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); |
221 | 223 | ||
222 | load_TR_desc(); | 224 | load_TR_desc(); |
225 | this_cpu_write(__tss_limit_invalid, false); | ||
223 | } | 226 | } |
224 | 227 | ||
225 | DECLARE_PER_CPU(bool, need_tr_refresh); | 228 | /* |
226 | 229 | * Call this if you need the TSS limit to be correct, which should be the case | |
227 | static inline void refresh_TR(void) | 230 | * if and only if you have TIF_IO_BITMAP set or you're switching to a task |
231 | * with TIF_IO_BITMAP set. | ||
232 | */ | ||
233 | static inline void refresh_tss_limit(void) | ||
228 | { | 234 | { |
229 | DEBUG_LOCKS_WARN_ON(preemptible()); | 235 | DEBUG_LOCKS_WARN_ON(preemptible()); |
230 | 236 | ||
231 | if (unlikely(this_cpu_read(need_tr_refresh))) { | 237 | if (unlikely(this_cpu_read(__tss_limit_invalid))) |
232 | force_reload_TR(); | 238 | force_reload_TR(); |
233 | this_cpu_write(need_tr_refresh, false); | ||
234 | } | ||
235 | } | 239 | } |
236 | 240 | ||
237 | /* | 241 | /* |
@@ -250,7 +254,7 @@ static inline void invalidate_tss_limit(void) | |||
250 | if (unlikely(test_thread_flag(TIF_IO_BITMAP))) | 254 | if (unlikely(test_thread_flag(TIF_IO_BITMAP))) |
251 | force_reload_TR(); | 255 | force_reload_TR(); |
252 | else | 256 | else |
253 | this_cpu_write(need_tr_refresh, true); | 257 | this_cpu_write(__tss_limit_invalid, true); |
254 | } | 258 | } |
255 | 259 | ||
256 | static inline void native_load_gdt(const struct desc_ptr *dtr) | 260 | static inline void native_load_gdt(const struct desc_ptr *dtr) |
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index ca49bab3e467..9c3cf0944bce 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c | |||
@@ -48,8 +48,14 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) | |||
48 | t->io_bitmap_ptr = bitmap; | 48 | t->io_bitmap_ptr = bitmap; |
49 | set_thread_flag(TIF_IO_BITMAP); | 49 | set_thread_flag(TIF_IO_BITMAP); |
50 | 50 | ||
51 | /* | ||
52 | * Now that we have an IO bitmap, we need our TSS limit to be | ||
53 | * correct. It's fine if we are preempted after doing this: | ||
54 | * with TIF_IO_BITMAP set, context switches will keep our TSS | ||
55 | * limit correct. | ||
56 | */ | ||
51 | preempt_disable(); | 57 | preempt_disable(); |
52 | refresh_TR(); | 58 | refresh_tss_limit(); |
53 | preempt_enable(); | 59 | preempt_enable(); |
54 | } | 60 | } |
55 | 61 | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 56b059486c3b..f67591561711 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -69,8 +69,8 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { | |||
69 | }; | 69 | }; |
70 | EXPORT_PER_CPU_SYMBOL(cpu_tss); | 70 | EXPORT_PER_CPU_SYMBOL(cpu_tss); |
71 | 71 | ||
72 | DEFINE_PER_CPU(bool, need_tr_refresh); | 72 | DEFINE_PER_CPU(bool, __tss_limit_invalid); |
73 | EXPORT_PER_CPU_SYMBOL_GPL(need_tr_refresh); | 73 | EXPORT_PER_CPU_SYMBOL_GPL(__tss_limit_invalid); |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * this gets called so that we can store lazy state into memory and copy the | 76 | * this gets called so that we can store lazy state into memory and copy the |
@@ -222,7 +222,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | |||
222 | * Make sure that the TSS limit is correct for the CPU | 222 | * Make sure that the TSS limit is correct for the CPU |
223 | * to notice the IO bitmap. | 223 | * to notice the IO bitmap. |
224 | */ | 224 | */ |
225 | refresh_TR(); | 225 | refresh_tss_limit(); |
226 | } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { | 226 | } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { |
227 | /* | 227 | /* |
228 | * Clear any possible leftover bits: | 228 | * Clear any possible leftover bits: |
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 06ce377dcbc9..026db42a86c3 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c | |||
@@ -113,12 +113,19 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, | |||
113 | .config = config, | 113 | .config = config, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | attr.sample_period = (-pmc->counter) & pmc_bitmask(pmc); | ||
117 | |||
116 | if (in_tx) | 118 | if (in_tx) |
117 | attr.config |= HSW_IN_TX; | 119 | attr.config |= HSW_IN_TX; |
118 | if (in_tx_cp) | 120 | if (in_tx_cp) { |
121 | /* | ||
122 | * HSW_IN_TX_CHECKPOINTED is not supported with nonzero | ||
123 | * period. Just clear the sample period so at least | ||
124 | * allocating the counter doesn't fail. | ||
125 | */ | ||
126 | attr.sample_period = 0; | ||
119 | attr.config |= HSW_IN_TX_CHECKPOINTED; | 127 | attr.config |= HSW_IN_TX_CHECKPOINTED; |
120 | 128 | } | |
121 | attr.sample_period = (-pmc->counter) & pmc_bitmask(pmc); | ||
122 | 129 | ||
123 | event = perf_event_create_kernel_counter(&attr, -1, current, | 130 | event = perf_event_create_kernel_counter(&attr, -1, current, |
124 | intr ? kvm_perf_overflow_intr : | 131 | intr ? kvm_perf_overflow_intr : |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index ef4ba71dbb66..283aa8601833 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2053,7 +2053,6 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) | |||
2053 | static unsigned long segment_base(u16 selector) | 2053 | static unsigned long segment_base(u16 selector) |
2054 | { | 2054 | { |
2055 | struct desc_ptr *gdt = this_cpu_ptr(&host_gdt); | 2055 | struct desc_ptr *gdt = this_cpu_ptr(&host_gdt); |
2056 | struct desc_struct *d; | ||
2057 | struct desc_struct *table; | 2056 | struct desc_struct *table; |
2058 | unsigned long v; | 2057 | unsigned long v; |
2059 | 2058 | ||
@@ -10642,6 +10641,11 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) | |||
10642 | { | 10641 | { |
10643 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 10642 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
10644 | 10643 | ||
10644 | if (vcpu->arch.exception.pending || | ||
10645 | vcpu->arch.nmi_injected || | ||
10646 | vcpu->arch.interrupt.pending) | ||
10647 | return -EBUSY; | ||
10648 | |||
10645 | if (nested_cpu_has_preemption_timer(get_vmcs12(vcpu)) && | 10649 | if (nested_cpu_has_preemption_timer(get_vmcs12(vcpu)) && |
10646 | vmx->nested.preemption_timer_expired) { | 10650 | vmx->nested.preemption_timer_expired) { |
10647 | if (vmx->nested.nested_run_pending) | 10651 | if (vmx->nested.nested_run_pending) |
@@ -10651,8 +10655,7 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) | |||
10651 | } | 10655 | } |
10652 | 10656 | ||
10653 | if (vcpu->arch.nmi_pending && nested_exit_on_nmi(vcpu)) { | 10657 | if (vcpu->arch.nmi_pending && nested_exit_on_nmi(vcpu)) { |
10654 | if (vmx->nested.nested_run_pending || | 10658 | if (vmx->nested.nested_run_pending) |
10655 | vcpu->arch.interrupt.pending) | ||
10656 | return -EBUSY; | 10659 | return -EBUSY; |
10657 | nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, | 10660 | nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, |
10658 | NMI_VECTOR | INTR_TYPE_NMI_INTR | | 10661 | NMI_VECTOR | INTR_TYPE_NMI_INTR | |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 8d69d5150748..2c14ad9809da 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/context_tracking.h> | 26 | #include <linux/context_tracking.h> |
27 | #include <linux/irqbypass.h> | 27 | #include <linux/irqbypass.h> |
28 | #include <linux/swait.h> | 28 | #include <linux/swait.h> |
29 | #include <linux/refcount.h> | ||
29 | #include <asm/signal.h> | 30 | #include <asm/signal.h> |
30 | 31 | ||
31 | #include <linux/kvm.h> | 32 | #include <linux/kvm.h> |
@@ -401,7 +402,7 @@ struct kvm { | |||
401 | #endif | 402 | #endif |
402 | struct kvm_vm_stat stat; | 403 | struct kvm_vm_stat stat; |
403 | struct kvm_arch arch; | 404 | struct kvm_arch arch; |
404 | atomic_t users_count; | 405 | refcount_t users_count; |
405 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 406 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET |
406 | struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; | 407 | struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; |
407 | spinlock_t ring_lock; | 408 | spinlock_t ring_lock; |
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 3a5ebae5303e..38e0a9ca5d71 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -5,7 +5,7 @@ include ../lib.mk | |||
5 | .PHONY: all all_32 all_64 warn_32bit_failure clean | 5 | .PHONY: all all_32 all_64 warn_32bit_failure clean |
6 | 6 | ||
7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ | 7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ |
8 | check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test \ | 8 | check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \ |
9 | protection_keys test_vdso | 9 | protection_keys test_vdso |
10 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ | 10 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ |
11 | test_FCMOV test_FCOMI test_FISTTP \ | 11 | test_FCMOV test_FCOMI test_FISTTP \ |
diff --git a/tools/testing/selftests/x86/ioperm.c b/tools/testing/selftests/x86/ioperm.c new file mode 100644 index 000000000000..b77313ba2ab1 --- /dev/null +++ b/tools/testing/selftests/x86/ioperm.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * ioperm.c - Test case for ioperm(2) | ||
3 | * Copyright (c) 2015 Andrew Lutomirski | ||
4 | */ | ||
5 | |||
6 | #define _GNU_SOURCE | ||
7 | #include <err.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdint.h> | ||
10 | #include <signal.h> | ||
11 | #include <setjmp.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | #include <errno.h> | ||
15 | #include <unistd.h> | ||
16 | #include <sys/types.h> | ||
17 | #include <sys/wait.h> | ||
18 | #include <stdbool.h> | ||
19 | #include <sched.h> | ||
20 | #include <sys/io.h> | ||
21 | |||
22 | static int nerrs = 0; | ||
23 | |||
24 | static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), | ||
25 | int flags) | ||
26 | { | ||
27 | struct sigaction sa; | ||
28 | memset(&sa, 0, sizeof(sa)); | ||
29 | sa.sa_sigaction = handler; | ||
30 | sa.sa_flags = SA_SIGINFO | flags; | ||
31 | sigemptyset(&sa.sa_mask); | ||
32 | if (sigaction(sig, &sa, 0)) | ||
33 | err(1, "sigaction"); | ||
34 | |||
35 | } | ||
36 | |||
37 | static void clearhandler(int sig) | ||
38 | { | ||
39 | struct sigaction sa; | ||
40 | memset(&sa, 0, sizeof(sa)); | ||
41 | sa.sa_handler = SIG_DFL; | ||
42 | sigemptyset(&sa.sa_mask); | ||
43 | if (sigaction(sig, &sa, 0)) | ||
44 | err(1, "sigaction"); | ||
45 | } | ||
46 | |||
47 | static jmp_buf jmpbuf; | ||
48 | |||
49 | static void sigsegv(int sig, siginfo_t *si, void *ctx_void) | ||
50 | { | ||
51 | siglongjmp(jmpbuf, 1); | ||
52 | } | ||
53 | |||
54 | static bool try_outb(unsigned short port) | ||
55 | { | ||
56 | sethandler(SIGSEGV, sigsegv, SA_RESETHAND); | ||
57 | if (sigsetjmp(jmpbuf, 1) != 0) { | ||
58 | return false; | ||
59 | } else { | ||
60 | asm volatile ("outb %%al, %w[port]" | ||
61 | : : [port] "Nd" (port), "a" (0)); | ||
62 | return true; | ||
63 | } | ||
64 | clearhandler(SIGSEGV); | ||
65 | } | ||
66 | |||
67 | static void expect_ok(unsigned short port) | ||
68 | { | ||
69 | if (!try_outb(port)) { | ||
70 | printf("[FAIL]\toutb to 0x%02hx failed\n", port); | ||
71 | exit(1); | ||
72 | } | ||
73 | |||
74 | printf("[OK]\toutb to 0x%02hx worked\n", port); | ||
75 | } | ||
76 | |||
77 | static void expect_gp(unsigned short port) | ||
78 | { | ||
79 | if (try_outb(port)) { | ||
80 | printf("[FAIL]\toutb to 0x%02hx worked\n", port); | ||
81 | exit(1); | ||
82 | } | ||
83 | |||
84 | printf("[OK]\toutb to 0x%02hx failed\n", port); | ||
85 | } | ||
86 | |||
87 | int main(void) | ||
88 | { | ||
89 | cpu_set_t cpuset; | ||
90 | CPU_ZERO(&cpuset); | ||
91 | CPU_SET(0, &cpuset); | ||
92 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) | ||
93 | err(1, "sched_setaffinity to CPU 0"); | ||
94 | |||
95 | expect_gp(0x80); | ||
96 | expect_gp(0xed); | ||
97 | |||
98 | /* | ||
99 | * Probe for ioperm support. Note that clearing ioperm bits | ||
100 | * works even as nonroot. | ||
101 | */ | ||
102 | printf("[RUN]\tenable 0x80\n"); | ||
103 | if (ioperm(0x80, 1, 1) != 0) { | ||
104 | printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n", | ||
105 | errno); | ||
106 | return 0; | ||
107 | } | ||
108 | expect_ok(0x80); | ||
109 | expect_gp(0xed); | ||
110 | |||
111 | printf("[RUN]\tdisable 0x80\n"); | ||
112 | if (ioperm(0x80, 1, 0) != 0) { | ||
113 | printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); | ||
114 | return 1; | ||
115 | } | ||
116 | expect_gp(0x80); | ||
117 | expect_gp(0xed); | ||
118 | |||
119 | /* Make sure that fork() preserves ioperm. */ | ||
120 | if (ioperm(0x80, 1, 1) != 0) { | ||
121 | printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | pid_t child = fork(); | ||
126 | if (child == -1) | ||
127 | err(1, "fork"); | ||
128 | |||
129 | if (child == 0) { | ||
130 | printf("[RUN]\tchild: check that we inherited permissions\n"); | ||
131 | expect_ok(0x80); | ||
132 | expect_gp(0xed); | ||
133 | return 0; | ||
134 | } else { | ||
135 | int status; | ||
136 | if (waitpid(child, &status, 0) != child || | ||
137 | !WIFEXITED(status)) { | ||
138 | printf("[FAIL]\tChild died\n"); | ||
139 | nerrs++; | ||
140 | } else if (WEXITSTATUS(status) != 0) { | ||
141 | printf("[FAIL]\tChild failed\n"); | ||
142 | nerrs++; | ||
143 | } else { | ||
144 | printf("[OK]\tChild succeeded\n"); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /* Test the capability checks. */ | ||
149 | |||
150 | printf("\tDrop privileges\n"); | ||
151 | if (setresuid(1, 1, 1) != 0) { | ||
152 | printf("[WARN]\tDropping privileges failed\n"); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | printf("[RUN]\tdisable 0x80\n"); | ||
157 | if (ioperm(0x80, 1, 0) != 0) { | ||
158 | printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); | ||
159 | return 1; | ||
160 | } | ||
161 | printf("[OK]\tit worked\n"); | ||
162 | |||
163 | printf("[RUN]\tenable 0x80 again\n"); | ||
164 | if (ioperm(0x80, 1, 1) == 0) { | ||
165 | printf("[FAIL]\tit succeeded but should have failed.\n"); | ||
166 | return 1; | ||
167 | } | ||
168 | printf("[OK]\tit failed\n"); | ||
169 | return 0; | ||
170 | } | ||
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 799499417f5b..a17d78759727 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -619,7 +619,7 @@ static struct kvm *kvm_create_vm(unsigned long type) | |||
619 | mutex_init(&kvm->lock); | 619 | mutex_init(&kvm->lock); |
620 | mutex_init(&kvm->irq_lock); | 620 | mutex_init(&kvm->irq_lock); |
621 | mutex_init(&kvm->slots_lock); | 621 | mutex_init(&kvm->slots_lock); |
622 | atomic_set(&kvm->users_count, 1); | 622 | refcount_set(&kvm->users_count, 1); |
623 | INIT_LIST_HEAD(&kvm->devices); | 623 | INIT_LIST_HEAD(&kvm->devices); |
624 | 624 | ||
625 | r = kvm_arch_init_vm(kvm, type); | 625 | r = kvm_arch_init_vm(kvm, type); |
@@ -749,13 +749,13 @@ static void kvm_destroy_vm(struct kvm *kvm) | |||
749 | 749 | ||
750 | void kvm_get_kvm(struct kvm *kvm) | 750 | void kvm_get_kvm(struct kvm *kvm) |
751 | { | 751 | { |
752 | atomic_inc(&kvm->users_count); | 752 | refcount_inc(&kvm->users_count); |
753 | } | 753 | } |
754 | EXPORT_SYMBOL_GPL(kvm_get_kvm); | 754 | EXPORT_SYMBOL_GPL(kvm_get_kvm); |
755 | 755 | ||
756 | void kvm_put_kvm(struct kvm *kvm) | 756 | void kvm_put_kvm(struct kvm *kvm) |
757 | { | 757 | { |
758 | if (atomic_dec_and_test(&kvm->users_count)) | 758 | if (refcount_dec_and_test(&kvm->users_count)) |
759 | kvm_destroy_vm(kvm); | 759 | kvm_destroy_vm(kvm); |
760 | } | 760 | } |
761 | EXPORT_SYMBOL_GPL(kvm_put_kvm); | 761 | EXPORT_SYMBOL_GPL(kvm_put_kvm); |
@@ -3641,7 +3641,7 @@ static int kvm_debugfs_open(struct inode *inode, struct file *file, | |||
3641 | * To avoid the race between open and the removal of the debugfs | 3641 | * To avoid the race between open and the removal of the debugfs |
3642 | * directory we test against the users count. | 3642 | * directory we test against the users count. |
3643 | */ | 3643 | */ |
3644 | if (!atomic_add_unless(&stat_data->kvm->users_count, 1, 0)) | 3644 | if (!refcount_inc_not_zero(&stat_data->kvm->users_count)) |
3645 | return -ENOENT; | 3645 | return -ENOENT; |
3646 | 3646 | ||
3647 | if (simple_attr_open(inode, file, get, set, fmt)) { | 3647 | if (simple_attr_open(inode, file, get, set, fmt)) { |