162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright IBM Corp. 2007
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Authors: Hollis Blanchard <hollisb@us.ibm.com>
762306a36Sopenharmony_ci *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/errno.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/kvm_host.h>
1362306a36Sopenharmony_ci#include <linux/vmalloc.h>
1462306a36Sopenharmony_ci#include <linux/hrtimer.h>
1562306a36Sopenharmony_ci#include <linux/sched/signal.h>
1662306a36Sopenharmony_ci#include <linux/fs.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/file.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/irqbypass.h>
2162306a36Sopenharmony_ci#include <linux/kvm_irqfd.h>
2262306a36Sopenharmony_ci#include <linux/of.h>
2362306a36Sopenharmony_ci#include <asm/cputable.h>
2462306a36Sopenharmony_ci#include <linux/uaccess.h>
2562306a36Sopenharmony_ci#include <asm/kvm_ppc.h>
2662306a36Sopenharmony_ci#include <asm/cputhreads.h>
2762306a36Sopenharmony_ci#include <asm/irqflags.h>
2862306a36Sopenharmony_ci#include <asm/iommu.h>
2962306a36Sopenharmony_ci#include <asm/switch_to.h>
3062306a36Sopenharmony_ci#include <asm/xive.h>
3162306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES
3262306a36Sopenharmony_ci#include <asm/hvcall.h>
3362306a36Sopenharmony_ci#include <asm/plpar_wrappers.h>
3462306a36Sopenharmony_ci#endif
3562306a36Sopenharmony_ci#include <asm/ultravisor.h>
3662306a36Sopenharmony_ci#include <asm/setup.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "timing.h"
3962306a36Sopenharmony_ci#include "../mm/mmu_decl.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
4262306a36Sopenharmony_ci#include "trace.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct kvmppc_ops *kvmppc_hv_ops;
4562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_hv_ops);
4662306a36Sopenharmony_cistruct kvmppc_ops *kvmppc_pr_ops;
4762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_pr_ops);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return !!(v->arch.pending_exceptions) || kvm_request_pending(v);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cibool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	return kvm_arch_vcpu_runnable(vcpu);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	return false;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	return 1;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Common checks before entering the guest world.  Call with interrupts
7262306a36Sopenharmony_ci * disabled.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * returns:
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * == 1 if we're ready to go into guest state
7762306a36Sopenharmony_ci * <= 0 if we need to go back to the host with return value
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ciint kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	int r;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	WARN_ON(irqs_disabled());
8462306a36Sopenharmony_ci	hard_irq_disable();
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	while (true) {
8762306a36Sopenharmony_ci		if (need_resched()) {
8862306a36Sopenharmony_ci			local_irq_enable();
8962306a36Sopenharmony_ci			cond_resched();
9062306a36Sopenharmony_ci			hard_irq_disable();
9162306a36Sopenharmony_ci			continue;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		if (signal_pending(current)) {
9562306a36Sopenharmony_ci			kvmppc_account_exit(vcpu, SIGNAL_EXITS);
9662306a36Sopenharmony_ci			vcpu->run->exit_reason = KVM_EXIT_INTR;
9762306a36Sopenharmony_ci			r = -EINTR;
9862306a36Sopenharmony_ci			break;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		vcpu->mode = IN_GUEST_MODE;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		/*
10462306a36Sopenharmony_ci		 * Reading vcpu->requests must happen after setting vcpu->mode,
10562306a36Sopenharmony_ci		 * so we don't miss a request because the requester sees
10662306a36Sopenharmony_ci		 * OUTSIDE_GUEST_MODE and assumes we'll be checking requests
10762306a36Sopenharmony_ci		 * before next entering the guest (and thus doesn't IPI).
10862306a36Sopenharmony_ci		 * This also orders the write to mode from any reads
10962306a36Sopenharmony_ci		 * to the page tables done while the VCPU is running.
11062306a36Sopenharmony_ci		 * Please see the comment in kvm_flush_remote_tlbs.
11162306a36Sopenharmony_ci		 */
11262306a36Sopenharmony_ci		smp_mb();
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		if (kvm_request_pending(vcpu)) {
11562306a36Sopenharmony_ci			/* Make sure we process requests preemptable */
11662306a36Sopenharmony_ci			local_irq_enable();
11762306a36Sopenharmony_ci			trace_kvm_check_requests(vcpu);
11862306a36Sopenharmony_ci			r = kvmppc_core_check_requests(vcpu);
11962306a36Sopenharmony_ci			hard_irq_disable();
12062306a36Sopenharmony_ci			if (r > 0)
12162306a36Sopenharmony_ci				continue;
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		if (kvmppc_core_prepare_to_enter(vcpu)) {
12662306a36Sopenharmony_ci			/* interrupts got enabled in between, so we
12762306a36Sopenharmony_ci			   are back at square 1 */
12862306a36Sopenharmony_ci			continue;
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		guest_enter_irqoff();
13262306a36Sopenharmony_ci		return 1;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* return to host */
13662306a36Sopenharmony_ci	local_irq_enable();
13762306a36Sopenharmony_ci	return r;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
14262306a36Sopenharmony_cistatic void kvmppc_swab_shared(struct kvm_vcpu *vcpu)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared;
14562306a36Sopenharmony_ci	int i;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	shared->sprg0 = swab64(shared->sprg0);
14862306a36Sopenharmony_ci	shared->sprg1 = swab64(shared->sprg1);
14962306a36Sopenharmony_ci	shared->sprg2 = swab64(shared->sprg2);
15062306a36Sopenharmony_ci	shared->sprg3 = swab64(shared->sprg3);
15162306a36Sopenharmony_ci	shared->srr0 = swab64(shared->srr0);
15262306a36Sopenharmony_ci	shared->srr1 = swab64(shared->srr1);
15362306a36Sopenharmony_ci	shared->dar = swab64(shared->dar);
15462306a36Sopenharmony_ci	shared->msr = swab64(shared->msr);
15562306a36Sopenharmony_ci	shared->dsisr = swab32(shared->dsisr);
15662306a36Sopenharmony_ci	shared->int_pending = swab32(shared->int_pending);
15762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(shared->sr); i++)
15862306a36Sopenharmony_ci		shared->sr[i] = swab32(shared->sr[i]);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci#endif
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciint kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int nr = kvmppc_get_gpr(vcpu, 11);
16562306a36Sopenharmony_ci	int r;
16662306a36Sopenharmony_ci	unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3);
16762306a36Sopenharmony_ci	unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4);
16862306a36Sopenharmony_ci	unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5);
16962306a36Sopenharmony_ci	unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
17062306a36Sopenharmony_ci	unsigned long r2 = 0;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!(kvmppc_get_msr(vcpu) & MSR_SF)) {
17362306a36Sopenharmony_ci		/* 32 bit mode */
17462306a36Sopenharmony_ci		param1 &= 0xffffffff;
17562306a36Sopenharmony_ci		param2 &= 0xffffffff;
17662306a36Sopenharmony_ci		param3 &= 0xffffffff;
17762306a36Sopenharmony_ci		param4 &= 0xffffffff;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	switch (nr) {
18162306a36Sopenharmony_ci	case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):
18262306a36Sopenharmony_ci	{
18362306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
18462306a36Sopenharmony_ci		/* Book3S can be little endian, find it out here */
18562306a36Sopenharmony_ci		int shared_big_endian = true;
18662306a36Sopenharmony_ci		if (vcpu->arch.intr_msr & MSR_LE)
18762306a36Sopenharmony_ci			shared_big_endian = false;
18862306a36Sopenharmony_ci		if (shared_big_endian != vcpu->arch.shared_big_endian)
18962306a36Sopenharmony_ci			kvmppc_swab_shared(vcpu);
19062306a36Sopenharmony_ci		vcpu->arch.shared_big_endian = shared_big_endian;
19162306a36Sopenharmony_ci#endif
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		if (!(param2 & MAGIC_PAGE_FLAG_NOT_MAPPED_NX)) {
19462306a36Sopenharmony_ci			/*
19562306a36Sopenharmony_ci			 * Older versions of the Linux magic page code had
19662306a36Sopenharmony_ci			 * a bug where they would map their trampoline code
19762306a36Sopenharmony_ci			 * NX. If that's the case, remove !PR NX capability.
19862306a36Sopenharmony_ci			 */
19962306a36Sopenharmony_ci			vcpu->arch.disable_kernel_nx = true;
20062306a36Sopenharmony_ci			kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		vcpu->arch.magic_page_pa = param1 & ~0xfffULL;
20462306a36Sopenharmony_ci		vcpu->arch.magic_page_ea = param2 & ~0xfffULL;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
20762306a36Sopenharmony_ci		/*
20862306a36Sopenharmony_ci		 * Make sure our 4k magic page is in the same window of a 64k
20962306a36Sopenharmony_ci		 * page within the guest and within the host's page.
21062306a36Sopenharmony_ci		 */
21162306a36Sopenharmony_ci		if ((vcpu->arch.magic_page_pa & 0xf000) !=
21262306a36Sopenharmony_ci		    ((ulong)vcpu->arch.shared & 0xf000)) {
21362306a36Sopenharmony_ci			void *old_shared = vcpu->arch.shared;
21462306a36Sopenharmony_ci			ulong shared = (ulong)vcpu->arch.shared;
21562306a36Sopenharmony_ci			void *new_shared;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci			shared &= PAGE_MASK;
21862306a36Sopenharmony_ci			shared |= vcpu->arch.magic_page_pa & 0xf000;
21962306a36Sopenharmony_ci			new_shared = (void*)shared;
22062306a36Sopenharmony_ci			memcpy(new_shared, old_shared, 0x1000);
22162306a36Sopenharmony_ci			vcpu->arch.shared = new_shared;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci#endif
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		r = EV_SUCCESS;
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	case KVM_HCALL_TOKEN(KVM_HC_FEATURES):
23162306a36Sopenharmony_ci		r = EV_SUCCESS;
23262306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2)
23362306a36Sopenharmony_ci		r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
23462306a36Sopenharmony_ci#endif
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		/* Second return value is in r4 */
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci	case EV_HCALL_TOKEN(EV_IDLE):
23962306a36Sopenharmony_ci		r = EV_SUCCESS;
24062306a36Sopenharmony_ci		kvm_vcpu_halt(vcpu);
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	default:
24362306a36Sopenharmony_ci		r = EV_UNIMPLEMENTED;
24462306a36Sopenharmony_ci		break;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	kvmppc_set_gpr(vcpu, 4, r2);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return r;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_kvm_pv);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ciint kvmppc_sanity_check(struct kvm_vcpu *vcpu)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	int r = false;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* We have to know what CPU to virtualize */
25862306a36Sopenharmony_ci	if (!vcpu->arch.pvr)
25962306a36Sopenharmony_ci		goto out;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* PAPR only works with book3s_64 */
26262306a36Sopenharmony_ci	if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled)
26362306a36Sopenharmony_ci		goto out;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* HV KVM can only do PAPR mode for now */
26662306a36Sopenharmony_ci	if (!vcpu->arch.papr_enabled && is_kvmppc_hv_enabled(vcpu->kvm))
26762306a36Sopenharmony_ci		goto out;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV
27062306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_EMB_HV))
27162306a36Sopenharmony_ci		goto out;
27262306a36Sopenharmony_ci#endif
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	r = true;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciout:
27762306a36Sopenharmony_ci	vcpu->arch.sane = r;
27862306a36Sopenharmony_ci	return r ? 0 : -EINVAL;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_sanity_check);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ciint kvmppc_emulate_mmio(struct kvm_vcpu *vcpu)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	enum emulation_result er;
28562306a36Sopenharmony_ci	int r;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	er = kvmppc_emulate_loadstore(vcpu);
28862306a36Sopenharmony_ci	switch (er) {
28962306a36Sopenharmony_ci	case EMULATE_DONE:
29062306a36Sopenharmony_ci		/* Future optimization: only reload non-volatiles if they were
29162306a36Sopenharmony_ci		 * actually modified. */
29262306a36Sopenharmony_ci		r = RESUME_GUEST_NV;
29362306a36Sopenharmony_ci		break;
29462306a36Sopenharmony_ci	case EMULATE_AGAIN:
29562306a36Sopenharmony_ci		r = RESUME_GUEST;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	case EMULATE_DO_MMIO:
29862306a36Sopenharmony_ci		vcpu->run->exit_reason = KVM_EXIT_MMIO;
29962306a36Sopenharmony_ci		/* We must reload nonvolatiles because "update" load/store
30062306a36Sopenharmony_ci		 * instructions modify register state. */
30162306a36Sopenharmony_ci		/* Future optimization: only reload non-volatiles if they were
30262306a36Sopenharmony_ci		 * actually modified. */
30362306a36Sopenharmony_ci		r = RESUME_HOST_NV;
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci	case EMULATE_FAIL:
30662306a36Sopenharmony_ci	{
30762306a36Sopenharmony_ci		ppc_inst_t last_inst;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
31062306a36Sopenharmony_ci		kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n",
31162306a36Sopenharmony_ci				      ppc_inst_val(last_inst));
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * Injecting a Data Storage here is a bit more
31562306a36Sopenharmony_ci		 * accurate since the instruction that caused the
31662306a36Sopenharmony_ci		 * access could still be a valid one.
31762306a36Sopenharmony_ci		 */
31862306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_BOOKE)) {
31962306a36Sopenharmony_ci			ulong dsisr = DSISR_BADACCESS;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci			if (vcpu->mmio_is_write)
32262306a36Sopenharmony_ci				dsisr |= DSISR_ISSTORE;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci			kvmppc_core_queue_data_storage(vcpu,
32562306a36Sopenharmony_ci					kvmppc_get_msr(vcpu) & SRR1_PREFIXED,
32662306a36Sopenharmony_ci					vcpu->arch.vaddr_accessed, dsisr);
32762306a36Sopenharmony_ci		} else {
32862306a36Sopenharmony_ci			/*
32962306a36Sopenharmony_ci			 * BookE does not send a SIGBUS on a bad
33062306a36Sopenharmony_ci			 * fault, so use a Program interrupt instead
33162306a36Sopenharmony_ci			 * to avoid a fault loop.
33262306a36Sopenharmony_ci			 */
33362306a36Sopenharmony_ci			kvmppc_core_queue_program(vcpu, 0);
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		r = RESUME_GUEST;
33762306a36Sopenharmony_ci		break;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci	default:
34062306a36Sopenharmony_ci		WARN_ON(1);
34162306a36Sopenharmony_ci		r = RESUME_GUEST;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return r;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_emulate_mmio);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ciint kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
34962306a36Sopenharmony_ci	      bool data)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK;
35262306a36Sopenharmony_ci	struct kvmppc_pte pte;
35362306a36Sopenharmony_ci	int r = -EINVAL;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	vcpu->stat.st++;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->store_to_eaddr)
35862306a36Sopenharmony_ci		r = vcpu->kvm->arch.kvm_ops->store_to_eaddr(vcpu, eaddr, ptr,
35962306a36Sopenharmony_ci							    size);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if ((!r) || (r == -EAGAIN))
36262306a36Sopenharmony_ci		return r;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	r = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST,
36562306a36Sopenharmony_ci			 XLATE_WRITE, &pte);
36662306a36Sopenharmony_ci	if (r < 0)
36762306a36Sopenharmony_ci		return r;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	*eaddr = pte.raddr;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!pte.may_write)
37262306a36Sopenharmony_ci		return -EPERM;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Magic page override */
37562306a36Sopenharmony_ci	if (kvmppc_supports_magic_page(vcpu) && mp_pa &&
37662306a36Sopenharmony_ci	    ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) &&
37762306a36Sopenharmony_ci	    !(kvmppc_get_msr(vcpu) & MSR_PR)) {
37862306a36Sopenharmony_ci		void *magic = vcpu->arch.shared;
37962306a36Sopenharmony_ci		magic += pte.eaddr & 0xfff;
38062306a36Sopenharmony_ci		memcpy(magic, ptr, size);
38162306a36Sopenharmony_ci		return EMULATE_DONE;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size))
38562306a36Sopenharmony_ci		return EMULATE_DO_MMIO;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return EMULATE_DONE;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_st);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ciint kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
39262306a36Sopenharmony_ci		      bool data)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK;
39562306a36Sopenharmony_ci	struct kvmppc_pte pte;
39662306a36Sopenharmony_ci	int rc = -EINVAL;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	vcpu->stat.ld++;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->load_from_eaddr)
40162306a36Sopenharmony_ci		rc = vcpu->kvm->arch.kvm_ops->load_from_eaddr(vcpu, eaddr, ptr,
40262306a36Sopenharmony_ci							      size);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if ((!rc) || (rc == -EAGAIN))
40562306a36Sopenharmony_ci		return rc;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	rc = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST,
40862306a36Sopenharmony_ci			  XLATE_READ, &pte);
40962306a36Sopenharmony_ci	if (rc)
41062306a36Sopenharmony_ci		return rc;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	*eaddr = pte.raddr;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!pte.may_read)
41562306a36Sopenharmony_ci		return -EPERM;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (!data && !pte.may_execute)
41862306a36Sopenharmony_ci		return -ENOEXEC;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Magic page override */
42162306a36Sopenharmony_ci	if (kvmppc_supports_magic_page(vcpu) && mp_pa &&
42262306a36Sopenharmony_ci	    ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) &&
42362306a36Sopenharmony_ci	    !(kvmppc_get_msr(vcpu) & MSR_PR)) {
42462306a36Sopenharmony_ci		void *magic = vcpu->arch.shared;
42562306a36Sopenharmony_ci		magic += pte.eaddr & 0xfff;
42662306a36Sopenharmony_ci		memcpy(ptr, magic, size);
42762306a36Sopenharmony_ci		return EMULATE_DONE;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	kvm_vcpu_srcu_read_lock(vcpu);
43162306a36Sopenharmony_ci	rc = kvm_read_guest(vcpu->kvm, pte.raddr, ptr, size);
43262306a36Sopenharmony_ci	kvm_vcpu_srcu_read_unlock(vcpu);
43362306a36Sopenharmony_ci	if (rc)
43462306a36Sopenharmony_ci		return EMULATE_DO_MMIO;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return EMULATE_DONE;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_ld);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct kvmppc_ops *kvm_ops = NULL;
44362306a36Sopenharmony_ci	int r;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/*
44662306a36Sopenharmony_ci	 * if we have both HV and PR enabled, default is HV
44762306a36Sopenharmony_ci	 */
44862306a36Sopenharmony_ci	if (type == 0) {
44962306a36Sopenharmony_ci		if (kvmppc_hv_ops)
45062306a36Sopenharmony_ci			kvm_ops = kvmppc_hv_ops;
45162306a36Sopenharmony_ci		else
45262306a36Sopenharmony_ci			kvm_ops = kvmppc_pr_ops;
45362306a36Sopenharmony_ci		if (!kvm_ops)
45462306a36Sopenharmony_ci			goto err_out;
45562306a36Sopenharmony_ci	} else	if (type == KVM_VM_PPC_HV) {
45662306a36Sopenharmony_ci		if (!kvmppc_hv_ops)
45762306a36Sopenharmony_ci			goto err_out;
45862306a36Sopenharmony_ci		kvm_ops = kvmppc_hv_ops;
45962306a36Sopenharmony_ci	} else if (type == KVM_VM_PPC_PR) {
46062306a36Sopenharmony_ci		if (!kvmppc_pr_ops)
46162306a36Sopenharmony_ci			goto err_out;
46262306a36Sopenharmony_ci		kvm_ops = kvmppc_pr_ops;
46362306a36Sopenharmony_ci	} else
46462306a36Sopenharmony_ci		goto err_out;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (!try_module_get(kvm_ops->owner))
46762306a36Sopenharmony_ci		return -ENOENT;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	kvm->arch.kvm_ops = kvm_ops;
47062306a36Sopenharmony_ci	r = kvmppc_core_init_vm(kvm);
47162306a36Sopenharmony_ci	if (r)
47262306a36Sopenharmony_ci		module_put(kvm_ops->owner);
47362306a36Sopenharmony_ci	return r;
47462306a36Sopenharmony_cierr_out:
47562306a36Sopenharmony_ci	return -EINVAL;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * We call kick_all_cpus_sync() to ensure that all
48362306a36Sopenharmony_ci	 * CPUs have executed any pending IPIs before we
48462306a36Sopenharmony_ci	 * continue and free VCPUs structures below.
48562306a36Sopenharmony_ci	 */
48662306a36Sopenharmony_ci	if (is_kvmppc_hv_enabled(kvm))
48762306a36Sopenharmony_ci		kick_all_cpus_sync();
48862306a36Sopenharmony_ci#endif
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	kvm_destroy_vcpus(kvm);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	mutex_lock(&kvm->lock);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	kvmppc_core_destroy_vm(kvm);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* drop the module reference */
49962306a36Sopenharmony_ci	module_put(kvm->arch.kvm_ops->owner);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	int r;
50562306a36Sopenharmony_ci	/* Assume we're using HV mode when the HV module is loaded */
50662306a36Sopenharmony_ci	int hv_enabled = kvmppc_hv_ops ? 1 : 0;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (kvm) {
50962306a36Sopenharmony_ci		/*
51062306a36Sopenharmony_ci		 * Hooray - we know which VM type we're running on. Depend on
51162306a36Sopenharmony_ci		 * that rather than the guess above.
51262306a36Sopenharmony_ci		 */
51362306a36Sopenharmony_ci		hv_enabled = is_kvmppc_hv_enabled(kvm);
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	switch (ext) {
51762306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
51862306a36Sopenharmony_ci	case KVM_CAP_PPC_BOOKE_SREGS:
51962306a36Sopenharmony_ci	case KVM_CAP_PPC_BOOKE_WATCHDOG:
52062306a36Sopenharmony_ci	case KVM_CAP_PPC_EPR:
52162306a36Sopenharmony_ci#else
52262306a36Sopenharmony_ci	case KVM_CAP_PPC_SEGSTATE:
52362306a36Sopenharmony_ci	case KVM_CAP_PPC_HIOR:
52462306a36Sopenharmony_ci	case KVM_CAP_PPC_PAPR:
52562306a36Sopenharmony_ci#endif
52662306a36Sopenharmony_ci	case KVM_CAP_PPC_UNSET_IRQ:
52762306a36Sopenharmony_ci	case KVM_CAP_PPC_IRQ_LEVEL:
52862306a36Sopenharmony_ci	case KVM_CAP_ENABLE_CAP:
52962306a36Sopenharmony_ci	case KVM_CAP_ONE_REG:
53062306a36Sopenharmony_ci	case KVM_CAP_IOEVENTFD:
53162306a36Sopenharmony_ci	case KVM_CAP_DEVICE_CTRL:
53262306a36Sopenharmony_ci	case KVM_CAP_IMMEDIATE_EXIT:
53362306a36Sopenharmony_ci	case KVM_CAP_SET_GUEST_DEBUG:
53462306a36Sopenharmony_ci		r = 1;
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	case KVM_CAP_PPC_GUEST_DEBUG_SSTEP:
53762306a36Sopenharmony_ci	case KVM_CAP_PPC_PAIRED_SINGLES:
53862306a36Sopenharmony_ci	case KVM_CAP_PPC_OSI:
53962306a36Sopenharmony_ci	case KVM_CAP_PPC_GET_PVINFO:
54062306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
54162306a36Sopenharmony_ci	case KVM_CAP_SW_TLB:
54262306a36Sopenharmony_ci#endif
54362306a36Sopenharmony_ci		/* We support this only for PR */
54462306a36Sopenharmony_ci		r = !hv_enabled;
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC
54762306a36Sopenharmony_ci	case KVM_CAP_IRQ_MPIC:
54862306a36Sopenharmony_ci		r = 1;
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci#endif
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
55362306a36Sopenharmony_ci	case KVM_CAP_SPAPR_TCE:
55462306a36Sopenharmony_ci	case KVM_CAP_SPAPR_TCE_64:
55562306a36Sopenharmony_ci		r = 1;
55662306a36Sopenharmony_ci		break;
55762306a36Sopenharmony_ci	case KVM_CAP_SPAPR_TCE_VFIO:
55862306a36Sopenharmony_ci		r = !!cpu_has_feature(CPU_FTR_HVMODE);
55962306a36Sopenharmony_ci		break;
56062306a36Sopenharmony_ci	case KVM_CAP_PPC_RTAS:
56162306a36Sopenharmony_ci	case KVM_CAP_PPC_FIXUP_HCALL:
56262306a36Sopenharmony_ci	case KVM_CAP_PPC_ENABLE_HCALL:
56362306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS
56462306a36Sopenharmony_ci	case KVM_CAP_IRQ_XICS:
56562306a36Sopenharmony_ci#endif
56662306a36Sopenharmony_ci	case KVM_CAP_PPC_GET_CPU_CHAR:
56762306a36Sopenharmony_ci		r = 1;
56862306a36Sopenharmony_ci		break;
56962306a36Sopenharmony_ci#ifdef CONFIG_KVM_XIVE
57062306a36Sopenharmony_ci	case KVM_CAP_PPC_IRQ_XIVE:
57162306a36Sopenharmony_ci		/*
57262306a36Sopenharmony_ci		 * We need XIVE to be enabled on the platform (implies
57362306a36Sopenharmony_ci		 * a POWER9 processor) and the PowerNV platform, as
57462306a36Sopenharmony_ci		 * nested is not yet supported.
57562306a36Sopenharmony_ci		 */
57662306a36Sopenharmony_ci		r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE) &&
57762306a36Sopenharmony_ci			kvmppc_xive_native_supported();
57862306a36Sopenharmony_ci		break;
57962306a36Sopenharmony_ci#endif
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci#ifdef CONFIG_HAVE_KVM_IRQFD
58262306a36Sopenharmony_ci	case KVM_CAP_IRQFD_RESAMPLE:
58362306a36Sopenharmony_ci		r = !xive_enabled();
58462306a36Sopenharmony_ci		break;
58562306a36Sopenharmony_ci#endif
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	case KVM_CAP_PPC_ALLOC_HTAB:
58862306a36Sopenharmony_ci		r = hv_enabled;
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3S_64 */
59162306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
59262306a36Sopenharmony_ci	case KVM_CAP_PPC_SMT:
59362306a36Sopenharmony_ci		r = 0;
59462306a36Sopenharmony_ci		if (kvm) {
59562306a36Sopenharmony_ci			if (kvm->arch.emul_smt_mode > 1)
59662306a36Sopenharmony_ci				r = kvm->arch.emul_smt_mode;
59762306a36Sopenharmony_ci			else
59862306a36Sopenharmony_ci				r = kvm->arch.smt_mode;
59962306a36Sopenharmony_ci		} else if (hv_enabled) {
60062306a36Sopenharmony_ci			if (cpu_has_feature(CPU_FTR_ARCH_300))
60162306a36Sopenharmony_ci				r = 1;
60262306a36Sopenharmony_ci			else
60362306a36Sopenharmony_ci				r = threads_per_subcore;
60462306a36Sopenharmony_ci		}
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	case KVM_CAP_PPC_SMT_POSSIBLE:
60762306a36Sopenharmony_ci		r = 1;
60862306a36Sopenharmony_ci		if (hv_enabled) {
60962306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
61062306a36Sopenharmony_ci				r = ((threads_per_subcore << 1) - 1);
61162306a36Sopenharmony_ci			else
61262306a36Sopenharmony_ci				/* P9 can emulate dbells, so allow any mode */
61362306a36Sopenharmony_ci				r = 8 | 4 | 2 | 1;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci		break;
61662306a36Sopenharmony_ci	case KVM_CAP_PPC_RMA:
61762306a36Sopenharmony_ci		r = 0;
61862306a36Sopenharmony_ci		break;
61962306a36Sopenharmony_ci	case KVM_CAP_PPC_HWRNG:
62062306a36Sopenharmony_ci		r = kvmppc_hwrng_present();
62162306a36Sopenharmony_ci		break;
62262306a36Sopenharmony_ci	case KVM_CAP_PPC_MMU_RADIX:
62362306a36Sopenharmony_ci		r = !!(hv_enabled && radix_enabled());
62462306a36Sopenharmony_ci		break;
62562306a36Sopenharmony_ci	case KVM_CAP_PPC_MMU_HASH_V3:
62662306a36Sopenharmony_ci		r = !!(hv_enabled && kvmppc_hv_ops->hash_v3_possible &&
62762306a36Sopenharmony_ci		       kvmppc_hv_ops->hash_v3_possible());
62862306a36Sopenharmony_ci		break;
62962306a36Sopenharmony_ci	case KVM_CAP_PPC_NESTED_HV:
63062306a36Sopenharmony_ci		r = !!(hv_enabled && kvmppc_hv_ops->enable_nested &&
63162306a36Sopenharmony_ci		       !kvmppc_hv_ops->enable_nested(NULL));
63262306a36Sopenharmony_ci		break;
63362306a36Sopenharmony_ci#endif
63462306a36Sopenharmony_ci	case KVM_CAP_SYNC_MMU:
63562306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
63662306a36Sopenharmony_ci		r = hv_enabled;
63762306a36Sopenharmony_ci#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
63862306a36Sopenharmony_ci		r = 1;
63962306a36Sopenharmony_ci#else
64062306a36Sopenharmony_ci		r = 0;
64162306a36Sopenharmony_ci#endif
64262306a36Sopenharmony_ci		break;
64362306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
64462306a36Sopenharmony_ci	case KVM_CAP_PPC_HTAB_FD:
64562306a36Sopenharmony_ci		r = hv_enabled;
64662306a36Sopenharmony_ci		break;
64762306a36Sopenharmony_ci#endif
64862306a36Sopenharmony_ci	case KVM_CAP_NR_VCPUS:
64962306a36Sopenharmony_ci		/*
65062306a36Sopenharmony_ci		 * Recommending a number of CPUs is somewhat arbitrary; we
65162306a36Sopenharmony_ci		 * return the number of present CPUs for -HV (since a host
65262306a36Sopenharmony_ci		 * will have secondary threads "offline"), and for other KVM
65362306a36Sopenharmony_ci		 * implementations just count online CPUs.
65462306a36Sopenharmony_ci		 */
65562306a36Sopenharmony_ci		if (hv_enabled)
65662306a36Sopenharmony_ci			r = min_t(unsigned int, num_present_cpus(), KVM_MAX_VCPUS);
65762306a36Sopenharmony_ci		else
65862306a36Sopenharmony_ci			r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS);
65962306a36Sopenharmony_ci		break;
66062306a36Sopenharmony_ci	case KVM_CAP_MAX_VCPUS:
66162306a36Sopenharmony_ci		r = KVM_MAX_VCPUS;
66262306a36Sopenharmony_ci		break;
66362306a36Sopenharmony_ci	case KVM_CAP_MAX_VCPU_ID:
66462306a36Sopenharmony_ci		r = KVM_MAX_VCPU_IDS;
66562306a36Sopenharmony_ci		break;
66662306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
66762306a36Sopenharmony_ci	case KVM_CAP_PPC_GET_SMMU_INFO:
66862306a36Sopenharmony_ci		r = 1;
66962306a36Sopenharmony_ci		break;
67062306a36Sopenharmony_ci	case KVM_CAP_SPAPR_MULTITCE:
67162306a36Sopenharmony_ci		r = 1;
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	case KVM_CAP_SPAPR_RESIZE_HPT:
67462306a36Sopenharmony_ci		r = !!hv_enabled;
67562306a36Sopenharmony_ci		break;
67662306a36Sopenharmony_ci#endif
67762306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
67862306a36Sopenharmony_ci	case KVM_CAP_PPC_FWNMI:
67962306a36Sopenharmony_ci		r = hv_enabled;
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci#endif
68262306a36Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
68362306a36Sopenharmony_ci	case KVM_CAP_PPC_HTM:
68462306a36Sopenharmony_ci		r = !!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) ||
68562306a36Sopenharmony_ci		     (hv_enabled && cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST));
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci#endif
68862306a36Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
68962306a36Sopenharmony_ci	case KVM_CAP_PPC_SECURE_GUEST:
69062306a36Sopenharmony_ci		r = hv_enabled && kvmppc_hv_ops->enable_svm &&
69162306a36Sopenharmony_ci			!kvmppc_hv_ops->enable_svm(NULL);
69262306a36Sopenharmony_ci		break;
69362306a36Sopenharmony_ci	case KVM_CAP_PPC_DAWR1:
69462306a36Sopenharmony_ci		r = !!(hv_enabled && kvmppc_hv_ops->enable_dawr1 &&
69562306a36Sopenharmony_ci		       !kvmppc_hv_ops->enable_dawr1(NULL));
69662306a36Sopenharmony_ci		break;
69762306a36Sopenharmony_ci	case KVM_CAP_PPC_RPT_INVALIDATE:
69862306a36Sopenharmony_ci		r = 1;
69962306a36Sopenharmony_ci		break;
70062306a36Sopenharmony_ci#endif
70162306a36Sopenharmony_ci	case KVM_CAP_PPC_AIL_MODE_3:
70262306a36Sopenharmony_ci		r = 0;
70362306a36Sopenharmony_ci		/*
70462306a36Sopenharmony_ci		 * KVM PR, POWER7, and some POWER9s don't support AIL=3 mode.
70562306a36Sopenharmony_ci		 * The POWER9s can support it if the guest runs in hash mode,
70662306a36Sopenharmony_ci		 * but QEMU doesn't necessarily query the capability in time.
70762306a36Sopenharmony_ci		 */
70862306a36Sopenharmony_ci		if (hv_enabled) {
70962306a36Sopenharmony_ci			if (kvmhv_on_pseries()) {
71062306a36Sopenharmony_ci				if (pseries_reloc_on_exception())
71162306a36Sopenharmony_ci					r = 1;
71262306a36Sopenharmony_ci			} else if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
71362306a36Sopenharmony_ci				  !cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
71462306a36Sopenharmony_ci				r = 1;
71562306a36Sopenharmony_ci			}
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci		break;
71862306a36Sopenharmony_ci	default:
71962306a36Sopenharmony_ci		r = 0;
72062306a36Sopenharmony_ci		break;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	return r;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cilong kvm_arch_dev_ioctl(struct file *filp,
72762306a36Sopenharmony_ci                        unsigned int ioctl, unsigned long arg)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	return -EINVAL;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_civoid kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	kvmppc_core_free_memslot(kvm, slot);
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ciint kvm_arch_prepare_memory_region(struct kvm *kvm,
73862306a36Sopenharmony_ci				   const struct kvm_memory_slot *old,
73962306a36Sopenharmony_ci				   struct kvm_memory_slot *new,
74062306a36Sopenharmony_ci				   enum kvm_mr_change change)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	return kvmppc_core_prepare_memory_region(kvm, old, new, change);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_civoid kvm_arch_commit_memory_region(struct kvm *kvm,
74662306a36Sopenharmony_ci				   struct kvm_memory_slot *old,
74762306a36Sopenharmony_ci				   const struct kvm_memory_slot *new,
74862306a36Sopenharmony_ci				   enum kvm_mr_change change)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	kvmppc_core_commit_memory_region(kvm, old, new, change);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_civoid kvm_arch_flush_shadow_memslot(struct kvm *kvm,
75462306a36Sopenharmony_ci				   struct kvm_memory_slot *slot)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	kvmppc_core_flush_memslot(kvm, slot);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	return 0;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	vcpu = container_of(timer, struct kvm_vcpu, arch.dec_timer);
76962306a36Sopenharmony_ci	kvmppc_decrementer_func(vcpu);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return HRTIMER_NORESTART;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	int err;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
77962306a36Sopenharmony_ci	vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci#ifdef CONFIG_KVM_EXIT_TIMING
78262306a36Sopenharmony_ci	mutex_init(&vcpu->arch.exit_timing_lock);
78362306a36Sopenharmony_ci#endif
78462306a36Sopenharmony_ci	err = kvmppc_subarch_vcpu_init(vcpu);
78562306a36Sopenharmony_ci	if (err)
78662306a36Sopenharmony_ci		return err;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	err = kvmppc_core_vcpu_create(vcpu);
78962306a36Sopenharmony_ci	if (err)
79062306a36Sopenharmony_ci		goto out_vcpu_uninit;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	rcuwait_init(&vcpu->arch.wait);
79362306a36Sopenharmony_ci	vcpu->arch.waitp = &vcpu->arch.wait;
79462306a36Sopenharmony_ci	return 0;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ciout_vcpu_uninit:
79762306a36Sopenharmony_ci	kvmppc_subarch_vcpu_uninit(vcpu);
79862306a36Sopenharmony_ci	return err;
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	/* Make sure we're not using the vcpu anymore */
80862306a36Sopenharmony_ci	hrtimer_cancel(&vcpu->arch.dec_timer);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	switch (vcpu->arch.irq_type) {
81162306a36Sopenharmony_ci	case KVMPPC_IRQ_MPIC:
81262306a36Sopenharmony_ci		kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu);
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	case KVMPPC_IRQ_XICS:
81562306a36Sopenharmony_ci		if (xics_on_xive())
81662306a36Sopenharmony_ci			kvmppc_xive_cleanup_vcpu(vcpu);
81762306a36Sopenharmony_ci		else
81862306a36Sopenharmony_ci			kvmppc_xics_free_icp(vcpu);
81962306a36Sopenharmony_ci		break;
82062306a36Sopenharmony_ci	case KVMPPC_IRQ_XIVE:
82162306a36Sopenharmony_ci		kvmppc_xive_native_cleanup_vcpu(vcpu);
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	kvmppc_core_vcpu_free(vcpu);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	kvmppc_subarch_vcpu_uninit(vcpu);
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	return kvmppc_core_pending_dec(vcpu);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
83862306a36Sopenharmony_ci	/*
83962306a36Sopenharmony_ci	 * vrsave (formerly usprg0) isn't used by Linux, but may
84062306a36Sopenharmony_ci	 * be used by the guest.
84162306a36Sopenharmony_ci	 *
84262306a36Sopenharmony_ci	 * On non-booke this is associated with Altivec and
84362306a36Sopenharmony_ci	 * is handled by code in book3s.c.
84462306a36Sopenharmony_ci	 */
84562306a36Sopenharmony_ci	mtspr(SPRN_VRSAVE, vcpu->arch.vrsave);
84662306a36Sopenharmony_ci#endif
84762306a36Sopenharmony_ci	kvmppc_core_vcpu_load(vcpu, cpu);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	kvmppc_core_vcpu_put(vcpu);
85362306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
85462306a36Sopenharmony_ci	vcpu->arch.vrsave = mfspr(SPRN_VRSAVE);
85562306a36Sopenharmony_ci#endif
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/*
85962306a36Sopenharmony_ci * irq_bypass_add_producer and irq_bypass_del_producer are only
86062306a36Sopenharmony_ci * useful if the architecture supports PCI passthrough.
86162306a36Sopenharmony_ci * irq_bypass_stop and irq_bypass_start are not needed and so
86262306a36Sopenharmony_ci * kvm_ops are not defined for them.
86362306a36Sopenharmony_ci */
86462306a36Sopenharmony_cibool kvm_arch_has_irq_bypass(void)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	return ((kvmppc_hv_ops && kvmppc_hv_ops->irq_bypass_add_producer) ||
86762306a36Sopenharmony_ci		(kvmppc_pr_ops && kvmppc_pr_ops->irq_bypass_add_producer));
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ciint kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
87162306a36Sopenharmony_ci				     struct irq_bypass_producer *prod)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct kvm_kernel_irqfd *irqfd =
87462306a36Sopenharmony_ci		container_of(cons, struct kvm_kernel_irqfd, consumer);
87562306a36Sopenharmony_ci	struct kvm *kvm = irqfd->kvm;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (kvm->arch.kvm_ops->irq_bypass_add_producer)
87862306a36Sopenharmony_ci		return kvm->arch.kvm_ops->irq_bypass_add_producer(cons, prod);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	return 0;
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_civoid kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
88462306a36Sopenharmony_ci				      struct irq_bypass_producer *prod)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	struct kvm_kernel_irqfd *irqfd =
88762306a36Sopenharmony_ci		container_of(cons, struct kvm_kernel_irqfd, consumer);
88862306a36Sopenharmony_ci	struct kvm *kvm = irqfd->kvm;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (kvm->arch.kvm_ops->irq_bypass_del_producer)
89162306a36Sopenharmony_ci		kvm->arch.kvm_ops->irq_bypass_del_producer(cons, prod);
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci#ifdef CONFIG_VSX
89562306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_dword_offset(int index)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	int offset;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if ((index != 0) && (index != 1))
90062306a36Sopenharmony_ci		return -1;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
90362306a36Sopenharmony_ci	offset =  index;
90462306a36Sopenharmony_ci#else
90562306a36Sopenharmony_ci	offset = 1 - index;
90662306a36Sopenharmony_ci#endif
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return offset;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_word_offset(int index)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	int offset;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if ((index > 3) || (index < 0))
91662306a36Sopenharmony_ci		return -1;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
91962306a36Sopenharmony_ci	offset = index;
92062306a36Sopenharmony_ci#else
92162306a36Sopenharmony_ci	offset = 3 - index;
92262306a36Sopenharmony_ci#endif
92362306a36Sopenharmony_ci	return offset;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_dword(struct kvm_vcpu *vcpu,
92762306a36Sopenharmony_ci	u64 gpr)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	union kvmppc_one_reg val;
93062306a36Sopenharmony_ci	int offset = kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset);
93162306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (offset == -1)
93462306a36Sopenharmony_ci		return;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (index >= 32) {
93762306a36Sopenharmony_ci		val.vval = VCPU_VSX_VR(vcpu, index - 32);
93862306a36Sopenharmony_ci		val.vsxval[offset] = gpr;
93962306a36Sopenharmony_ci		VCPU_VSX_VR(vcpu, index - 32) = val.vval;
94062306a36Sopenharmony_ci	} else {
94162306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, offset) = gpr;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_dword_dump(struct kvm_vcpu *vcpu,
94662306a36Sopenharmony_ci	u64 gpr)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	union kvmppc_one_reg val;
94962306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (index >= 32) {
95262306a36Sopenharmony_ci		val.vval = VCPU_VSX_VR(vcpu, index - 32);
95362306a36Sopenharmony_ci		val.vsxval[0] = gpr;
95462306a36Sopenharmony_ci		val.vsxval[1] = gpr;
95562306a36Sopenharmony_ci		VCPU_VSX_VR(vcpu, index - 32) = val.vval;
95662306a36Sopenharmony_ci	} else {
95762306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, 0) = gpr;
95862306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, 1) = gpr;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_word_dump(struct kvm_vcpu *vcpu,
96362306a36Sopenharmony_ci	u32 gpr)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	union kvmppc_one_reg val;
96662306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (index >= 32) {
96962306a36Sopenharmony_ci		val.vsx32val[0] = gpr;
97062306a36Sopenharmony_ci		val.vsx32val[1] = gpr;
97162306a36Sopenharmony_ci		val.vsx32val[2] = gpr;
97262306a36Sopenharmony_ci		val.vsx32val[3] = gpr;
97362306a36Sopenharmony_ci		VCPU_VSX_VR(vcpu, index - 32) = val.vval;
97462306a36Sopenharmony_ci	} else {
97562306a36Sopenharmony_ci		val.vsx32val[0] = gpr;
97662306a36Sopenharmony_ci		val.vsx32val[1] = gpr;
97762306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, 0) = val.vsxval[0];
97862306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, 1) = val.vsxval[0];
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu,
98362306a36Sopenharmony_ci	u32 gpr32)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	union kvmppc_one_reg val;
98662306a36Sopenharmony_ci	int offset = kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset);
98762306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
98862306a36Sopenharmony_ci	int dword_offset, word_offset;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (offset == -1)
99162306a36Sopenharmony_ci		return;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (index >= 32) {
99462306a36Sopenharmony_ci		val.vval = VCPU_VSX_VR(vcpu, index - 32);
99562306a36Sopenharmony_ci		val.vsx32val[offset] = gpr32;
99662306a36Sopenharmony_ci		VCPU_VSX_VR(vcpu, index - 32) = val.vval;
99762306a36Sopenharmony_ci	} else {
99862306a36Sopenharmony_ci		dword_offset = offset / 2;
99962306a36Sopenharmony_ci		word_offset = offset % 2;
100062306a36Sopenharmony_ci		val.vsxval[0] = VCPU_VSX_FPR(vcpu, index, dword_offset);
100162306a36Sopenharmony_ci		val.vsx32val[word_offset] = gpr32;
100262306a36Sopenharmony_ci		VCPU_VSX_FPR(vcpu, index, dword_offset) = val.vsxval[0];
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci#endif /* CONFIG_VSX */
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
100862306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_offset_generic(struct kvm_vcpu *vcpu,
100962306a36Sopenharmony_ci		int index, int element_size)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	int offset;
101262306a36Sopenharmony_ci	int elts = sizeof(vector128)/element_size;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if ((index < 0) || (index >= elts))
101562306a36Sopenharmony_ci		return -1;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (kvmppc_need_byteswap(vcpu))
101862306a36Sopenharmony_ci		offset = elts - index - 1;
101962306a36Sopenharmony_ci	else
102062306a36Sopenharmony_ci		offset = index;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	return offset;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_dword_offset(struct kvm_vcpu *vcpu,
102662306a36Sopenharmony_ci		int index)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	return kvmppc_get_vmx_offset_generic(vcpu, index, 8);
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_word_offset(struct kvm_vcpu *vcpu,
103262306a36Sopenharmony_ci		int index)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	return kvmppc_get_vmx_offset_generic(vcpu, index, 4);
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_hword_offset(struct kvm_vcpu *vcpu,
103862306a36Sopenharmony_ci		int index)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	return kvmppc_get_vmx_offset_generic(vcpu, index, 2);
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_byte_offset(struct kvm_vcpu *vcpu,
104462306a36Sopenharmony_ci		int index)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	return kvmppc_get_vmx_offset_generic(vcpu, index, 1);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu,
105162306a36Sopenharmony_ci	u64 gpr)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	union kvmppc_one_reg val;
105462306a36Sopenharmony_ci	int offset = kvmppc_get_vmx_dword_offset(vcpu,
105562306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_offset);
105662306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (offset == -1)
105962306a36Sopenharmony_ci		return;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	val.vval = VCPU_VSX_VR(vcpu, index);
106262306a36Sopenharmony_ci	val.vsxval[offset] = gpr;
106362306a36Sopenharmony_ci	VCPU_VSX_VR(vcpu, index) = val.vval;
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu,
106762306a36Sopenharmony_ci	u32 gpr32)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	union kvmppc_one_reg val;
107062306a36Sopenharmony_ci	int offset = kvmppc_get_vmx_word_offset(vcpu,
107162306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_offset);
107262306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (offset == -1)
107562306a36Sopenharmony_ci		return;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	val.vval = VCPU_VSX_VR(vcpu, index);
107862306a36Sopenharmony_ci	val.vsx32val[offset] = gpr32;
107962306a36Sopenharmony_ci	VCPU_VSX_VR(vcpu, index) = val.vval;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu,
108362306a36Sopenharmony_ci	u16 gpr16)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	union kvmppc_one_reg val;
108662306a36Sopenharmony_ci	int offset = kvmppc_get_vmx_hword_offset(vcpu,
108762306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_offset);
108862306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (offset == -1)
109162306a36Sopenharmony_ci		return;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	val.vval = VCPU_VSX_VR(vcpu, index);
109462306a36Sopenharmony_ci	val.vsx16val[offset] = gpr16;
109562306a36Sopenharmony_ci	VCPU_VSX_VR(vcpu, index) = val.vval;
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu,
109962306a36Sopenharmony_ci	u8 gpr8)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	union kvmppc_one_reg val;
110262306a36Sopenharmony_ci	int offset = kvmppc_get_vmx_byte_offset(vcpu,
110362306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_offset);
110462306a36Sopenharmony_ci	int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (offset == -1)
110762306a36Sopenharmony_ci		return;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	val.vval = VCPU_VSX_VR(vcpu, index);
111062306a36Sopenharmony_ci	val.vsx8val[offset] = gpr8;
111162306a36Sopenharmony_ci	VCPU_VSX_VR(vcpu, index) = val.vval;
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci#ifdef CONFIG_PPC_FPU
111662306a36Sopenharmony_cistatic inline u64 sp_to_dp(u32 fprs)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	u64 fprd;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	preempt_disable();
112162306a36Sopenharmony_ci	enable_kernel_fp();
112262306a36Sopenharmony_ci	asm ("lfs%U1%X1 0,%1; stfd%U0%X0 0,%0" : "=m<>" (fprd) : "m<>" (fprs)
112362306a36Sopenharmony_ci	     : "fr0");
112462306a36Sopenharmony_ci	preempt_enable();
112562306a36Sopenharmony_ci	return fprd;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic inline u32 dp_to_sp(u64 fprd)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	u32 fprs;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	preempt_disable();
113362306a36Sopenharmony_ci	enable_kernel_fp();
113462306a36Sopenharmony_ci	asm ("lfd%U1%X1 0,%1; stfs%U0%X0 0,%0" : "=m<>" (fprs) : "m<>" (fprd)
113562306a36Sopenharmony_ci	     : "fr0");
113662306a36Sopenharmony_ci	preempt_enable();
113762306a36Sopenharmony_ci	return fprs;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci#else
114162306a36Sopenharmony_ci#define sp_to_dp(x)	(x)
114262306a36Sopenharmony_ci#define dp_to_sp(x)	(x)
114362306a36Sopenharmony_ci#endif /* CONFIG_PPC_FPU */
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cistatic void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
114862306a36Sopenharmony_ci	u64 gpr;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (run->mmio.len > sizeof(gpr))
115162306a36Sopenharmony_ci		return;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (!vcpu->arch.mmio_host_swabbed) {
115462306a36Sopenharmony_ci		switch (run->mmio.len) {
115562306a36Sopenharmony_ci		case 8: gpr = *(u64 *)run->mmio.data; break;
115662306a36Sopenharmony_ci		case 4: gpr = *(u32 *)run->mmio.data; break;
115762306a36Sopenharmony_ci		case 2: gpr = *(u16 *)run->mmio.data; break;
115862306a36Sopenharmony_ci		case 1: gpr = *(u8 *)run->mmio.data; break;
115962306a36Sopenharmony_ci		}
116062306a36Sopenharmony_ci	} else {
116162306a36Sopenharmony_ci		switch (run->mmio.len) {
116262306a36Sopenharmony_ci		case 8: gpr = swab64(*(u64 *)run->mmio.data); break;
116362306a36Sopenharmony_ci		case 4: gpr = swab32(*(u32 *)run->mmio.data); break;
116462306a36Sopenharmony_ci		case 2: gpr = swab16(*(u16 *)run->mmio.data); break;
116562306a36Sopenharmony_ci		case 1: gpr = *(u8 *)run->mmio.data; break;
116662306a36Sopenharmony_ci		}
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* conversion between single and double precision */
117062306a36Sopenharmony_ci	if ((vcpu->arch.mmio_sp64_extend) && (run->mmio.len == 4))
117162306a36Sopenharmony_ci		gpr = sp_to_dp(gpr);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (vcpu->arch.mmio_sign_extend) {
117462306a36Sopenharmony_ci		switch (run->mmio.len) {
117562306a36Sopenharmony_ci#ifdef CONFIG_PPC64
117662306a36Sopenharmony_ci		case 4:
117762306a36Sopenharmony_ci			gpr = (s64)(s32)gpr;
117862306a36Sopenharmony_ci			break;
117962306a36Sopenharmony_ci#endif
118062306a36Sopenharmony_ci		case 2:
118162306a36Sopenharmony_ci			gpr = (s64)(s16)gpr;
118262306a36Sopenharmony_ci			break;
118362306a36Sopenharmony_ci		case 1:
118462306a36Sopenharmony_ci			gpr = (s64)(s8)gpr;
118562306a36Sopenharmony_ci			break;
118662306a36Sopenharmony_ci		}
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) {
119062306a36Sopenharmony_ci	case KVM_MMIO_REG_GPR:
119162306a36Sopenharmony_ci		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
119262306a36Sopenharmony_ci		break;
119362306a36Sopenharmony_ci	case KVM_MMIO_REG_FPR:
119462306a36Sopenharmony_ci		if (vcpu->kvm->arch.kvm_ops->giveup_ext)
119562306a36Sopenharmony_ci			vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_FP);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
119862306a36Sopenharmony_ci		break;
119962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S
120062306a36Sopenharmony_ci	case KVM_MMIO_REG_QPR:
120162306a36Sopenharmony_ci		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
120262306a36Sopenharmony_ci		break;
120362306a36Sopenharmony_ci	case KVM_MMIO_REG_FQPR:
120462306a36Sopenharmony_ci		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
120562306a36Sopenharmony_ci		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
120662306a36Sopenharmony_ci		break;
120762306a36Sopenharmony_ci#endif
120862306a36Sopenharmony_ci#ifdef CONFIG_VSX
120962306a36Sopenharmony_ci	case KVM_MMIO_REG_VSX:
121062306a36Sopenharmony_ci		if (vcpu->kvm->arch.kvm_ops->giveup_ext)
121162306a36Sopenharmony_ci			vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VSX);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci		if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_DWORD)
121462306a36Sopenharmony_ci			kvmppc_set_vsr_dword(vcpu, gpr);
121562306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_WORD)
121662306a36Sopenharmony_ci			kvmppc_set_vsr_word(vcpu, gpr);
121762306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type ==
121862306a36Sopenharmony_ci				KVMPPC_VSX_COPY_DWORD_LOAD_DUMP)
121962306a36Sopenharmony_ci			kvmppc_set_vsr_dword_dump(vcpu, gpr);
122062306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type ==
122162306a36Sopenharmony_ci				KVMPPC_VSX_COPY_WORD_LOAD_DUMP)
122262306a36Sopenharmony_ci			kvmppc_set_vsr_word_dump(vcpu, gpr);
122362306a36Sopenharmony_ci		break;
122462306a36Sopenharmony_ci#endif
122562306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
122662306a36Sopenharmony_ci	case KVM_MMIO_REG_VMX:
122762306a36Sopenharmony_ci		if (vcpu->kvm->arch.kvm_ops->giveup_ext)
122862306a36Sopenharmony_ci			vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VEC);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_DWORD)
123162306a36Sopenharmony_ci			kvmppc_set_vmx_dword(vcpu, gpr);
123262306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_WORD)
123362306a36Sopenharmony_ci			kvmppc_set_vmx_word(vcpu, gpr);
123462306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type ==
123562306a36Sopenharmony_ci				KVMPPC_VMX_COPY_HWORD)
123662306a36Sopenharmony_ci			kvmppc_set_vmx_hword(vcpu, gpr);
123762306a36Sopenharmony_ci		else if (vcpu->arch.mmio_copy_type ==
123862306a36Sopenharmony_ci				KVMPPC_VMX_COPY_BYTE)
123962306a36Sopenharmony_ci			kvmppc_set_vmx_byte(vcpu, gpr);
124062306a36Sopenharmony_ci		break;
124162306a36Sopenharmony_ci#endif
124262306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
124362306a36Sopenharmony_ci	case KVM_MMIO_REG_NESTED_GPR:
124462306a36Sopenharmony_ci		if (kvmppc_need_byteswap(vcpu))
124562306a36Sopenharmony_ci			gpr = swab64(gpr);
124662306a36Sopenharmony_ci		kvm_vcpu_write_guest(vcpu, vcpu->arch.nested_io_gpr, &gpr,
124762306a36Sopenharmony_ci				     sizeof(gpr));
124862306a36Sopenharmony_ci		break;
124962306a36Sopenharmony_ci#endif
125062306a36Sopenharmony_ci	default:
125162306a36Sopenharmony_ci		BUG();
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic int __kvmppc_handle_load(struct kvm_vcpu *vcpu,
125662306a36Sopenharmony_ci				unsigned int rt, unsigned int bytes,
125762306a36Sopenharmony_ci				int is_default_endian, int sign_extend)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
126062306a36Sopenharmony_ci	int idx, ret;
126162306a36Sopenharmony_ci	bool host_swabbed;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	/* Pity C doesn't have a logical XOR operator */
126462306a36Sopenharmony_ci	if (kvmppc_need_byteswap(vcpu)) {
126562306a36Sopenharmony_ci		host_swabbed = is_default_endian;
126662306a36Sopenharmony_ci	} else {
126762306a36Sopenharmony_ci		host_swabbed = !is_default_endian;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if (bytes > sizeof(run->mmio.data))
127162306a36Sopenharmony_ci		return EMULATE_FAIL;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
127462306a36Sopenharmony_ci	run->mmio.len = bytes;
127562306a36Sopenharmony_ci	run->mmio.is_write = 0;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	vcpu->arch.io_gpr = rt;
127862306a36Sopenharmony_ci	vcpu->arch.mmio_host_swabbed = host_swabbed;
127962306a36Sopenharmony_ci	vcpu->mmio_needed = 1;
128062306a36Sopenharmony_ci	vcpu->mmio_is_write = 0;
128162306a36Sopenharmony_ci	vcpu->arch.mmio_sign_extend = sign_extend;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	idx = srcu_read_lock(&vcpu->kvm->srcu);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
128662306a36Sopenharmony_ci			      bytes, &run->mmio.data);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	srcu_read_unlock(&vcpu->kvm->srcu, idx);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (!ret) {
129162306a36Sopenharmony_ci		kvmppc_complete_mmio_load(vcpu);
129262306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
129362306a36Sopenharmony_ci		return EMULATE_DONE;
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return EMULATE_DO_MMIO;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ciint kvmppc_handle_load(struct kvm_vcpu *vcpu,
130062306a36Sopenharmony_ci		       unsigned int rt, unsigned int bytes,
130162306a36Sopenharmony_ci		       int is_default_endian)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 0);
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_load);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci/* Same as above, but sign extends */
130862306a36Sopenharmony_ciint kvmppc_handle_loads(struct kvm_vcpu *vcpu,
130962306a36Sopenharmony_ci			unsigned int rt, unsigned int bytes,
131062306a36Sopenharmony_ci			int is_default_endian)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 1);
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci#ifdef CONFIG_VSX
131662306a36Sopenharmony_ciint kvmppc_handle_vsx_load(struct kvm_vcpu *vcpu,
131762306a36Sopenharmony_ci			unsigned int rt, unsigned int bytes,
131862306a36Sopenharmony_ci			int is_default_endian, int mmio_sign_extend)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_DONE;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	/* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */
132362306a36Sopenharmony_ci	if (vcpu->arch.mmio_vsx_copy_nums > 4)
132462306a36Sopenharmony_ci		return EMULATE_FAIL;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	while (vcpu->arch.mmio_vsx_copy_nums) {
132762306a36Sopenharmony_ci		emulated = __kvmppc_handle_load(vcpu, rt, bytes,
132862306a36Sopenharmony_ci			is_default_endian, mmio_sign_extend);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		if (emulated != EMULATE_DONE)
133162306a36Sopenharmony_ci			break;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		vcpu->arch.paddr_accessed += vcpu->run->mmio.len;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci		vcpu->arch.mmio_vsx_copy_nums--;
133662306a36Sopenharmony_ci		vcpu->arch.mmio_vsx_offset++;
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci	return emulated;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci#endif /* CONFIG_VSX */
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ciint kvmppc_handle_store(struct kvm_vcpu *vcpu,
134362306a36Sopenharmony_ci			u64 val, unsigned int bytes, int is_default_endian)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
134662306a36Sopenharmony_ci	void *data = run->mmio.data;
134762306a36Sopenharmony_ci	int idx, ret;
134862306a36Sopenharmony_ci	bool host_swabbed;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	/* Pity C doesn't have a logical XOR operator */
135162306a36Sopenharmony_ci	if (kvmppc_need_byteswap(vcpu)) {
135262306a36Sopenharmony_ci		host_swabbed = is_default_endian;
135362306a36Sopenharmony_ci	} else {
135462306a36Sopenharmony_ci		host_swabbed = !is_default_endian;
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	if (bytes > sizeof(run->mmio.data))
135862306a36Sopenharmony_ci		return EMULATE_FAIL;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
136162306a36Sopenharmony_ci	run->mmio.len = bytes;
136262306a36Sopenharmony_ci	run->mmio.is_write = 1;
136362306a36Sopenharmony_ci	vcpu->mmio_needed = 1;
136462306a36Sopenharmony_ci	vcpu->mmio_is_write = 1;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if ((vcpu->arch.mmio_sp64_extend) && (bytes == 4))
136762306a36Sopenharmony_ci		val = dp_to_sp(val);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	/* Store the value at the lowest bytes in 'data'. */
137062306a36Sopenharmony_ci	if (!host_swabbed) {
137162306a36Sopenharmony_ci		switch (bytes) {
137262306a36Sopenharmony_ci		case 8: *(u64 *)data = val; break;
137362306a36Sopenharmony_ci		case 4: *(u32 *)data = val; break;
137462306a36Sopenharmony_ci		case 2: *(u16 *)data = val; break;
137562306a36Sopenharmony_ci		case 1: *(u8  *)data = val; break;
137662306a36Sopenharmony_ci		}
137762306a36Sopenharmony_ci	} else {
137862306a36Sopenharmony_ci		switch (bytes) {
137962306a36Sopenharmony_ci		case 8: *(u64 *)data = swab64(val); break;
138062306a36Sopenharmony_ci		case 4: *(u32 *)data = swab32(val); break;
138162306a36Sopenharmony_ci		case 2: *(u16 *)data = swab16(val); break;
138262306a36Sopenharmony_ci		case 1: *(u8  *)data = val; break;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	idx = srcu_read_lock(&vcpu->kvm->srcu);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
138962306a36Sopenharmony_ci			       bytes, &run->mmio.data);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	srcu_read_unlock(&vcpu->kvm->srcu, idx);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (!ret) {
139462306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
139562306a36Sopenharmony_ci		return EMULATE_DONE;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return EMULATE_DO_MMIO;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_store);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci#ifdef CONFIG_VSX
140362306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	u32 dword_offset, word_offset;
140662306a36Sopenharmony_ci	union kvmppc_one_reg reg;
140762306a36Sopenharmony_ci	int vsx_offset = 0;
140862306a36Sopenharmony_ci	int copy_type = vcpu->arch.mmio_copy_type;
140962306a36Sopenharmony_ci	int result = 0;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	switch (copy_type) {
141262306a36Sopenharmony_ci	case KVMPPC_VSX_COPY_DWORD:
141362306a36Sopenharmony_ci		vsx_offset =
141462306a36Sopenharmony_ci			kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci		if (vsx_offset == -1) {
141762306a36Sopenharmony_ci			result = -1;
141862306a36Sopenharmony_ci			break;
141962306a36Sopenharmony_ci		}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci		if (rs < 32) {
142262306a36Sopenharmony_ci			*val = VCPU_VSX_FPR(vcpu, rs, vsx_offset);
142362306a36Sopenharmony_ci		} else {
142462306a36Sopenharmony_ci			reg.vval = VCPU_VSX_VR(vcpu, rs - 32);
142562306a36Sopenharmony_ci			*val = reg.vsxval[vsx_offset];
142662306a36Sopenharmony_ci		}
142762306a36Sopenharmony_ci		break;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	case KVMPPC_VSX_COPY_WORD:
143062306a36Sopenharmony_ci		vsx_offset =
143162306a36Sopenharmony_ci			kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		if (vsx_offset == -1) {
143462306a36Sopenharmony_ci			result = -1;
143562306a36Sopenharmony_ci			break;
143662306a36Sopenharmony_ci		}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci		if (rs < 32) {
143962306a36Sopenharmony_ci			dword_offset = vsx_offset / 2;
144062306a36Sopenharmony_ci			word_offset = vsx_offset % 2;
144162306a36Sopenharmony_ci			reg.vsxval[0] = VCPU_VSX_FPR(vcpu, rs, dword_offset);
144262306a36Sopenharmony_ci			*val = reg.vsx32val[word_offset];
144362306a36Sopenharmony_ci		} else {
144462306a36Sopenharmony_ci			reg.vval = VCPU_VSX_VR(vcpu, rs - 32);
144562306a36Sopenharmony_ci			*val = reg.vsx32val[vsx_offset];
144662306a36Sopenharmony_ci		}
144762306a36Sopenharmony_ci		break;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	default:
145062306a36Sopenharmony_ci		result = -1;
145162306a36Sopenharmony_ci		break;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	return result;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ciint kvmppc_handle_vsx_store(struct kvm_vcpu *vcpu,
145862306a36Sopenharmony_ci			int rs, unsigned int bytes, int is_default_endian)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	u64 val;
146162306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_DONE;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	vcpu->arch.io_gpr = rs;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */
146662306a36Sopenharmony_ci	if (vcpu->arch.mmio_vsx_copy_nums > 4)
146762306a36Sopenharmony_ci		return EMULATE_FAIL;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	while (vcpu->arch.mmio_vsx_copy_nums) {
147062306a36Sopenharmony_ci		if (kvmppc_get_vsr_data(vcpu, rs, &val) == -1)
147162306a36Sopenharmony_ci			return EMULATE_FAIL;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci		emulated = kvmppc_handle_store(vcpu,
147462306a36Sopenharmony_ci			 val, bytes, is_default_endian);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		if (emulated != EMULATE_DONE)
147762306a36Sopenharmony_ci			break;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		vcpu->arch.paddr_accessed += vcpu->run->mmio.len;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		vcpu->arch.mmio_vsx_copy_nums--;
148262306a36Sopenharmony_ci		vcpu->arch.mmio_vsx_offset++;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return emulated;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
149162306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_FAIL;
149262306a36Sopenharmony_ci	int r;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	vcpu->arch.paddr_accessed += run->mmio.len;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (!vcpu->mmio_is_write) {
149762306a36Sopenharmony_ci		emulated = kvmppc_handle_vsx_load(vcpu, vcpu->arch.io_gpr,
149862306a36Sopenharmony_ci			 run->mmio.len, 1, vcpu->arch.mmio_sign_extend);
149962306a36Sopenharmony_ci	} else {
150062306a36Sopenharmony_ci		emulated = kvmppc_handle_vsx_store(vcpu,
150162306a36Sopenharmony_ci			 vcpu->arch.io_gpr, run->mmio.len, 1);
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	switch (emulated) {
150562306a36Sopenharmony_ci	case EMULATE_DO_MMIO:
150662306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_MMIO;
150762306a36Sopenharmony_ci		r = RESUME_HOST;
150862306a36Sopenharmony_ci		break;
150962306a36Sopenharmony_ci	case EMULATE_FAIL:
151062306a36Sopenharmony_ci		pr_info("KVM: MMIO emulation failed (VSX repeat)\n");
151162306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
151262306a36Sopenharmony_ci		run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
151362306a36Sopenharmony_ci		r = RESUME_HOST;
151462306a36Sopenharmony_ci		break;
151562306a36Sopenharmony_ci	default:
151662306a36Sopenharmony_ci		r = RESUME_GUEST;
151762306a36Sopenharmony_ci		break;
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci	return r;
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci#endif /* CONFIG_VSX */
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
152462306a36Sopenharmony_ciint kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu,
152562306a36Sopenharmony_ci		unsigned int rt, unsigned int bytes, int is_default_endian)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_DONE;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (vcpu->arch.mmio_vmx_copy_nums > 2)
153062306a36Sopenharmony_ci		return EMULATE_FAIL;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	while (vcpu->arch.mmio_vmx_copy_nums) {
153362306a36Sopenharmony_ci		emulated = __kvmppc_handle_load(vcpu, rt, bytes,
153462306a36Sopenharmony_ci				is_default_endian, 0);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		if (emulated != EMULATE_DONE)
153762306a36Sopenharmony_ci			break;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		vcpu->arch.paddr_accessed += vcpu->run->mmio.len;
154062306a36Sopenharmony_ci		vcpu->arch.mmio_vmx_copy_nums--;
154162306a36Sopenharmony_ci		vcpu->arch.mmio_vmx_offset++;
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	return emulated;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_cistatic int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	union kvmppc_one_reg reg;
155062306a36Sopenharmony_ci	int vmx_offset = 0;
155162306a36Sopenharmony_ci	int result = 0;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	vmx_offset =
155462306a36Sopenharmony_ci		kvmppc_get_vmx_dword_offset(vcpu, vcpu->arch.mmio_vmx_offset);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	if (vmx_offset == -1)
155762306a36Sopenharmony_ci		return -1;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	reg.vval = VCPU_VSX_VR(vcpu, index);
156062306a36Sopenharmony_ci	*val = reg.vsxval[vmx_offset];
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	return result;
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_cistatic int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	union kvmppc_one_reg reg;
156862306a36Sopenharmony_ci	int vmx_offset = 0;
156962306a36Sopenharmony_ci	int result = 0;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	vmx_offset =
157262306a36Sopenharmony_ci		kvmppc_get_vmx_word_offset(vcpu, vcpu->arch.mmio_vmx_offset);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	if (vmx_offset == -1)
157562306a36Sopenharmony_ci		return -1;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	reg.vval = VCPU_VSX_VR(vcpu, index);
157862306a36Sopenharmony_ci	*val = reg.vsx32val[vmx_offset];
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	return result;
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	union kvmppc_one_reg reg;
158662306a36Sopenharmony_ci	int vmx_offset = 0;
158762306a36Sopenharmony_ci	int result = 0;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	vmx_offset =
159062306a36Sopenharmony_ci		kvmppc_get_vmx_hword_offset(vcpu, vcpu->arch.mmio_vmx_offset);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (vmx_offset == -1)
159362306a36Sopenharmony_ci		return -1;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	reg.vval = VCPU_VSX_VR(vcpu, index);
159662306a36Sopenharmony_ci	*val = reg.vsx16val[vmx_offset];
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	return result;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	union kvmppc_one_reg reg;
160462306a36Sopenharmony_ci	int vmx_offset = 0;
160562306a36Sopenharmony_ci	int result = 0;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	vmx_offset =
160862306a36Sopenharmony_ci		kvmppc_get_vmx_byte_offset(vcpu, vcpu->arch.mmio_vmx_offset);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	if (vmx_offset == -1)
161162306a36Sopenharmony_ci		return -1;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	reg.vval = VCPU_VSX_VR(vcpu, index);
161462306a36Sopenharmony_ci	*val = reg.vsx8val[vmx_offset];
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	return result;
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ciint kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu,
162062306a36Sopenharmony_ci		unsigned int rs, unsigned int bytes, int is_default_endian)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	u64 val = 0;
162362306a36Sopenharmony_ci	unsigned int index = rs & KVM_MMIO_REG_MASK;
162462306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_DONE;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	if (vcpu->arch.mmio_vmx_copy_nums > 2)
162762306a36Sopenharmony_ci		return EMULATE_FAIL;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	vcpu->arch.io_gpr = rs;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	while (vcpu->arch.mmio_vmx_copy_nums) {
163262306a36Sopenharmony_ci		switch (vcpu->arch.mmio_copy_type) {
163362306a36Sopenharmony_ci		case KVMPPC_VMX_COPY_DWORD:
163462306a36Sopenharmony_ci			if (kvmppc_get_vmx_dword(vcpu, index, &val) == -1)
163562306a36Sopenharmony_ci				return EMULATE_FAIL;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci			break;
163862306a36Sopenharmony_ci		case KVMPPC_VMX_COPY_WORD:
163962306a36Sopenharmony_ci			if (kvmppc_get_vmx_word(vcpu, index, &val) == -1)
164062306a36Sopenharmony_ci				return EMULATE_FAIL;
164162306a36Sopenharmony_ci			break;
164262306a36Sopenharmony_ci		case KVMPPC_VMX_COPY_HWORD:
164362306a36Sopenharmony_ci			if (kvmppc_get_vmx_hword(vcpu, index, &val) == -1)
164462306a36Sopenharmony_ci				return EMULATE_FAIL;
164562306a36Sopenharmony_ci			break;
164662306a36Sopenharmony_ci		case KVMPPC_VMX_COPY_BYTE:
164762306a36Sopenharmony_ci			if (kvmppc_get_vmx_byte(vcpu, index, &val) == -1)
164862306a36Sopenharmony_ci				return EMULATE_FAIL;
164962306a36Sopenharmony_ci			break;
165062306a36Sopenharmony_ci		default:
165162306a36Sopenharmony_ci			return EMULATE_FAIL;
165262306a36Sopenharmony_ci		}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		emulated = kvmppc_handle_store(vcpu, val, bytes,
165562306a36Sopenharmony_ci				is_default_endian);
165662306a36Sopenharmony_ci		if (emulated != EMULATE_DONE)
165762306a36Sopenharmony_ci			break;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		vcpu->arch.paddr_accessed += vcpu->run->mmio.len;
166062306a36Sopenharmony_ci		vcpu->arch.mmio_vmx_copy_nums--;
166162306a36Sopenharmony_ci		vcpu->arch.mmio_vmx_offset++;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	return emulated;
166562306a36Sopenharmony_ci}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic int kvmppc_emulate_mmio_vmx_loadstore(struct kvm_vcpu *vcpu)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
167062306a36Sopenharmony_ci	enum emulation_result emulated = EMULATE_FAIL;
167162306a36Sopenharmony_ci	int r;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	vcpu->arch.paddr_accessed += run->mmio.len;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (!vcpu->mmio_is_write) {
167662306a36Sopenharmony_ci		emulated = kvmppc_handle_vmx_load(vcpu,
167762306a36Sopenharmony_ci				vcpu->arch.io_gpr, run->mmio.len, 1);
167862306a36Sopenharmony_ci	} else {
167962306a36Sopenharmony_ci		emulated = kvmppc_handle_vmx_store(vcpu,
168062306a36Sopenharmony_ci				vcpu->arch.io_gpr, run->mmio.len, 1);
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	switch (emulated) {
168462306a36Sopenharmony_ci	case EMULATE_DO_MMIO:
168562306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_MMIO;
168662306a36Sopenharmony_ci		r = RESUME_HOST;
168762306a36Sopenharmony_ci		break;
168862306a36Sopenharmony_ci	case EMULATE_FAIL:
168962306a36Sopenharmony_ci		pr_info("KVM: MMIO emulation failed (VMX repeat)\n");
169062306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
169162306a36Sopenharmony_ci		run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
169262306a36Sopenharmony_ci		r = RESUME_HOST;
169362306a36Sopenharmony_ci		break;
169462306a36Sopenharmony_ci	default:
169562306a36Sopenharmony_ci		r = RESUME_GUEST;
169662306a36Sopenharmony_ci		break;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci	return r;
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ciint kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
170362306a36Sopenharmony_ci{
170462306a36Sopenharmony_ci	int r = 0;
170562306a36Sopenharmony_ci	union kvmppc_one_reg val;
170662306a36Sopenharmony_ci	int size;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	size = one_reg_size(reg->id);
170962306a36Sopenharmony_ci	if (size > sizeof(val))
171062306a36Sopenharmony_ci		return -EINVAL;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	r = kvmppc_get_one_reg(vcpu, reg->id, &val);
171362306a36Sopenharmony_ci	if (r == -EINVAL) {
171462306a36Sopenharmony_ci		r = 0;
171562306a36Sopenharmony_ci		switch (reg->id) {
171662306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
171762306a36Sopenharmony_ci		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
171862306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
171962306a36Sopenharmony_ci				r = -ENXIO;
172062306a36Sopenharmony_ci				break;
172162306a36Sopenharmony_ci			}
172262306a36Sopenharmony_ci			val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
172362306a36Sopenharmony_ci			break;
172462306a36Sopenharmony_ci		case KVM_REG_PPC_VSCR:
172562306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
172662306a36Sopenharmony_ci				r = -ENXIO;
172762306a36Sopenharmony_ci				break;
172862306a36Sopenharmony_ci			}
172962306a36Sopenharmony_ci			val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
173062306a36Sopenharmony_ci			break;
173162306a36Sopenharmony_ci		case KVM_REG_PPC_VRSAVE:
173262306a36Sopenharmony_ci			val = get_reg_val(reg->id, vcpu->arch.vrsave);
173362306a36Sopenharmony_ci			break;
173462306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
173562306a36Sopenharmony_ci		default:
173662306a36Sopenharmony_ci			r = -EINVAL;
173762306a36Sopenharmony_ci			break;
173862306a36Sopenharmony_ci		}
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	if (r)
174262306a36Sopenharmony_ci		return r;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size))
174562306a36Sopenharmony_ci		r = -EFAULT;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	return r;
174862306a36Sopenharmony_ci}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ciint kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	int r;
175362306a36Sopenharmony_ci	union kvmppc_one_reg val;
175462306a36Sopenharmony_ci	int size;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	size = one_reg_size(reg->id);
175762306a36Sopenharmony_ci	if (size > sizeof(val))
175862306a36Sopenharmony_ci		return -EINVAL;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
176162306a36Sopenharmony_ci		return -EFAULT;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	r = kvmppc_set_one_reg(vcpu, reg->id, &val);
176462306a36Sopenharmony_ci	if (r == -EINVAL) {
176562306a36Sopenharmony_ci		r = 0;
176662306a36Sopenharmony_ci		switch (reg->id) {
176762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
176862306a36Sopenharmony_ci		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
176962306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
177062306a36Sopenharmony_ci				r = -ENXIO;
177162306a36Sopenharmony_ci				break;
177262306a36Sopenharmony_ci			}
177362306a36Sopenharmony_ci			vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
177462306a36Sopenharmony_ci			break;
177562306a36Sopenharmony_ci		case KVM_REG_PPC_VSCR:
177662306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
177762306a36Sopenharmony_ci				r = -ENXIO;
177862306a36Sopenharmony_ci				break;
177962306a36Sopenharmony_ci			}
178062306a36Sopenharmony_ci			vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
178162306a36Sopenharmony_ci			break;
178262306a36Sopenharmony_ci		case KVM_REG_PPC_VRSAVE:
178362306a36Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
178462306a36Sopenharmony_ci				r = -ENXIO;
178562306a36Sopenharmony_ci				break;
178662306a36Sopenharmony_ci			}
178762306a36Sopenharmony_ci			vcpu->arch.vrsave = set_reg_val(reg->id, val);
178862306a36Sopenharmony_ci			break;
178962306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
179062306a36Sopenharmony_ci		default:
179162306a36Sopenharmony_ci			r = -EINVAL;
179262306a36Sopenharmony_ci			break;
179362306a36Sopenharmony_ci		}
179462306a36Sopenharmony_ci	}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	return r;
179762306a36Sopenharmony_ci}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
180262306a36Sopenharmony_ci	int r;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	vcpu_load(vcpu);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (vcpu->mmio_needed) {
180762306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
180862306a36Sopenharmony_ci		if (!vcpu->mmio_is_write)
180962306a36Sopenharmony_ci			kvmppc_complete_mmio_load(vcpu);
181062306a36Sopenharmony_ci#ifdef CONFIG_VSX
181162306a36Sopenharmony_ci		if (vcpu->arch.mmio_vsx_copy_nums > 0) {
181262306a36Sopenharmony_ci			vcpu->arch.mmio_vsx_copy_nums--;
181362306a36Sopenharmony_ci			vcpu->arch.mmio_vsx_offset++;
181462306a36Sopenharmony_ci		}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci		if (vcpu->arch.mmio_vsx_copy_nums > 0) {
181762306a36Sopenharmony_ci			r = kvmppc_emulate_mmio_vsx_loadstore(vcpu);
181862306a36Sopenharmony_ci			if (r == RESUME_HOST) {
181962306a36Sopenharmony_ci				vcpu->mmio_needed = 1;
182062306a36Sopenharmony_ci				goto out;
182162306a36Sopenharmony_ci			}
182262306a36Sopenharmony_ci		}
182362306a36Sopenharmony_ci#endif
182462306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
182562306a36Sopenharmony_ci		if (vcpu->arch.mmio_vmx_copy_nums > 0) {
182662306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_copy_nums--;
182762306a36Sopenharmony_ci			vcpu->arch.mmio_vmx_offset++;
182862306a36Sopenharmony_ci		}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		if (vcpu->arch.mmio_vmx_copy_nums > 0) {
183162306a36Sopenharmony_ci			r = kvmppc_emulate_mmio_vmx_loadstore(vcpu);
183262306a36Sopenharmony_ci			if (r == RESUME_HOST) {
183362306a36Sopenharmony_ci				vcpu->mmio_needed = 1;
183462306a36Sopenharmony_ci				goto out;
183562306a36Sopenharmony_ci			}
183662306a36Sopenharmony_ci		}
183762306a36Sopenharmony_ci#endif
183862306a36Sopenharmony_ci	} else if (vcpu->arch.osi_needed) {
183962306a36Sopenharmony_ci		u64 *gprs = run->osi.gprs;
184062306a36Sopenharmony_ci		int i;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci		for (i = 0; i < 32; i++)
184362306a36Sopenharmony_ci			kvmppc_set_gpr(vcpu, i, gprs[i]);
184462306a36Sopenharmony_ci		vcpu->arch.osi_needed = 0;
184562306a36Sopenharmony_ci	} else if (vcpu->arch.hcall_needed) {
184662306a36Sopenharmony_ci		int i;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		kvmppc_set_gpr(vcpu, 3, run->papr_hcall.ret);
184962306a36Sopenharmony_ci		for (i = 0; i < 9; ++i)
185062306a36Sopenharmony_ci			kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]);
185162306a36Sopenharmony_ci		vcpu->arch.hcall_needed = 0;
185262306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
185362306a36Sopenharmony_ci	} else if (vcpu->arch.epr_needed) {
185462306a36Sopenharmony_ci		kvmppc_set_epr(vcpu, run->epr.epr);
185562306a36Sopenharmony_ci		vcpu->arch.epr_needed = 0;
185662306a36Sopenharmony_ci#endif
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	kvm_sigset_activate(vcpu);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (run->immediate_exit)
186262306a36Sopenharmony_ci		r = -EINTR;
186362306a36Sopenharmony_ci	else
186462306a36Sopenharmony_ci		r = kvmppc_vcpu_run(vcpu);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	kvm_sigset_deactivate(vcpu);
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
186962306a36Sopenharmony_ciout:
187062306a36Sopenharmony_ci#endif
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	/*
187362306a36Sopenharmony_ci	 * We're already returning to userspace, don't pass the
187462306a36Sopenharmony_ci	 * RESUME_HOST flags along.
187562306a36Sopenharmony_ci	 */
187662306a36Sopenharmony_ci	if (r > 0)
187762306a36Sopenharmony_ci		r = 0;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	vcpu_put(vcpu);
188062306a36Sopenharmony_ci	return r;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ciint kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	if (irq->irq == KVM_INTERRUPT_UNSET) {
188662306a36Sopenharmony_ci		kvmppc_core_dequeue_external(vcpu);
188762306a36Sopenharmony_ci		return 0;
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	kvmppc_core_queue_external(vcpu, irq);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	kvm_vcpu_kick(vcpu);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	return 0;
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
189862306a36Sopenharmony_ci				     struct kvm_enable_cap *cap)
189962306a36Sopenharmony_ci{
190062306a36Sopenharmony_ci	int r;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	if (cap->flags)
190362306a36Sopenharmony_ci		return -EINVAL;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	switch (cap->cap) {
190662306a36Sopenharmony_ci	case KVM_CAP_PPC_OSI:
190762306a36Sopenharmony_ci		r = 0;
190862306a36Sopenharmony_ci		vcpu->arch.osi_enabled = true;
190962306a36Sopenharmony_ci		break;
191062306a36Sopenharmony_ci	case KVM_CAP_PPC_PAPR:
191162306a36Sopenharmony_ci		r = 0;
191262306a36Sopenharmony_ci		vcpu->arch.papr_enabled = true;
191362306a36Sopenharmony_ci		break;
191462306a36Sopenharmony_ci	case KVM_CAP_PPC_EPR:
191562306a36Sopenharmony_ci		r = 0;
191662306a36Sopenharmony_ci		if (cap->args[0])
191762306a36Sopenharmony_ci			vcpu->arch.epr_flags |= KVMPPC_EPR_USER;
191862306a36Sopenharmony_ci		else
191962306a36Sopenharmony_ci			vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER;
192062306a36Sopenharmony_ci		break;
192162306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
192262306a36Sopenharmony_ci	case KVM_CAP_PPC_BOOKE_WATCHDOG:
192362306a36Sopenharmony_ci		r = 0;
192462306a36Sopenharmony_ci		vcpu->arch.watchdog_enabled = true;
192562306a36Sopenharmony_ci		break;
192662306a36Sopenharmony_ci#endif
192762306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
192862306a36Sopenharmony_ci	case KVM_CAP_SW_TLB: {
192962306a36Sopenharmony_ci		struct kvm_config_tlb cfg;
193062306a36Sopenharmony_ci		void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0];
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci		r = -EFAULT;
193362306a36Sopenharmony_ci		if (copy_from_user(&cfg, user_ptr, sizeof(cfg)))
193462306a36Sopenharmony_ci			break;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg);
193762306a36Sopenharmony_ci		break;
193862306a36Sopenharmony_ci	}
193962306a36Sopenharmony_ci#endif
194062306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC
194162306a36Sopenharmony_ci	case KVM_CAP_IRQ_MPIC: {
194262306a36Sopenharmony_ci		struct fd f;
194362306a36Sopenharmony_ci		struct kvm_device *dev;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci		r = -EBADF;
194662306a36Sopenharmony_ci		f = fdget(cap->args[0]);
194762306a36Sopenharmony_ci		if (!f.file)
194862306a36Sopenharmony_ci			break;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci		r = -EPERM;
195162306a36Sopenharmony_ci		dev = kvm_device_from_filp(f.file);
195262306a36Sopenharmony_ci		if (dev)
195362306a36Sopenharmony_ci			r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		fdput(f);
195662306a36Sopenharmony_ci		break;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci#endif
195962306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS
196062306a36Sopenharmony_ci	case KVM_CAP_IRQ_XICS: {
196162306a36Sopenharmony_ci		struct fd f;
196262306a36Sopenharmony_ci		struct kvm_device *dev;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		r = -EBADF;
196562306a36Sopenharmony_ci		f = fdget(cap->args[0]);
196662306a36Sopenharmony_ci		if (!f.file)
196762306a36Sopenharmony_ci			break;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci		r = -EPERM;
197062306a36Sopenharmony_ci		dev = kvm_device_from_filp(f.file);
197162306a36Sopenharmony_ci		if (dev) {
197262306a36Sopenharmony_ci			if (xics_on_xive())
197362306a36Sopenharmony_ci				r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]);
197462306a36Sopenharmony_ci			else
197562306a36Sopenharmony_ci				r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]);
197662306a36Sopenharmony_ci		}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci		fdput(f);
197962306a36Sopenharmony_ci		break;
198062306a36Sopenharmony_ci	}
198162306a36Sopenharmony_ci#endif /* CONFIG_KVM_XICS */
198262306a36Sopenharmony_ci#ifdef CONFIG_KVM_XIVE
198362306a36Sopenharmony_ci	case KVM_CAP_PPC_IRQ_XIVE: {
198462306a36Sopenharmony_ci		struct fd f;
198562306a36Sopenharmony_ci		struct kvm_device *dev;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci		r = -EBADF;
198862306a36Sopenharmony_ci		f = fdget(cap->args[0]);
198962306a36Sopenharmony_ci		if (!f.file)
199062306a36Sopenharmony_ci			break;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		r = -ENXIO;
199362306a36Sopenharmony_ci		if (!xive_enabled())
199462306a36Sopenharmony_ci			break;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci		r = -EPERM;
199762306a36Sopenharmony_ci		dev = kvm_device_from_filp(f.file);
199862306a36Sopenharmony_ci		if (dev)
199962306a36Sopenharmony_ci			r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
200062306a36Sopenharmony_ci							    cap->args[1]);
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci		fdput(f);
200362306a36Sopenharmony_ci		break;
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci#endif /* CONFIG_KVM_XIVE */
200662306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
200762306a36Sopenharmony_ci	case KVM_CAP_PPC_FWNMI:
200862306a36Sopenharmony_ci		r = -EINVAL;
200962306a36Sopenharmony_ci		if (!is_kvmppc_hv_enabled(vcpu->kvm))
201062306a36Sopenharmony_ci			break;
201162306a36Sopenharmony_ci		r = 0;
201262306a36Sopenharmony_ci		vcpu->kvm->arch.fwnmi_enabled = true;
201362306a36Sopenharmony_ci		break;
201462306a36Sopenharmony_ci#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
201562306a36Sopenharmony_ci	default:
201662306a36Sopenharmony_ci		r = -EINVAL;
201762306a36Sopenharmony_ci		break;
201862306a36Sopenharmony_ci	}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	if (!r)
202162306a36Sopenharmony_ci		r = kvmppc_sanity_check(vcpu);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	return r;
202462306a36Sopenharmony_ci}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_cibool kvm_arch_intc_initialized(struct kvm *kvm)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC
202962306a36Sopenharmony_ci	if (kvm->arch.mpic)
203062306a36Sopenharmony_ci		return true;
203162306a36Sopenharmony_ci#endif
203262306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS
203362306a36Sopenharmony_ci	if (kvm->arch.xics || kvm->arch.xive)
203462306a36Sopenharmony_ci		return true;
203562306a36Sopenharmony_ci#endif
203662306a36Sopenharmony_ci	return false;
203762306a36Sopenharmony_ci}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
204062306a36Sopenharmony_ci                                    struct kvm_mp_state *mp_state)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	return -EINVAL;
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
204662306a36Sopenharmony_ci                                    struct kvm_mp_state *mp_state)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	return -EINVAL;
204962306a36Sopenharmony_ci}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp,
205262306a36Sopenharmony_ci			       unsigned int ioctl, unsigned long arg)
205362306a36Sopenharmony_ci{
205462306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
205562306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	if (ioctl == KVM_INTERRUPT) {
205862306a36Sopenharmony_ci		struct kvm_interrupt irq;
205962306a36Sopenharmony_ci		if (copy_from_user(&irq, argp, sizeof(irq)))
206062306a36Sopenharmony_ci			return -EFAULT;
206162306a36Sopenharmony_ci		return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_ci	return -ENOIOCTLCMD;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp,
206762306a36Sopenharmony_ci                         unsigned int ioctl, unsigned long arg)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
207062306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
207162306a36Sopenharmony_ci	long r;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	switch (ioctl) {
207462306a36Sopenharmony_ci	case KVM_ENABLE_CAP:
207562306a36Sopenharmony_ci	{
207662306a36Sopenharmony_ci		struct kvm_enable_cap cap;
207762306a36Sopenharmony_ci		r = -EFAULT;
207862306a36Sopenharmony_ci		if (copy_from_user(&cap, argp, sizeof(cap)))
207962306a36Sopenharmony_ci			goto out;
208062306a36Sopenharmony_ci		vcpu_load(vcpu);
208162306a36Sopenharmony_ci		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
208262306a36Sopenharmony_ci		vcpu_put(vcpu);
208362306a36Sopenharmony_ci		break;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	case KVM_SET_ONE_REG:
208762306a36Sopenharmony_ci	case KVM_GET_ONE_REG:
208862306a36Sopenharmony_ci	{
208962306a36Sopenharmony_ci		struct kvm_one_reg reg;
209062306a36Sopenharmony_ci		r = -EFAULT;
209162306a36Sopenharmony_ci		if (copy_from_user(&reg, argp, sizeof(reg)))
209262306a36Sopenharmony_ci			goto out;
209362306a36Sopenharmony_ci		if (ioctl == KVM_SET_ONE_REG)
209462306a36Sopenharmony_ci			r = kvm_vcpu_ioctl_set_one_reg(vcpu, &reg);
209562306a36Sopenharmony_ci		else
209662306a36Sopenharmony_ci			r = kvm_vcpu_ioctl_get_one_reg(vcpu, &reg);
209762306a36Sopenharmony_ci		break;
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
210162306a36Sopenharmony_ci	case KVM_DIRTY_TLB: {
210262306a36Sopenharmony_ci		struct kvm_dirty_tlb dirty;
210362306a36Sopenharmony_ci		r = -EFAULT;
210462306a36Sopenharmony_ci		if (copy_from_user(&dirty, argp, sizeof(dirty)))
210562306a36Sopenharmony_ci			goto out;
210662306a36Sopenharmony_ci		vcpu_load(vcpu);
210762306a36Sopenharmony_ci		r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
210862306a36Sopenharmony_ci		vcpu_put(vcpu);
210962306a36Sopenharmony_ci		break;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci#endif
211262306a36Sopenharmony_ci	default:
211362306a36Sopenharmony_ci		r = -EINVAL;
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ciout:
211762306a36Sopenharmony_ci	return r;
211862306a36Sopenharmony_ci}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	return VM_FAULT_SIGBUS;
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_cistatic int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
212662306a36Sopenharmony_ci{
212762306a36Sopenharmony_ci	u32 inst_nop = 0x60000000;
212862306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV
212962306a36Sopenharmony_ci	u32 inst_sc1 = 0x44000022;
213062306a36Sopenharmony_ci	pvinfo->hcall[0] = cpu_to_be32(inst_sc1);
213162306a36Sopenharmony_ci	pvinfo->hcall[1] = cpu_to_be32(inst_nop);
213262306a36Sopenharmony_ci	pvinfo->hcall[2] = cpu_to_be32(inst_nop);
213362306a36Sopenharmony_ci	pvinfo->hcall[3] = cpu_to_be32(inst_nop);
213462306a36Sopenharmony_ci#else
213562306a36Sopenharmony_ci	u32 inst_lis = 0x3c000000;
213662306a36Sopenharmony_ci	u32 inst_ori = 0x60000000;
213762306a36Sopenharmony_ci	u32 inst_sc = 0x44000002;
213862306a36Sopenharmony_ci	u32 inst_imm_mask = 0xffff;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	/*
214162306a36Sopenharmony_ci	 * The hypercall to get into KVM from within guest context is as
214262306a36Sopenharmony_ci	 * follows:
214362306a36Sopenharmony_ci	 *
214462306a36Sopenharmony_ci	 *    lis r0, r0, KVM_SC_MAGIC_R0@h
214562306a36Sopenharmony_ci	 *    ori r0, KVM_SC_MAGIC_R0@l
214662306a36Sopenharmony_ci	 *    sc
214762306a36Sopenharmony_ci	 *    nop
214862306a36Sopenharmony_ci	 */
214962306a36Sopenharmony_ci	pvinfo->hcall[0] = cpu_to_be32(inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask));
215062306a36Sopenharmony_ci	pvinfo->hcall[1] = cpu_to_be32(inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask));
215162306a36Sopenharmony_ci	pvinfo->hcall[2] = cpu_to_be32(inst_sc);
215262306a36Sopenharmony_ci	pvinfo->hcall[3] = cpu_to_be32(inst_nop);
215362306a36Sopenharmony_ci#endif
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	return 0;
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_cibool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
216162306a36Sopenharmony_ci{
216262306a36Sopenharmony_ci	int ret = 0;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC
216562306a36Sopenharmony_ci	ret = ret || (kvm->arch.mpic != NULL);
216662306a36Sopenharmony_ci#endif
216762306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS
216862306a36Sopenharmony_ci	ret = ret || (kvm->arch.xics != NULL);
216962306a36Sopenharmony_ci	ret = ret || (kvm->arch.xive != NULL);
217062306a36Sopenharmony_ci#endif
217162306a36Sopenharmony_ci	smp_rmb();
217262306a36Sopenharmony_ci	return ret;
217362306a36Sopenharmony_ci}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ciint kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
217662306a36Sopenharmony_ci			  bool line_status)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	if (!kvm_arch_irqchip_in_kernel(kvm))
217962306a36Sopenharmony_ci		return -ENXIO;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
218262306a36Sopenharmony_ci					irq_event->irq, irq_event->level,
218362306a36Sopenharmony_ci					line_status);
218462306a36Sopenharmony_ci	return 0;
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ciint kvm_vm_ioctl_enable_cap(struct kvm *kvm,
218962306a36Sopenharmony_ci			    struct kvm_enable_cap *cap)
219062306a36Sopenharmony_ci{
219162306a36Sopenharmony_ci	int r;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	if (cap->flags)
219462306a36Sopenharmony_ci		return -EINVAL;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	switch (cap->cap) {
219762306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
219862306a36Sopenharmony_ci	case KVM_CAP_PPC_ENABLE_HCALL: {
219962306a36Sopenharmony_ci		unsigned long hcall = cap->args[0];
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		r = -EINVAL;
220262306a36Sopenharmony_ci		if (hcall > MAX_HCALL_OPCODE || (hcall & 3) ||
220362306a36Sopenharmony_ci		    cap->args[1] > 1)
220462306a36Sopenharmony_ci			break;
220562306a36Sopenharmony_ci		if (!kvmppc_book3s_hcall_implemented(kvm, hcall))
220662306a36Sopenharmony_ci			break;
220762306a36Sopenharmony_ci		if (cap->args[1])
220862306a36Sopenharmony_ci			set_bit(hcall / 4, kvm->arch.enabled_hcalls);
220962306a36Sopenharmony_ci		else
221062306a36Sopenharmony_ci			clear_bit(hcall / 4, kvm->arch.enabled_hcalls);
221162306a36Sopenharmony_ci		r = 0;
221262306a36Sopenharmony_ci		break;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci	case KVM_CAP_PPC_SMT: {
221562306a36Sopenharmony_ci		unsigned long mode = cap->args[0];
221662306a36Sopenharmony_ci		unsigned long flags = cap->args[1];
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci		r = -EINVAL;
221962306a36Sopenharmony_ci		if (kvm->arch.kvm_ops->set_smt_mode)
222062306a36Sopenharmony_ci			r = kvm->arch.kvm_ops->set_smt_mode(kvm, mode, flags);
222162306a36Sopenharmony_ci		break;
222262306a36Sopenharmony_ci	}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	case KVM_CAP_PPC_NESTED_HV:
222562306a36Sopenharmony_ci		r = -EINVAL;
222662306a36Sopenharmony_ci		if (!is_kvmppc_hv_enabled(kvm) ||
222762306a36Sopenharmony_ci		    !kvm->arch.kvm_ops->enable_nested)
222862306a36Sopenharmony_ci			break;
222962306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->enable_nested(kvm);
223062306a36Sopenharmony_ci		break;
223162306a36Sopenharmony_ci#endif
223262306a36Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
223362306a36Sopenharmony_ci	case KVM_CAP_PPC_SECURE_GUEST:
223462306a36Sopenharmony_ci		r = -EINVAL;
223562306a36Sopenharmony_ci		if (!is_kvmppc_hv_enabled(kvm) || !kvm->arch.kvm_ops->enable_svm)
223662306a36Sopenharmony_ci			break;
223762306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->enable_svm(kvm);
223862306a36Sopenharmony_ci		break;
223962306a36Sopenharmony_ci	case KVM_CAP_PPC_DAWR1:
224062306a36Sopenharmony_ci		r = -EINVAL;
224162306a36Sopenharmony_ci		if (!is_kvmppc_hv_enabled(kvm) || !kvm->arch.kvm_ops->enable_dawr1)
224262306a36Sopenharmony_ci			break;
224362306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->enable_dawr1(kvm);
224462306a36Sopenharmony_ci		break;
224562306a36Sopenharmony_ci#endif
224662306a36Sopenharmony_ci	default:
224762306a36Sopenharmony_ci		r = -EINVAL;
224862306a36Sopenharmony_ci		break;
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	return r;
225262306a36Sopenharmony_ci}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
225562306a36Sopenharmony_ci/*
225662306a36Sopenharmony_ci * These functions check whether the underlying hardware is safe
225762306a36Sopenharmony_ci * against attacks based on observing the effects of speculatively
225862306a36Sopenharmony_ci * executed instructions, and whether it supplies instructions for
225962306a36Sopenharmony_ci * use in workarounds.  The information comes from firmware, either
226062306a36Sopenharmony_ci * via the device tree on powernv platforms or from an hcall on
226162306a36Sopenharmony_ci * pseries platforms.
226262306a36Sopenharmony_ci */
226362306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES
226462306a36Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp)
226562306a36Sopenharmony_ci{
226662306a36Sopenharmony_ci	struct h_cpu_char_result c;
226762306a36Sopenharmony_ci	unsigned long rc;
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	if (!machine_is(pseries))
227062306a36Sopenharmony_ci		return -ENOTTY;
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	rc = plpar_get_cpu_characteristics(&c);
227362306a36Sopenharmony_ci	if (rc == H_SUCCESS) {
227462306a36Sopenharmony_ci		cp->character = c.character;
227562306a36Sopenharmony_ci		cp->behaviour = c.behaviour;
227662306a36Sopenharmony_ci		cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 |
227762306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED |
227862306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 |
227962306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 |
228062306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV |
228162306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_BR_HINT_HONOURED |
228262306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF |
228362306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS |
228462306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST;
228562306a36Sopenharmony_ci		cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY |
228662306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR |
228762306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR |
228862306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci	return 0;
229162306a36Sopenharmony_ci}
229262306a36Sopenharmony_ci#else
229362306a36Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp)
229462306a36Sopenharmony_ci{
229562306a36Sopenharmony_ci	return -ENOTTY;
229662306a36Sopenharmony_ci}
229762306a36Sopenharmony_ci#endif
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_cistatic inline bool have_fw_feat(struct device_node *fw_features,
230062306a36Sopenharmony_ci				const char *state, const char *name)
230162306a36Sopenharmony_ci{
230262306a36Sopenharmony_ci	struct device_node *np;
230362306a36Sopenharmony_ci	bool r = false;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	np = of_get_child_by_name(fw_features, name);
230662306a36Sopenharmony_ci	if (np) {
230762306a36Sopenharmony_ci		r = of_property_read_bool(np, state);
230862306a36Sopenharmony_ci		of_node_put(np);
230962306a36Sopenharmony_ci	}
231062306a36Sopenharmony_ci	return r;
231162306a36Sopenharmony_ci}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_cistatic int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp)
231462306a36Sopenharmony_ci{
231562306a36Sopenharmony_ci	struct device_node *np, *fw_features;
231662306a36Sopenharmony_ci	int r;
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	memset(cp, 0, sizeof(*cp));
231962306a36Sopenharmony_ci	r = pseries_get_cpu_char(cp);
232062306a36Sopenharmony_ci	if (r != -ENOTTY)
232162306a36Sopenharmony_ci		return r;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	np = of_find_node_by_name(NULL, "ibm,opal");
232462306a36Sopenharmony_ci	if (np) {
232562306a36Sopenharmony_ci		fw_features = of_get_child_by_name(np, "fw-features");
232662306a36Sopenharmony_ci		of_node_put(np);
232762306a36Sopenharmony_ci		if (!fw_features)
232862306a36Sopenharmony_ci			return 0;
232962306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
233062306a36Sopenharmony_ci				 "inst-spec-barrier-ori31,31,0"))
233162306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31;
233262306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
233362306a36Sopenharmony_ci				 "fw-bcctrl-serialized"))
233462306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED;
233562306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
233662306a36Sopenharmony_ci				 "inst-l1d-flush-ori30,30,0"))
233762306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30;
233862306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
233962306a36Sopenharmony_ci				 "inst-l1d-flush-trig2"))
234062306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2;
234162306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
234262306a36Sopenharmony_ci				 "fw-l1d-thread-split"))
234362306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV;
234462306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
234562306a36Sopenharmony_ci				 "fw-count-cache-disabled"))
234662306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS;
234762306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
234862306a36Sopenharmony_ci				 "fw-count-cache-flush-bcctr2,0,0"))
234962306a36Sopenharmony_ci			cp->character |= KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST;
235062306a36Sopenharmony_ci		cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 |
235162306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED |
235262306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 |
235362306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 |
235462306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV |
235562306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS |
235662306a36Sopenharmony_ci			KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
235962306a36Sopenharmony_ci				 "speculation-policy-favor-security"))
236062306a36Sopenharmony_ci			cp->behaviour |= KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY;
236162306a36Sopenharmony_ci		if (!have_fw_feat(fw_features, "disabled",
236262306a36Sopenharmony_ci				  "needs-l1d-flush-msr-pr-0-to-1"))
236362306a36Sopenharmony_ci			cp->behaviour |= KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR;
236462306a36Sopenharmony_ci		if (!have_fw_feat(fw_features, "disabled",
236562306a36Sopenharmony_ci				  "needs-spec-barrier-for-bound-checks"))
236662306a36Sopenharmony_ci			cp->behaviour |= KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR;
236762306a36Sopenharmony_ci		if (have_fw_feat(fw_features, "enabled",
236862306a36Sopenharmony_ci				 "needs-count-cache-flush-on-context-switch"))
236962306a36Sopenharmony_ci			cp->behaviour |= KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE;
237062306a36Sopenharmony_ci		cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY |
237162306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR |
237262306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR |
237362306a36Sopenharmony_ci			KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci		of_node_put(fw_features);
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	return 0;
237962306a36Sopenharmony_ci}
238062306a36Sopenharmony_ci#endif
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ciint kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	struct kvm *kvm __maybe_unused = filp->private_data;
238562306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
238662306a36Sopenharmony_ci	int r;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	switch (ioctl) {
238962306a36Sopenharmony_ci	case KVM_PPC_GET_PVINFO: {
239062306a36Sopenharmony_ci		struct kvm_ppc_pvinfo pvinfo;
239162306a36Sopenharmony_ci		memset(&pvinfo, 0, sizeof(pvinfo));
239262306a36Sopenharmony_ci		r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
239362306a36Sopenharmony_ci		if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
239462306a36Sopenharmony_ci			r = -EFAULT;
239562306a36Sopenharmony_ci			goto out;
239662306a36Sopenharmony_ci		}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		break;
239962306a36Sopenharmony_ci	}
240062306a36Sopenharmony_ci#ifdef CONFIG_SPAPR_TCE_IOMMU
240162306a36Sopenharmony_ci	case KVM_CREATE_SPAPR_TCE_64: {
240262306a36Sopenharmony_ci		struct kvm_create_spapr_tce_64 create_tce_64;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		r = -EFAULT;
240562306a36Sopenharmony_ci		if (copy_from_user(&create_tce_64, argp, sizeof(create_tce_64)))
240662306a36Sopenharmony_ci			goto out;
240762306a36Sopenharmony_ci		if (create_tce_64.flags) {
240862306a36Sopenharmony_ci			r = -EINVAL;
240962306a36Sopenharmony_ci			goto out;
241062306a36Sopenharmony_ci		}
241162306a36Sopenharmony_ci		r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64);
241262306a36Sopenharmony_ci		goto out;
241362306a36Sopenharmony_ci	}
241462306a36Sopenharmony_ci	case KVM_CREATE_SPAPR_TCE: {
241562306a36Sopenharmony_ci		struct kvm_create_spapr_tce create_tce;
241662306a36Sopenharmony_ci		struct kvm_create_spapr_tce_64 create_tce_64;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci		r = -EFAULT;
241962306a36Sopenharmony_ci		if (copy_from_user(&create_tce, argp, sizeof(create_tce)))
242062306a36Sopenharmony_ci			goto out;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci		create_tce_64.liobn = create_tce.liobn;
242362306a36Sopenharmony_ci		create_tce_64.page_shift = IOMMU_PAGE_SHIFT_4K;
242462306a36Sopenharmony_ci		create_tce_64.offset = 0;
242562306a36Sopenharmony_ci		create_tce_64.size = create_tce.window_size >>
242662306a36Sopenharmony_ci				IOMMU_PAGE_SHIFT_4K;
242762306a36Sopenharmony_ci		create_tce_64.flags = 0;
242862306a36Sopenharmony_ci		r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64);
242962306a36Sopenharmony_ci		goto out;
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci#endif
243262306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
243362306a36Sopenharmony_ci	case KVM_PPC_GET_SMMU_INFO: {
243462306a36Sopenharmony_ci		struct kvm_ppc_smmu_info info;
243562306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci		memset(&info, 0, sizeof(info));
243862306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->get_smmu_info(kvm, &info);
243962306a36Sopenharmony_ci		if (r >= 0 && copy_to_user(argp, &info, sizeof(info)))
244062306a36Sopenharmony_ci			r = -EFAULT;
244162306a36Sopenharmony_ci		break;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci	case KVM_PPC_RTAS_DEFINE_TOKEN: {
244462306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci		r = kvm_vm_ioctl_rtas_define_token(kvm, argp);
244762306a36Sopenharmony_ci		break;
244862306a36Sopenharmony_ci	}
244962306a36Sopenharmony_ci	case KVM_PPC_CONFIGURE_V3_MMU: {
245062306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
245162306a36Sopenharmony_ci		struct kvm_ppc_mmuv3_cfg cfg;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci		r = -EINVAL;
245462306a36Sopenharmony_ci		if (!kvm->arch.kvm_ops->configure_mmu)
245562306a36Sopenharmony_ci			goto out;
245662306a36Sopenharmony_ci		r = -EFAULT;
245762306a36Sopenharmony_ci		if (copy_from_user(&cfg, argp, sizeof(cfg)))
245862306a36Sopenharmony_ci			goto out;
245962306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->configure_mmu(kvm, &cfg);
246062306a36Sopenharmony_ci		break;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	case KVM_PPC_GET_RMMU_INFO: {
246362306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
246462306a36Sopenharmony_ci		struct kvm_ppc_rmmu_info info;
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci		r = -EINVAL;
246762306a36Sopenharmony_ci		if (!kvm->arch.kvm_ops->get_rmmu_info)
246862306a36Sopenharmony_ci			goto out;
246962306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->get_rmmu_info(kvm, &info);
247062306a36Sopenharmony_ci		if (r >= 0 && copy_to_user(argp, &info, sizeof(info)))
247162306a36Sopenharmony_ci			r = -EFAULT;
247262306a36Sopenharmony_ci		break;
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci	case KVM_PPC_GET_CPU_CHAR: {
247562306a36Sopenharmony_ci		struct kvm_ppc_cpu_char cpuchar;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci		r = kvmppc_get_cpu_char(&cpuchar);
247862306a36Sopenharmony_ci		if (r >= 0 && copy_to_user(argp, &cpuchar, sizeof(cpuchar)))
247962306a36Sopenharmony_ci			r = -EFAULT;
248062306a36Sopenharmony_ci		break;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci	case KVM_PPC_SVM_OFF: {
248362306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci		r = 0;
248662306a36Sopenharmony_ci		if (!kvm->arch.kvm_ops->svm_off)
248762306a36Sopenharmony_ci			goto out;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->svm_off(kvm);
249062306a36Sopenharmony_ci		break;
249162306a36Sopenharmony_ci	}
249262306a36Sopenharmony_ci	default: {
249362306a36Sopenharmony_ci		struct kvm *kvm = filp->private_data;
249462306a36Sopenharmony_ci		r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
249562306a36Sopenharmony_ci	}
249662306a36Sopenharmony_ci#else /* CONFIG_PPC_BOOK3S_64 */
249762306a36Sopenharmony_ci	default:
249862306a36Sopenharmony_ci		r = -ENOTTY;
249962306a36Sopenharmony_ci#endif
250062306a36Sopenharmony_ci	}
250162306a36Sopenharmony_ciout:
250262306a36Sopenharmony_ci	return r;
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic DEFINE_IDA(lpid_inuse);
250662306a36Sopenharmony_cistatic unsigned long nr_lpids;
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_cilong kvmppc_alloc_lpid(void)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	int lpid;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	/* The host LPID must always be 0 (allocation starts at 1) */
251362306a36Sopenharmony_ci	lpid = ida_alloc_range(&lpid_inuse, 1, nr_lpids - 1, GFP_KERNEL);
251462306a36Sopenharmony_ci	if (lpid < 0) {
251562306a36Sopenharmony_ci		if (lpid == -ENOMEM)
251662306a36Sopenharmony_ci			pr_err("%s: Out of memory\n", __func__);
251762306a36Sopenharmony_ci		else
251862306a36Sopenharmony_ci			pr_err("%s: No LPIDs free\n", __func__);
251962306a36Sopenharmony_ci		return -ENOMEM;
252062306a36Sopenharmony_ci	}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	return lpid;
252362306a36Sopenharmony_ci}
252462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_alloc_lpid);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_civoid kvmppc_free_lpid(long lpid)
252762306a36Sopenharmony_ci{
252862306a36Sopenharmony_ci	ida_free(&lpid_inuse, lpid);
252962306a36Sopenharmony_ci}
253062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_free_lpid);
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci/* nr_lpids_param includes the host LPID */
253362306a36Sopenharmony_civoid kvmppc_init_lpid(unsigned long nr_lpids_param)
253462306a36Sopenharmony_ci{
253562306a36Sopenharmony_ci	nr_lpids = nr_lpids_param;
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_init_lpid);
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ppc_instr);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_civoid kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	if (vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs)
254462306a36Sopenharmony_ci		vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs(vcpu, debugfs_dentry);
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ciint kvm_arch_create_vm_debugfs(struct kvm *kvm)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	if (kvm->arch.kvm_ops->create_vm_debugfs)
255062306a36Sopenharmony_ci		kvm->arch.kvm_ops->create_vm_debugfs(kvm);
255162306a36Sopenharmony_ci	return 0;
255262306a36Sopenharmony_ci}
2553