// 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)) {
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