// SPDX-License-Identifier: GPL-2.0
/*
* Guest memory management for KVM/s390
*
* Copyright IBM Corp. 2008, 2020, 2024
*
* Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* David Hildenbrand <david@redhat.com>
* Janosch Frank <frankja@linux.ibm.com>
*/
#include <linux/compiler.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/pgtable.h>
#include <linux/pagemap.h>
#include <asm/lowcore.h>
#include <asm/uv.h>
#include <asm/gmap_helpers.h>
#include "dat.h"
#include "gmap.h"
#include "kvm-s390.h"
#include "faultin.h"
static inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)
{
return vcpu->arch.sie_block->prog0c & PROG_IN_SIE;
}
static int gmap_limit_to_type(gfn_t limit)
{
if (!limit)
return TABLE_TYPE_REGION1;
if (limit <= _REGION3_SIZE >> PAGE_SHIFT)
return TABLE_TYPE_SEGMENT;
if (limit <= _REGION2_SIZE >> PAGE_SHIFT)
return TABLE_TYPE_REGION3;
if (limit <= _REGION1_SIZE >> PAGE_SHIFT)
return TABLE_TYPE_REGION2;
return TABLE_TYPE_REGION1;
}
/**
* gmap_new() - Allocate and initialize a guest address space.
* @kvm: The kvm owning the guest.
* @limit: Maximum address of the gmap address space.
*
* Return: A guest address space structure.
*/
struct gmap *gmap_new(struct kvm *kvm, gfn_t limit)
{
struct crst_table *table;
struct gmap *gmap;
int type;
type = gmap_limit_to_type(limit);
gmap = kzalloc_obj(*gmap, GFP_KERNEL_ACCOUNT);
if (!gmap)
return NULL;
INIT_LIST_HEAD(&gmap->children);
INIT_LIST_HEAD(&gmap->list);
INIT_LIST_HEAD(&gmap->scb_users);
INIT_RADIX_TREE(&gmap->host_to_rmap, GFP_KVM_S390_MMU_CACHE);
spin_lock_init(&gmap->children_lock);
spin_lock_init(&gmap->host_to_rmap_lock);
refcount_set(&gmap->refcount, 1);
table = dat_alloc_crst_sleepable(_CRSTE_EMPTY(type).val);
if (!table) {
kfree(gmap);
return NUL