/*
* Copyright 2011 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
* Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved.
*
* Authors:
* Paul Mackerras <paulus@au1.ibm.com>
* Alexander Graf <agraf@suse.de>
* Kevin Wolf <mail@kevin-wolf.de>
*
* Description: KVM functions specific to running on Book 3S
* processors in hypervisor mode (specifically POWER7 and later).
*
* This file is derived from arch/powerpc/kvm/book3s.c,
* by Alexander Graf <agraf@suse.de>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*/
#include <linux/kvm_host.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/preempt.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/cpumask.h>
#include <linux/spinlock.h>
#include <linux/page-flags.h>
#include <asm/reg.h>
#include <asm/cputable.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
#include <asm/mmu_context.h>
#include <asm/lppaca.h>
#include <asm/processor.h>
#include <asm/cputhreads.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
/*
* For now, limit memory to 64GB and require it to be large pages.
* This value is chosen because it makes the ram_pginfo array be
* 64kB in size, which is about as large as we want to be trying
* to allocate with kmalloc.
*/
#define MAX_MEM_ORDER 36
#define LARGE_PAGE_ORDER 24 /* 16MB pages */
/* #define EXIT_DEBUG */
/* #define EXIT_DEBUG_SIMPLE */
/* #define EXIT_DEBUG_INT */
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
local_paca->kvm_hstate.kvm_vcpu = vcpu;
local_paca->kvm_hstate.kvm_vcore = vcpu->arch.vcore;
}
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
{
}
static void kvmppc_vcpu_blocked(struct kvm_vcpu *vcpu);
static void kvmppc_vcpu_unblocked(struct kvm_vcpu *vcpu);
void kvmppc_vcpu_block(struct kvm_vcpu *vcpu)
{
u64 now;
unsigned long dec_nsec;
now = get_tb();
if (now >= vcpu->arch.dec_expires && !kvmppc_core_pending_dec(vcpu))
kvmppc_core_queue_dec(vcpu);
if (vcpu->arch.pending_exceptions)
return;
if (vcpu->arch.dec_expires != ~(u64)0) {
dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC /
tb_ticks_per_sec;
hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec),
HRTIMER_MODE_REL);
}
kvmppc_vcpu_blocked(vcpu);
kvm_vcpu_block(vcpu);
vcpu->stat.halt_wakeup++;
if (vcpu->arch.dec_expires != ~(u64)0)
hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
kvmppc_vcpu_unblocked(vcpu);
}
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
{
vcpu->arch.shregs.msr = msr;
}
void kvmppc_set_pvr(struct