|  | // SPDX-License-Identifier: GPL-2.0-only | 
|  | /* | 
|  | * Copyright 2023 Jordan Niethe, IBM Corp. <jniethe5@gmail.com> | 
|  | * | 
|  | * Authors: | 
|  | *    Jordan Niethe <jniethe5@gmail.com> | 
|  | * | 
|  | * Description: KVM functions specific to running on Book 3S | 
|  | * processors as a NESTEDv2 guest. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "linux/blk-mq.h" | 
|  | #include "linux/console.h" | 
|  | #include "linux/gfp_types.h" | 
|  | #include "linux/signal.h" | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/kvm_host.h> | 
|  | #include <linux/pgtable.h> | 
|  |  | 
|  | #include <asm/kvm_ppc.h> | 
|  | #include <asm/kvm_book3s.h> | 
|  | #include <asm/hvcall.h> | 
|  | #include <asm/pgalloc.h> | 
|  | #include <asm/reg.h> | 
|  | #include <asm/plpar_wrappers.h> | 
|  | #include <asm/guest-state-buffer.h> | 
|  | #include "trace_hv.h" | 
|  |  | 
|  | struct static_key_false __kvmhv_is_nestedv2 __read_mostly; | 
|  | EXPORT_SYMBOL_GPL(__kvmhv_is_nestedv2); | 
|  |  | 
|  |  | 
|  | static size_t | 
|  | gs_msg_ops_kvmhv_nestedv2_config_get_size(struct kvmppc_gs_msg *gsm) | 
|  | { | 
|  | u16 ids[] = { | 
|  | KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE, | 
|  | KVMPPC_GSID_RUN_INPUT, | 
|  | KVMPPC_GSID_RUN_OUTPUT, | 
|  |  | 
|  | }; | 
|  | size_t size = 0; | 
|  |  | 
|  | for (int i = 0; i < ARRAY_SIZE(ids); i++) | 
|  | size += kvmppc_gse_total_size(kvmppc_gsid_size(ids[i])); | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static int | 
|  | gs_msg_ops_kvmhv_nestedv2_config_fill_info(struct kvmppc_gs_buff *gsb, | 
|  | struct kvmppc_gs_msg *gsm) | 
|  | { | 
|  | struct kvmhv_nestedv2_config *cfg; | 
|  | int rc; | 
|  |  | 
|  | cfg = gsm->data; | 
|  |  | 
|  | if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE)) { | 
|  | rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE, | 
|  | cfg->vcpu_run_output_size); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_INPUT)) { | 
|  | rc = kvmppc_gse_put_buff_info(gsb, KVMPPC_GSID_RUN_INPUT, | 
|  | cfg->vcpu_run_input_cfg); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_OUTPUT)) { | 
|  | rc = kvmppc_gse_put_buff_info(gsb, KVMPPC_GSID_RUN_OUTPUT, | 
|  | cfg->vcpu_run_output_cfg); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | gs_msg_ops_kvmhv_nestedv2_config_refresh_info(struct kvmppc_gs_msg *gsm, | 
|  | struct kvmppc_gs_buff *gsb) | 
|  | { | 
|  | struct kvmhv_nestedv2_config *cfg; | 
|  | struct kvmppc_gs_parser gsp = { 0 }; | 
|  | struct kvmppc_gs_elem *gse; | 
|  | int rc; | 
|  |  | 
|  | cfg = gsm->data; | 
|  |  | 
|  | rc = kvmppc_gse_parse(&gsp, gsb); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  |  | 
|  | gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE); | 
|  | if (gse) | 
|  | cfg->vcpu_run_output_size = kvmppc_gse_get_u64(gse); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct kvmppc_gs_msg_ops config_msg_ops = { | 
|  | .get_size = gs_msg_ops_kvmhv_nestedv2_config_get_size, | 
|  | .fill_info = gs_msg_ops_kvmhv_nestedv2_config_fill_info, | 
|  | .refresh_info = gs_msg_ops_kvmhv_nestedv2_config_refresh_info, | 
|  | }; | 
|  |  | 
|  | static size_t gs_msg_ops_vcpu_get_size(struct kvmppc_gs_msg *gsm) | 
|  | { | 
|  | struct kvmppc_gs_bitmap gsbm = { 0 }; | 
|  | size_t size = 0; | 
|  | u16 iden; | 
|  |  | 
|  | kvmppc_gsbm_fill(&gsbm); | 
|  | kvmppc_gsbm_for_each(&gsbm, iden) | 
|  | { | 
|  | switch (iden) { | 
|  | case KVMPPC_GSID_HOST_STATE_SIZE: | 
|  | case KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE: | 
|  | case KVMPPC_GSID_PARTITION_TABLE: | 
|  | case KVMPPC_GSID_PROCESS_TABLE: | 
|  | case KVMPPC_GSID_RUN_INPUT: | 
|  | case KVMPPC_GSID_RUN_OUTPUT: | 
|  | break; | 
|  | default: | 
|  | size += kvmppc_gse_total_size(kvmppc_gsid_size(iden)); | 
|  | } | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, | 
|  | struct kvmppc_gs_msg *gsm) | 
|  | { | 
|  | struct kvm_vcpu *vcpu; | 
|  | vector128 v; | 
|  | int rc, i; | 
|  | u16 iden; | 
|  | u32 arch_compat = 0; | 
|  |  | 
|  | vcpu = gsm->data; | 
|  |  | 
|  | kvmppc_gsm_for_each(gsm, iden) | 
|  | { | 
|  | rc = 0; | 
|  |  | 
|  | if ((gsm->flags & KVMPPC_GS_FLAGS_WIDE) != | 
|  | (kvmppc_gsid_flags(iden) & KVMPPC_GS_FLAGS_WIDE)) | 
|  | continue; | 
|  |  | 
|  | switch (iden) { | 
|  | case KVMPPC_GSID_DSCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dscr); | 
|  | break; | 
|  | case KVMPPC_GSID_MMCRA: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.mmcra); | 
|  | break; | 
|  | case KVMPPC_GSID_HFSCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hfscr); | 
|  | break; | 
|  | case KVMPPC_GSID_PURR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.purr); | 
|  | break; | 
|  | case KVMPPC_GSID_SPURR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.spurr); | 
|  | break; | 
|  | case KVMPPC_GSID_AMR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.amr); | 
|  | break; | 
|  | case KVMPPC_GSID_UAMOR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.uamor); | 
|  | break; | 
|  | case KVMPPC_GSID_SIAR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.siar); | 
|  | break; | 
|  | case KVMPPC_GSID_SDAR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.sdar); | 
|  | break; | 
|  | case KVMPPC_GSID_IAMR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.iamr); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWR0: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dawr0); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWR1: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dawr1); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWRX0: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx0); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWRX1: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx1); | 
|  | break; | 
|  | case KVMPPC_GSID_DEXCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dexcr); | 
|  | break; | 
|  | case KVMPPC_GSID_HASHKEYR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashkeyr); | 
|  | break; | 
|  | case KVMPPC_GSID_HASHPKEYR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashpkeyr); | 
|  | break; | 
|  | case KVMPPC_GSID_CIABR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ciabr); | 
|  | break; | 
|  | case KVMPPC_GSID_WORT: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.wort); | 
|  | break; | 
|  | case KVMPPC_GSID_PPR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ppr); | 
|  | break; | 
|  | case KVMPPC_GSID_PSPB: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pspb); | 
|  | break; | 
|  | case KVMPPC_GSID_TAR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.tar); | 
|  | break; | 
|  | case KVMPPC_GSID_FSCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.fscr); | 
|  | break; | 
|  | case KVMPPC_GSID_EBBHR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ebbhr); | 
|  | break; | 
|  | case KVMPPC_GSID_EBBRR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ebbrr); | 
|  | break; | 
|  | case KVMPPC_GSID_BESCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.bescr); | 
|  | break; | 
|  | case KVMPPC_GSID_IC: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ic); | 
|  | break; | 
|  | case KVMPPC_GSID_CTRL: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ctrl); | 
|  | break; | 
|  | case KVMPPC_GSID_PIDR: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pid); | 
|  | break; | 
|  | case KVMPPC_GSID_AMOR: { | 
|  | u64 amor = ~0; | 
|  |  | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, amor); | 
|  | break; | 
|  | } | 
|  | case KVMPPC_GSID_VRSAVE: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.vrsave); | 
|  | break; | 
|  | case KVMPPC_GSID_MMCR(0)... KVMPPC_GSID_MMCR(3): | 
|  | i = iden - KVMPPC_GSID_MMCR(0); | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.mmcr[i]); | 
|  | break; | 
|  | case KVMPPC_GSID_SIER(0)... KVMPPC_GSID_SIER(2): | 
|  | i = iden - KVMPPC_GSID_SIER(0); | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.sier[i]); | 
|  | break; | 
|  | case KVMPPC_GSID_PMC(0)... KVMPPC_GSID_PMC(5): | 
|  | i = iden - KVMPPC_GSID_PMC(0); | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pmc[i]); | 
|  | break; | 
|  | case KVMPPC_GSID_GPR(0)... KVMPPC_GSID_GPR(31): | 
|  | i = iden - KVMPPC_GSID_GPR(0); | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.regs.gpr[i]); | 
|  | break; | 
|  | case KVMPPC_GSID_CR: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.regs.ccr); | 
|  | break; | 
|  | case KVMPPC_GSID_XER: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.xer); | 
|  | break; | 
|  | case KVMPPC_GSID_CTR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.ctr); | 
|  | break; | 
|  | case KVMPPC_GSID_LR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.regs.link); | 
|  | break; | 
|  | case KVMPPC_GSID_NIA: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.nip); | 
|  | break; | 
|  | case KVMPPC_GSID_SRR0: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.srr0); | 
|  | break; | 
|  | case KVMPPC_GSID_SRR1: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.srr1); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG0: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.sprg0); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG1: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.sprg1); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG2: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.sprg2); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG3: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.sprg3); | 
|  | break; | 
|  | case KVMPPC_GSID_DAR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.dar); | 
|  | break; | 
|  | case KVMPPC_GSID_DSISR: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, | 
|  | vcpu->arch.shregs.dsisr); | 
|  | break; | 
|  | case KVMPPC_GSID_MSR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.shregs.msr); | 
|  | break; | 
|  | case KVMPPC_GSID_VTB: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.vcore->vtb); | 
|  | break; | 
|  | case KVMPPC_GSID_DPDES: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.vcore->dpdes); | 
|  | break; | 
|  | case KVMPPC_GSID_LPCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.vcore->lpcr); | 
|  | break; | 
|  | case KVMPPC_GSID_TB_OFFSET: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, | 
|  | vcpu->arch.vcore->tb_offset); | 
|  | break; | 
|  | case KVMPPC_GSID_FPSCR: | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.fp.fpscr); | 
|  | break; | 
|  | case KVMPPC_GSID_VSRS(0)... KVMPPC_GSID_VSRS(31): | 
|  | i = iden - KVMPPC_GSID_VSRS(0); | 
|  | memcpy(&v, &vcpu->arch.fp.fpr[i], | 
|  | sizeof(vcpu->arch.fp.fpr[i])); | 
|  | rc = kvmppc_gse_put_vector128(gsb, iden, &v); | 
|  | break; | 
|  | #ifdef CONFIG_VSX | 
|  | case KVMPPC_GSID_VSCR: | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, | 
|  | vcpu->arch.vr.vscr.u[3]); | 
|  | break; | 
|  | case KVMPPC_GSID_VSRS(32)... KVMPPC_GSID_VSRS(63): | 
|  | i = iden - KVMPPC_GSID_VSRS(32); | 
|  | rc = kvmppc_gse_put_vector128(gsb, iden, | 
|  | &vcpu->arch.vr.vr[i]); | 
|  | break; | 
|  | #endif | 
|  | case KVMPPC_GSID_DEC_EXPIRY_TB: { | 
|  | u64 dw; | 
|  |  | 
|  | dw = vcpu->arch.dec_expires - | 
|  | vcpu->arch.vcore->tb_offset; | 
|  | rc = kvmppc_gse_put_u64(gsb, iden, dw); | 
|  | break; | 
|  | } | 
|  | case KVMPPC_GSID_LOGICAL_PVR: | 
|  | /* | 
|  | * Though 'arch_compat == 0' would mean the default | 
|  | * compatibility, arch_compat, being a Guest Wide | 
|  | * Element, cannot be filled with a value of 0 in GSB | 
|  | * as this would result into a kernel trap. | 
|  | * Hence, when `arch_compat == 0`, arch_compat should | 
|  | * default to L1's PVR. | 
|  | */ | 
|  | if (!vcpu->arch.vcore->arch_compat) { | 
|  | if (cpu_has_feature(CPU_FTR_ARCH_31)) | 
|  | arch_compat = PVR_ARCH_31; | 
|  | else if (cpu_has_feature(CPU_FTR_ARCH_300)) | 
|  | arch_compat = PVR_ARCH_300; | 
|  | } else { | 
|  | arch_compat = vcpu->arch.vcore->arch_compat; | 
|  | } | 
|  | rc = kvmppc_gse_put_u32(gsb, iden, arch_compat); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (rc < 0) | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gs_msg_ops_vcpu_refresh_info(struct kvmppc_gs_msg *gsm, | 
|  | struct kvmppc_gs_buff *gsb) | 
|  | { | 
|  | struct kvmppc_gs_parser gsp = { 0 }; | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_bitmap *valids; | 
|  | struct kvm_vcpu *vcpu; | 
|  | struct kvmppc_gs_elem *gse; | 
|  | vector128 v; | 
|  | int rc, i; | 
|  | u16 iden; | 
|  |  | 
|  | vcpu = gsm->data; | 
|  |  | 
|  | rc = kvmppc_gse_parse(&gsp, gsb); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | valids = &io->valids; | 
|  |  | 
|  | kvmppc_gsp_for_each(&gsp, iden, gse) | 
|  | { | 
|  | switch (iden) { | 
|  | case KVMPPC_GSID_DSCR: | 
|  | vcpu->arch.dscr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_MMCRA: | 
|  | vcpu->arch.mmcra = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_HFSCR: | 
|  | vcpu->arch.hfscr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_PURR: | 
|  | vcpu->arch.purr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SPURR: | 
|  | vcpu->arch.spurr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_AMR: | 
|  | vcpu->arch.amr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_UAMOR: | 
|  | vcpu->arch.uamor = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SIAR: | 
|  | vcpu->arch.siar = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SDAR: | 
|  | vcpu->arch.sdar = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_IAMR: | 
|  | vcpu->arch.iamr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWR0: | 
|  | vcpu->arch.dawr0 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWR1: | 
|  | vcpu->arch.dawr1 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWRX0: | 
|  | vcpu->arch.dawrx0 = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DAWRX1: | 
|  | vcpu->arch.dawrx1 = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DEXCR: | 
|  | vcpu->arch.dexcr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_HASHKEYR: | 
|  | vcpu->arch.hashkeyr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_HASHPKEYR: | 
|  | vcpu->arch.hashpkeyr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_CIABR: | 
|  | vcpu->arch.ciabr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_WORT: | 
|  | vcpu->arch.wort = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_PPR: | 
|  | vcpu->arch.ppr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_PSPB: | 
|  | vcpu->arch.pspb = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_TAR: | 
|  | vcpu->arch.tar = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_FSCR: | 
|  | vcpu->arch.fscr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_EBBHR: | 
|  | vcpu->arch.ebbhr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_EBBRR: | 
|  | vcpu->arch.ebbrr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_BESCR: | 
|  | vcpu->arch.bescr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_IC: | 
|  | vcpu->arch.ic = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_CTRL: | 
|  | vcpu->arch.ctrl = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_PIDR: | 
|  | vcpu->arch.pid = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_AMOR: | 
|  | break; | 
|  | case KVMPPC_GSID_VRSAVE: | 
|  | vcpu->arch.vrsave = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_MMCR(0)... KVMPPC_GSID_MMCR(3): | 
|  | i = iden - KVMPPC_GSID_MMCR(0); | 
|  | vcpu->arch.mmcr[i] = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SIER(0)... KVMPPC_GSID_SIER(2): | 
|  | i = iden - KVMPPC_GSID_SIER(0); | 
|  | vcpu->arch.sier[i] = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_PMC(0)... KVMPPC_GSID_PMC(5): | 
|  | i = iden - KVMPPC_GSID_PMC(0); | 
|  | vcpu->arch.pmc[i] = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_GPR(0)... KVMPPC_GSID_GPR(31): | 
|  | i = iden - KVMPPC_GSID_GPR(0); | 
|  | vcpu->arch.regs.gpr[i] = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_CR: | 
|  | vcpu->arch.regs.ccr = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_XER: | 
|  | vcpu->arch.regs.xer = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_CTR: | 
|  | vcpu->arch.regs.ctr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_LR: | 
|  | vcpu->arch.regs.link = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_NIA: | 
|  | vcpu->arch.regs.nip = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SRR0: | 
|  | vcpu->arch.shregs.srr0 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SRR1: | 
|  | vcpu->arch.shregs.srr1 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG0: | 
|  | vcpu->arch.shregs.sprg0 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG1: | 
|  | vcpu->arch.shregs.sprg1 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG2: | 
|  | vcpu->arch.shregs.sprg2 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_SPRG3: | 
|  | vcpu->arch.shregs.sprg3 = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DAR: | 
|  | vcpu->arch.shregs.dar = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DSISR: | 
|  | vcpu->arch.shregs.dsisr = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_MSR: | 
|  | vcpu->arch.shregs.msr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_VTB: | 
|  | vcpu->arch.vcore->vtb = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DPDES: | 
|  | vcpu->arch.vcore->dpdes = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_LPCR: | 
|  | vcpu->arch.vcore->lpcr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_TB_OFFSET: | 
|  | vcpu->arch.vcore->tb_offset = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_FPSCR: | 
|  | vcpu->arch.fp.fpscr = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_VSRS(0)... KVMPPC_GSID_VSRS(31): | 
|  | kvmppc_gse_get_vector128(gse, &v); | 
|  | i = iden - KVMPPC_GSID_VSRS(0); | 
|  | memcpy(&vcpu->arch.fp.fpr[i], &v, | 
|  | sizeof(vcpu->arch.fp.fpr[i])); | 
|  | break; | 
|  | #ifdef CONFIG_VSX | 
|  | case KVMPPC_GSID_VSCR: | 
|  | vcpu->arch.vr.vscr.u[3] = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_VSRS(32)... KVMPPC_GSID_VSRS(63): | 
|  | i = iden - KVMPPC_GSID_VSRS(32); | 
|  | kvmppc_gse_get_vector128(gse, &vcpu->arch.vr.vr[i]); | 
|  | break; | 
|  | #endif | 
|  | case KVMPPC_GSID_HDAR: | 
|  | vcpu->arch.fault_dar = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_HDSISR: | 
|  | vcpu->arch.fault_dsisr = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_ASDR: | 
|  | vcpu->arch.fault_gpa = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_HEIR: | 
|  | vcpu->arch.emul_inst = kvmppc_gse_get_u64(gse); | 
|  | break; | 
|  | case KVMPPC_GSID_DEC_EXPIRY_TB: { | 
|  | u64 dw; | 
|  |  | 
|  | dw = kvmppc_gse_get_u64(gse); | 
|  | vcpu->arch.dec_expires = | 
|  | dw + vcpu->arch.vcore->tb_offset; | 
|  | break; | 
|  | } | 
|  | case KVMPPC_GSID_LOGICAL_PVR: | 
|  | vcpu->arch.vcore->arch_compat = kvmppc_gse_get_u32(gse); | 
|  | break; | 
|  | default: | 
|  | continue; | 
|  | } | 
|  | kvmppc_gsbm_set(valids, iden); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct kvmppc_gs_msg_ops vcpu_message_ops = { | 
|  | .get_size = gs_msg_ops_vcpu_get_size, | 
|  | .fill_info = gs_msg_ops_vcpu_fill_info, | 
|  | .refresh_info = gs_msg_ops_vcpu_refresh_info, | 
|  | }; | 
|  |  | 
|  | static int kvmhv_nestedv2_host_create(struct kvm_vcpu *vcpu, | 
|  | struct kvmhv_nestedv2_io *io) | 
|  | { | 
|  | struct kvmhv_nestedv2_config *cfg; | 
|  | struct kvmppc_gs_buff *gsb, *vcpu_run_output, *vcpu_run_input; | 
|  | unsigned long guest_id, vcpu_id; | 
|  | struct kvmppc_gs_msg *gsm, *vcpu_message, *vcore_message; | 
|  | int rc; | 
|  |  | 
|  | cfg = &io->cfg; | 
|  | guest_id = vcpu->kvm->arch.lpid; | 
|  | vcpu_id = vcpu->vcpu_id; | 
|  |  | 
|  | gsm = kvmppc_gsm_new(&config_msg_ops, cfg, KVMPPC_GS_FLAGS_WIDE, | 
|  | GFP_KERNEL); | 
|  | if (!gsm) { | 
|  | rc = -ENOMEM; | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | gsb = kvmppc_gsb_new(kvmppc_gsm_size(gsm), guest_id, vcpu_id, | 
|  | GFP_KERNEL); | 
|  | if (!gsb) { | 
|  | rc = -ENOMEM; | 
|  | goto free_gsm; | 
|  | } | 
|  |  | 
|  | rc = kvmppc_gsb_receive_datum(gsb, gsm, | 
|  | KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't get vcpu run output buffer minimum size\n"); | 
|  | goto free_gsb; | 
|  | } | 
|  |  | 
|  | vcpu_run_output = kvmppc_gsb_new(cfg->vcpu_run_output_size, guest_id, | 
|  | vcpu_id, GFP_KERNEL); | 
|  | if (!vcpu_run_output) { | 
|  | rc = -ENOMEM; | 
|  | goto free_gsb; | 
|  | } | 
|  |  | 
|  | cfg->vcpu_run_output_cfg.address = kvmppc_gsb_paddress(vcpu_run_output); | 
|  | cfg->vcpu_run_output_cfg.size = kvmppc_gsb_capacity(vcpu_run_output); | 
|  | io->vcpu_run_output = vcpu_run_output; | 
|  |  | 
|  | gsm->flags = 0; | 
|  | rc = kvmppc_gsb_send_datum(gsb, gsm, KVMPPC_GSID_RUN_OUTPUT); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't set vcpu run output buffer\n"); | 
|  | goto free_gs_out; | 
|  | } | 
|  |  | 
|  | vcpu_message = kvmppc_gsm_new(&vcpu_message_ops, vcpu, 0, GFP_KERNEL); | 
|  | if (!vcpu_message) { | 
|  | rc = -ENOMEM; | 
|  | goto free_gs_out; | 
|  | } | 
|  | kvmppc_gsm_include_all(vcpu_message); | 
|  |  | 
|  | io->vcpu_message = vcpu_message; | 
|  |  | 
|  | vcpu_run_input = kvmppc_gsb_new(kvmppc_gsm_size(vcpu_message), guest_id, | 
|  | vcpu_id, GFP_KERNEL); | 
|  | if (!vcpu_run_input) { | 
|  | rc = -ENOMEM; | 
|  | goto free_vcpu_message; | 
|  | } | 
|  |  | 
|  | io->vcpu_run_input = vcpu_run_input; | 
|  | cfg->vcpu_run_input_cfg.address = kvmppc_gsb_paddress(vcpu_run_input); | 
|  | cfg->vcpu_run_input_cfg.size = kvmppc_gsb_capacity(vcpu_run_input); | 
|  | rc = kvmppc_gsb_send_datum(gsb, gsm, KVMPPC_GSID_RUN_INPUT); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't set vcpu run input buffer\n"); | 
|  | goto free_vcpu_run_input; | 
|  | } | 
|  |  | 
|  | vcore_message = kvmppc_gsm_new(&vcpu_message_ops, vcpu, | 
|  | KVMPPC_GS_FLAGS_WIDE, GFP_KERNEL); | 
|  | if (!vcore_message) { | 
|  | rc = -ENOMEM; | 
|  | goto free_vcpu_run_input; | 
|  | } | 
|  |  | 
|  | kvmppc_gsm_include_all(vcore_message); | 
|  | kvmppc_gsbm_clear(&vcore_message->bitmap, KVMPPC_GSID_LOGICAL_PVR); | 
|  | io->vcore_message = vcore_message; | 
|  |  | 
|  | kvmppc_gsbm_fill(&io->valids); | 
|  | kvmppc_gsm_free(gsm); | 
|  | kvmppc_gsb_free(gsb); | 
|  | return 0; | 
|  |  | 
|  | free_vcpu_run_input: | 
|  | kvmppc_gsb_free(vcpu_run_input); | 
|  | free_vcpu_message: | 
|  | kvmppc_gsm_free(vcpu_message); | 
|  | free_gs_out: | 
|  | kvmppc_gsb_free(vcpu_run_output); | 
|  | free_gsb: | 
|  | kvmppc_gsb_free(gsb); | 
|  | free_gsm: | 
|  | kvmppc_gsm_free(gsm); | 
|  | err: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * __kvmhv_nestedv2_mark_dirty() - mark a Guest State ID to be sent to the host | 
|  | * @vcpu: vcpu | 
|  | * @iden: guest state ID | 
|  | * | 
|  | * Mark a guest state ID as having been changed by the L1 host and thus | 
|  | * the new value must be sent to the L0 hypervisor. See kvmhv_nestedv2_flush_vcpu() | 
|  | */ | 
|  | int __kvmhv_nestedv2_mark_dirty(struct kvm_vcpu *vcpu, u16 iden) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_bitmap *valids; | 
|  | struct kvmppc_gs_msg *gsm; | 
|  |  | 
|  | if (!iden) | 
|  | return 0; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | valids = &io->valids; | 
|  | gsm = io->vcpu_message; | 
|  | kvmppc_gsm_include(gsm, iden); | 
|  | gsm = io->vcore_message; | 
|  | kvmppc_gsm_include(gsm, iden); | 
|  | kvmppc_gsbm_set(valids, iden); | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_mark_dirty); | 
|  |  | 
|  | /** | 
|  | * __kvmhv_nestedv2_cached_reload() - reload a Guest State ID from the host | 
|  | * @vcpu: vcpu | 
|  | * @iden: guest state ID | 
|  | * | 
|  | * Reload the value for the guest state ID from the L0 host into the L1 host. | 
|  | * This is cached so that going out to the L0 host only happens if necessary. | 
|  | */ | 
|  | int __kvmhv_nestedv2_cached_reload(struct kvm_vcpu *vcpu, u16 iden) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_bitmap *valids; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | struct kvmppc_gs_msg gsm; | 
|  | int rc; | 
|  |  | 
|  | if (!iden) | 
|  | return 0; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | valids = &io->valids; | 
|  | if (kvmppc_gsbm_test(valids, iden)) | 
|  | return 0; | 
|  |  | 
|  | gsb = io->vcpu_run_input; | 
|  | kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, kvmppc_gsid_flags(iden)); | 
|  | rc = kvmppc_gsb_receive_datum(gsb, &gsm, iden); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't get GSID: 0x%x\n", iden); | 
|  | return rc; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_cached_reload); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_flush_vcpu() - send modified Guest State IDs to the host | 
|  | * @vcpu: vcpu | 
|  | * @time_limit: hdec expiry tb | 
|  | * | 
|  | * Send the values marked by __kvmhv_nestedv2_mark_dirty() to the L0 host. | 
|  | * Thread wide values are copied to the H_GUEST_RUN_VCPU input buffer. Guest | 
|  | * wide values need to be sent with H_GUEST_SET first. | 
|  | * | 
|  | * The hdec tb offset is always sent to L0 host. | 
|  | */ | 
|  | int kvmhv_nestedv2_flush_vcpu(struct kvm_vcpu *vcpu, u64 time_limit) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | struct kvmppc_gs_msg *gsm; | 
|  | int rc; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | gsb = io->vcpu_run_input; | 
|  | gsm = io->vcore_message; | 
|  | rc = kvmppc_gsb_send_data(gsb, gsm); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't set guest wide elements\n"); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | gsm = io->vcpu_message; | 
|  | kvmppc_gsb_reset(gsb); | 
|  | rc = kvmppc_gsm_fill_info(gsm, gsb); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't fill vcpu run input buffer\n"); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_HDEC_EXPIRY_TB, time_limit); | 
|  | if (rc < 0) | 
|  | return rc; | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_flush_vcpu); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_set_ptbl_entry() - send partition and process table state to | 
|  | * L0 host | 
|  | * @lpid: guest id | 
|  | * @dw0: partition table double word | 
|  | * @dw1: process table double word | 
|  | */ | 
|  | int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1) | 
|  | { | 
|  | struct kvmppc_gs_part_table patbl; | 
|  | struct kvmppc_gs_proc_table prtbl; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | size_t size; | 
|  | int rc; | 
|  |  | 
|  | size = kvmppc_gse_total_size( | 
|  | kvmppc_gsid_size(KVMPPC_GSID_PARTITION_TABLE)) + | 
|  | kvmppc_gse_total_size( | 
|  | kvmppc_gsid_size(KVMPPC_GSID_PROCESS_TABLE)) + | 
|  | sizeof(struct kvmppc_gs_header); | 
|  | gsb = kvmppc_gsb_new(size, lpid, 0, GFP_KERNEL); | 
|  | if (!gsb) | 
|  | return -ENOMEM; | 
|  |  | 
|  | patbl.address = dw0 & RPDB_MASK; | 
|  | patbl.ea_bits = ((((dw0 & RTS1_MASK) >> (RTS1_SHIFT - 3)) | | 
|  | ((dw0 & RTS2_MASK) >> RTS2_SHIFT)) + | 
|  | 31); | 
|  | patbl.gpd_size = 1ul << ((dw0 & RPDS_MASK) + 3); | 
|  | rc = kvmppc_gse_put_part_table(gsb, KVMPPC_GSID_PARTITION_TABLE, patbl); | 
|  | if (rc < 0) | 
|  | goto free_gsb; | 
|  |  | 
|  | prtbl.address = dw1 & PRTB_MASK; | 
|  | prtbl.gpd_size = 1ul << ((dw1 & PRTS_MASK) + 12); | 
|  | rc = kvmppc_gse_put_proc_table(gsb, KVMPPC_GSID_PROCESS_TABLE, prtbl); | 
|  | if (rc < 0) | 
|  | goto free_gsb; | 
|  |  | 
|  | rc = kvmppc_gsb_send(gsb, KVMPPC_GS_FLAGS_WIDE); | 
|  | if (rc < 0) { | 
|  | pr_err("KVM-NESTEDv2: couldn't set the PATE\n"); | 
|  | goto free_gsb; | 
|  | } | 
|  |  | 
|  | kvmppc_gsb_free(gsb); | 
|  | return 0; | 
|  |  | 
|  | free_gsb: | 
|  | kvmppc_gsb_free(gsb); | 
|  | return rc; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_ptbl_entry); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_set_vpa() - register L2 VPA with L0 | 
|  | * @vcpu: vcpu | 
|  | * @vpa: L1 logical real address | 
|  | */ | 
|  | int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | int rc = 0; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | gsb = io->vcpu_run_input; | 
|  |  | 
|  | kvmppc_gsb_reset(gsb); | 
|  | rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_VPA, vpa); | 
|  | if (rc < 0) | 
|  | goto out; | 
|  |  | 
|  | rc = kvmppc_gsb_send(gsb, 0); | 
|  | if (rc < 0) | 
|  | pr_err("KVM-NESTEDv2: couldn't register the L2 VPA (rc=%d)\n", rc); | 
|  |  | 
|  | out: | 
|  | kvmppc_gsb_reset(gsb); | 
|  | return rc; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_vpa); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_parse_output() - receive values from H_GUEST_RUN_VCPU output | 
|  | * @vcpu: vcpu | 
|  | * | 
|  | * Parse the output buffer from H_GUEST_RUN_VCPU to update vcpu. | 
|  | */ | 
|  | int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | struct kvmppc_gs_msg gsm; | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | gsb = io->vcpu_run_output; | 
|  |  | 
|  | vcpu->arch.fault_dar = 0; | 
|  | vcpu->arch.fault_dsisr = 0; | 
|  | vcpu->arch.fault_gpa = 0; | 
|  | vcpu->arch.emul_inst = KVM_INST_FETCH_FAILED; | 
|  |  | 
|  | kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, 0); | 
|  | return kvmppc_gsm_refresh_info(&gsm, gsb); | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_parse_output); | 
|  |  | 
|  | static void kvmhv_nestedv2_host_free(struct kvm_vcpu *vcpu, | 
|  | struct kvmhv_nestedv2_io *io) | 
|  | { | 
|  | kvmppc_gsm_free(io->vcpu_message); | 
|  | kvmppc_gsm_free(io->vcore_message); | 
|  | kvmppc_gsb_free(io->vcpu_run_input); | 
|  | kvmppc_gsb_free(io->vcpu_run_output); | 
|  | } | 
|  |  | 
|  | int __kvmhv_nestedv2_reload_ptregs(struct kvm_vcpu *vcpu, struct pt_regs *regs) | 
|  | { | 
|  | struct kvmhv_nestedv2_io *io; | 
|  | struct kvmppc_gs_bitmap *valids; | 
|  | struct kvmppc_gs_buff *gsb; | 
|  | struct kvmppc_gs_msg gsm; | 
|  | int rc = 0; | 
|  |  | 
|  |  | 
|  | io = &vcpu->arch.nestedv2_io; | 
|  | valids = &io->valids; | 
|  |  | 
|  | gsb = io->vcpu_run_input; | 
|  | kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, 0); | 
|  |  | 
|  | for (int i = 0; i < 32; i++) { | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_GPR(i))) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_GPR(i)); | 
|  | } | 
|  |  | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_CR)) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_CR); | 
|  |  | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_XER)) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_XER); | 
|  |  | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_CTR)) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_CTR); | 
|  |  | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_LR)) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_LR); | 
|  |  | 
|  | if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_NIA)) | 
|  | kvmppc_gsm_include(&gsm, KVMPPC_GSID_NIA); | 
|  |  | 
|  | rc = kvmppc_gsb_receive_data(gsb, &gsm); | 
|  | if (rc < 0) | 
|  | pr_err("KVM-NESTEDv2: couldn't reload ptregs\n"); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_reload_ptregs); | 
|  |  | 
|  | int __kvmhv_nestedv2_mark_dirty_ptregs(struct kvm_vcpu *vcpu, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | for (int i = 0; i < 32; i++) | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_GPR(i)); | 
|  |  | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_CR); | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_XER); | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_CTR); | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LR); | 
|  | kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_NIA); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_mark_dirty_ptregs); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_vcpu_create() - create nested vcpu for the NESTEDv2 API | 
|  | * @vcpu: vcpu | 
|  | * @io: NESTEDv2 nested io state | 
|  | * | 
|  | * Parse the output buffer from H_GUEST_RUN_VCPU to update vcpu. | 
|  | */ | 
|  | int kvmhv_nestedv2_vcpu_create(struct kvm_vcpu *vcpu, | 
|  | struct kvmhv_nestedv2_io *io) | 
|  | { | 
|  | long rc; | 
|  |  | 
|  | rc = plpar_guest_create_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id); | 
|  |  | 
|  | if (rc != H_SUCCESS) { | 
|  | pr_err("KVM: Create Guest vcpu hcall failed, rc=%ld\n", rc); | 
|  | switch (rc) { | 
|  | case H_NOT_ENOUGH_RESOURCES: | 
|  | case H_ABORTED: | 
|  | return -ENOMEM; | 
|  | case H_AUTHORITY: | 
|  | return -EPERM; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  |  | 
|  | rc = kvmhv_nestedv2_host_create(vcpu, io); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_vcpu_create); | 
|  |  | 
|  | /** | 
|  | * kvmhv_nestedv2_vcpu_free() - free the NESTEDv2 state | 
|  | * @vcpu: vcpu | 
|  | * @io: NESTEDv2 nested io state | 
|  | */ | 
|  | void kvmhv_nestedv2_vcpu_free(struct kvm_vcpu *vcpu, | 
|  | struct kvmhv_nestedv2_io *io) | 
|  | { | 
|  | kvmhv_nestedv2_host_free(vcpu, io); | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(kvmhv_nestedv2_vcpu_free); |