2019-06-04 15:11:33 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2009-01-04 05:23:10 +07:00
|
|
|
/*
|
2013-01-11 21:22:45 +07:00
|
|
|
* Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All rights reserved.
|
2009-01-04 05:23:10 +07:00
|
|
|
*
|
|
|
|
* Author: Yu Liu, yu.liu@freescale.com
|
2011-12-20 22:34:47 +07:00
|
|
|
* Scott Wood, scottwood@freescale.com
|
2011-12-20 22:34:37 +07:00
|
|
|
* Ashish Kalra, ashish.kalra@freescale.com
|
2011-12-20 22:34:47 +07:00
|
|
|
* Varun Sethi, varun.sethi@freescale.com
|
2013-01-11 21:22:45 +07:00
|
|
|
* Alexander Graf, agraf@suse.de
|
2009-01-04 05:23:10 +07:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This file is based on arch/powerpc/kvm/44x_tlb.c,
|
|
|
|
* by Hollis Blanchard <hollisb@us.ibm.com>.
|
|
|
|
*/
|
|
|
|
|
2011-08-19 03:25:18 +07:00
|
|
|
#include <linux/kernel.h>
|
2009-01-04 05:23:10 +07:00
|
|
|
#include <linux/types.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 15:04:11 +07:00
|
|
|
#include <linux/slab.h>
|
2009-01-04 05:23:10 +07:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/kvm.h>
|
|
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include <linux/highmem.h>
|
2011-08-19 03:25:21 +07:00
|
|
|
#include <linux/log2.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/rwsem.h>
|
|
|
|
#include <linux/vmalloc.h>
|
2011-09-20 06:31:48 +07:00
|
|
|
#include <linux/hugetlb.h>
|
2009-01-04 05:23:10 +07:00
|
|
|
#include <asm/kvm_ppc.h>
|
|
|
|
|
2011-12-20 22:34:29 +07:00
|
|
|
#include "e500.h"
|
2013-10-07 23:47:58 +07:00
|
|
|
#include "trace_booke.h"
|
2011-03-29 03:01:24 +07:00
|
|
|
#include "timing.h"
|
2013-01-11 21:22:45 +07:00
|
|
|
#include "e500_mmu_host.h"
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-08-19 03:25:18 +07:00
|
|
|
static inline unsigned int gtlb0_get_next_victim(
|
2009-01-04 05:23:10 +07:00
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
|
{
|
|
|
|
unsigned int victim;
|
|
|
|
|
2011-06-15 06:34:59 +07:00
|
|
|
victim = vcpu_e500->gtlb_nv[0]++;
|
2011-08-19 03:25:21 +07:00
|
|
|
if (unlikely(vcpu_e500->gtlb_nv[0] >= vcpu_e500->gtlb_params[0].ways))
|
2011-06-15 06:34:59 +07:00
|
|
|
vcpu_e500->gtlb_nv[0] = 0;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return victim;
|
|
|
|
}
|
|
|
|
|
2011-08-19 03:25:18 +07:00
|
|
|
static int tlb0_set_base(gva_t addr, int sets, int ways)
|
|
|
|
{
|
|
|
|
int set_base;
|
|
|
|
|
|
|
|
set_base = (addr >> PAGE_SHIFT) & (sets - 1);
|
|
|
|
set_base *= ways;
|
|
|
|
|
|
|
|
return set_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gtlb0_set_base(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t addr)
|
|
|
|
{
|
2011-08-19 03:25:21 +07:00
|
|
|
return tlb0_set_base(addr, vcpu_e500->gtlb_params[0].sets,
|
|
|
|
vcpu_e500->gtlb_params[0].ways);
|
2011-08-19 03:25:18 +07:00
|
|
|
}
|
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
static unsigned int get_tlb_esel(struct kvm_vcpu *vcpu, int tlbsel)
|
2011-08-19 03:25:18 +07:00
|
|
|
{
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
int esel = get_tlb_esel_bit(vcpu);
|
2011-08-19 03:25:18 +07:00
|
|
|
|
|
|
|
if (tlbsel == 0) {
|
2011-08-19 03:25:21 +07:00
|
|
|
esel &= vcpu_e500->gtlb_params[0].ways - 1;
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
esel += gtlb0_set_base(vcpu_e500, vcpu->arch.shared->mas2);
|
2011-08-19 03:25:18 +07:00
|
|
|
} else {
|
2011-08-19 03:25:21 +07:00
|
|
|
esel &= vcpu_e500->gtlb_params[tlbsel].entries - 1;
|
2011-08-19 03:25:18 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return esel;
|
|
|
|
}
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
/* Search the guest TLB for a matching entry. */
|
|
|
|
static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
|
|
|
|
gva_t eaddr, int tlbsel, unsigned int pid, int as)
|
|
|
|
{
|
2011-08-19 03:25:21 +07:00
|
|
|
int size = vcpu_e500->gtlb_params[tlbsel].entries;
|
|
|
|
unsigned int set_base, offset;
|
2009-01-04 05:23:10 +07:00
|
|
|
int i;
|
|
|
|
|
2011-06-15 06:35:20 +07:00
|
|
|
if (tlbsel == 0) {
|
2011-08-19 03:25:18 +07:00
|
|
|
set_base = gtlb0_set_base(vcpu_e500, eaddr);
|
2011-08-19 03:25:21 +07:00
|
|
|
size = vcpu_e500->gtlb_params[0].ways;
|
2011-06-15 06:35:20 +07:00
|
|
|
} else {
|
2012-03-23 01:39:11 +07:00
|
|
|
if (eaddr < vcpu_e500->tlb1_min_eaddr ||
|
|
|
|
eaddr > vcpu_e500->tlb1_max_eaddr)
|
|
|
|
return -1;
|
2011-06-15 06:35:20 +07:00
|
|
|
set_base = 0;
|
|
|
|
}
|
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
offset = vcpu_e500->gtlb_offset[tlbsel];
|
|
|
|
|
2011-06-15 06:35:20 +07:00
|
|
|
for (i = 0; i < size; i++) {
|
2011-08-19 03:25:21 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *tlbe =
|
|
|
|
&vcpu_e500->gtlb_arch[offset + set_base + i];
|
2009-01-04 05:23:10 +07:00
|
|
|
unsigned int tid;
|
|
|
|
|
|
|
|
if (eaddr < get_tlb_eaddr(tlbe))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (eaddr > get_tlb_end(tlbe))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tid = get_tlb_tid(tlbe);
|
|
|
|
if (tid && (tid != pid))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!get_tlb_v(tlbe))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (get_tlb_ts(tlbe) != as && as != -1)
|
|
|
|
continue;
|
|
|
|
|
2011-06-15 06:35:20 +07:00
|
|
|
return set_base + i;
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
|
2014-01-09 22:01:05 +07:00
|
|
|
gva_t eaddr, int as)
|
2009-01-04 05:23:10 +07:00
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
2011-12-20 22:34:34 +07:00
|
|
|
unsigned int victim, tsized;
|
2009-01-04 05:23:10 +07:00
|
|
|
int tlbsel;
|
|
|
|
|
2009-01-14 23:47:37 +07:00
|
|
|
/* since we only have two TLBs, only lower bit is used. */
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
tlbsel = (vcpu->arch.shared->mas4 >> 28) & 0x1;
|
2011-08-19 03:25:18 +07:00
|
|
|
victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
tsized = (vcpu->arch.shared->mas4 >> 7) & 0x1f;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
|
2011-06-15 06:34:59 +07:00
|
|
|
| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas1 = MAS1_VALID | (as ? MAS1_TS : 0)
|
2011-12-20 22:34:34 +07:00
|
|
|
| MAS1_TID(get_tlbmiss_tid(vcpu))
|
2009-01-04 05:23:10 +07:00
|
|
|
| MAS1_TSIZE(tsized);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas2 = (eaddr & MAS2_EPN)
|
|
|
|
| (vcpu->arch.shared->mas4 & MAS2_ATTRIB_MASK);
|
|
|
|
vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
|
|
|
|
vcpu->arch.shared->mas6 = (vcpu->arch.shared->mas6 & MAS6_SPID1)
|
2009-01-04 05:23:10 +07:00
|
|
|
| (get_cur_pid(vcpu) << 16)
|
|
|
|
| (as ? MAS6_SAS : 0);
|
|
|
|
}
|
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
static void kvmppc_recalc_tlb1map_range(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
|
{
|
|
|
|
int size = vcpu_e500->gtlb_params[1].entries;
|
|
|
|
unsigned int offset;
|
|
|
|
gva_t eaddr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
vcpu_e500->tlb1_min_eaddr = ~0UL;
|
|
|
|
vcpu_e500->tlb1_max_eaddr = 0;
|
|
|
|
offset = vcpu_e500->gtlb_offset[1];
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
struct kvm_book3e_206_tlb_entry *tlbe =
|
|
|
|
&vcpu_e500->gtlb_arch[offset + i];
|
|
|
|
|
|
|
|
if (!get_tlb_v(tlbe))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
eaddr = get_tlb_eaddr(tlbe);
|
|
|
|
vcpu_e500->tlb1_min_eaddr =
|
|
|
|
min(vcpu_e500->tlb1_min_eaddr, eaddr);
|
|
|
|
|
|
|
|
eaddr = get_tlb_end(tlbe);
|
|
|
|
vcpu_e500->tlb1_max_eaddr =
|
|
|
|
max(vcpu_e500->tlb1_max_eaddr, eaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmppc_need_recalc_tlb1map_range(struct kvmppc_vcpu_e500 *vcpu_e500,
|
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe)
|
|
|
|
{
|
|
|
|
unsigned long start, end, size;
|
|
|
|
|
|
|
|
size = get_tlb_bytes(gtlbe);
|
|
|
|
start = get_tlb_eaddr(gtlbe) & ~(size - 1);
|
|
|
|
end = start + size - 1;
|
|
|
|
|
|
|
|
return vcpu_e500->tlb1_min_eaddr == start ||
|
|
|
|
vcpu_e500->tlb1_max_eaddr == end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is supposed to be called for a adding a new valid tlb entry */
|
|
|
|
static void kvmppc_set_tlb1map_range(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe)
|
|
|
|
{
|
|
|
|
unsigned long start, end, size;
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
|
|
|
|
if (!get_tlb_v(gtlbe))
|
|
|
|
return;
|
|
|
|
|
|
|
|
size = get_tlb_bytes(gtlbe);
|
|
|
|
start = get_tlb_eaddr(gtlbe) & ~(size - 1);
|
|
|
|
end = start + size - 1;
|
|
|
|
|
|
|
|
vcpu_e500->tlb1_min_eaddr = min(vcpu_e500->tlb1_min_eaddr, start);
|
|
|
|
vcpu_e500->tlb1_max_eaddr = max(vcpu_e500->tlb1_max_eaddr, end);
|
|
|
|
}
|
|
|
|
|
2011-06-15 06:34:59 +07:00
|
|
|
static inline int kvmppc_e500_gtlbe_invalidate(
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500,
|
|
|
|
int tlbsel, int esel)
|
2009-01-04 05:23:10 +07:00
|
|
|
{
|
2011-08-19 03:25:21 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe =
|
|
|
|
get_entry(vcpu_e500, tlbsel, esel);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
if (unlikely(get_tlb_iprot(gtlbe)))
|
|
|
|
return -1;
|
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
if (tlbsel == 1 && kvmppc_need_recalc_tlb1map_range(vcpu_e500, gtlbe))
|
|
|
|
kvmppc_recalc_tlb1map_range(vcpu_e500);
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
gtlbe->mas1 = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-17 15:52:08 +07:00
|
|
|
int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value)
|
|
|
|
{
|
|
|
|
int esel;
|
|
|
|
|
|
|
|
if (value & MMUCSR0_TLB0FI)
|
2011-08-19 03:25:21 +07:00
|
|
|
for (esel = 0; esel < vcpu_e500->gtlb_params[0].entries; esel++)
|
2009-02-17 15:52:08 +07:00
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel);
|
|
|
|
if (value & MMUCSR0_TLB1FI)
|
2011-08-19 03:25:21 +07:00
|
|
|
for (esel = 0; esel < vcpu_e500->gtlb_params[1].entries; esel++)
|
2009-02-17 15:52:08 +07:00
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel);
|
|
|
|
|
2013-01-18 21:22:08 +07:00
|
|
|
/* Invalidate all host shadow mappings */
|
|
|
|
kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
|
2009-02-17 15:52:08 +07:00
|
|
|
|
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
2012-10-11 13:13:22 +07:00
|
|
|
int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea)
|
2009-01-04 05:23:10 +07:00
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
unsigned int ia;
|
|
|
|
int esel, tlbsel;
|
|
|
|
|
|
|
|
ia = (ea >> 2) & 0x1;
|
|
|
|
|
2009-01-14 23:47:37 +07:00
|
|
|
/* since we only have two TLBs, only lower bit is used. */
|
2009-01-04 05:23:10 +07:00
|
|
|
tlbsel = (ea >> 3) & 0x1;
|
|
|
|
|
|
|
|
if (ia) {
|
|
|
|
/* invalidate all entries */
|
2011-08-19 03:25:21 +07:00
|
|
|
for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries;
|
|
|
|
esel++)
|
2009-01-04 05:23:10 +07:00
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
|
|
|
|
} else {
|
|
|
|
ea &= 0xfffff000;
|
|
|
|
esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel,
|
|
|
|
get_cur_pid(vcpu), -1);
|
|
|
|
if (esel >= 0)
|
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
|
|
|
|
}
|
|
|
|
|
2013-01-18 21:22:08 +07:00
|
|
|
/* Invalidate all host shadow mappings */
|
|
|
|
kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
2011-12-20 22:34:39 +07:00
|
|
|
static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
|
2012-10-11 13:13:22 +07:00
|
|
|
int pid, int type)
|
2011-12-20 22:34:39 +07:00
|
|
|
{
|
|
|
|
struct kvm_book3e_206_tlb_entry *tlbe;
|
|
|
|
int tid, esel;
|
|
|
|
|
|
|
|
/* invalidate all entries */
|
|
|
|
for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries; esel++) {
|
|
|
|
tlbe = get_entry(vcpu_e500, tlbsel, esel);
|
|
|
|
tid = get_tlb_tid(tlbe);
|
2012-10-11 13:13:22 +07:00
|
|
|
if (type == 0 || tid == pid) {
|
2011-12-20 22:34:39 +07:00
|
|
|
inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
|
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
|
2012-10-11 13:13:22 +07:00
|
|
|
gva_t ea)
|
2011-12-20 22:34:39 +07:00
|
|
|
{
|
|
|
|
int tlbsel, esel;
|
|
|
|
|
|
|
|
for (tlbsel = 0; tlbsel < 2; tlbsel++) {
|
|
|
|
esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, -1);
|
|
|
|
if (esel >= 0) {
|
|
|
|
inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
|
|
|
|
kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-11 13:13:22 +07:00
|
|
|
int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int type, gva_t ea)
|
2011-12-20 22:34:39 +07:00
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
int pid = get_cur_spid(vcpu);
|
|
|
|
|
2012-10-11 13:13:22 +07:00
|
|
|
if (type == 0 || type == 1) {
|
|
|
|
tlbilx_all(vcpu_e500, 0, pid, type);
|
|
|
|
tlbilx_all(vcpu_e500, 1, pid, type);
|
|
|
|
} else if (type == 3) {
|
|
|
|
tlbilx_one(vcpu_e500, pid, ea);
|
2011-12-20 22:34:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
int tlbsel, esel;
|
2011-08-19 03:25:21 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
tlbsel = get_tlb_tlbsel(vcpu);
|
|
|
|
esel = get_tlb_esel(vcpu, tlbsel);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
gtlbe = get_entry(vcpu_e500, tlbsel, esel);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas0 &= ~MAS0_NV(~0);
|
|
|
|
vcpu->arch.shared->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
|
|
|
|
vcpu->arch.shared->mas1 = gtlbe->mas1;
|
|
|
|
vcpu->arch.shared->mas2 = gtlbe->mas2;
|
|
|
|
vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
2012-10-11 13:13:22 +07:00
|
|
|
int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea)
|
2009-01-04 05:23:10 +07:00
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
int as = !!get_cur_sas(vcpu);
|
|
|
|
unsigned int pid = get_cur_spid(vcpu);
|
2009-01-04 05:23:10 +07:00
|
|
|
int esel, tlbsel;
|
2011-08-19 03:25:21 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe = NULL;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
for (tlbsel = 0; tlbsel < 2; tlbsel++) {
|
|
|
|
esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as);
|
|
|
|
if (esel >= 0) {
|
2011-08-19 03:25:21 +07:00
|
|
|
gtlbe = get_entry(vcpu_e500, tlbsel, esel);
|
2009-01-04 05:23:10 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gtlbe) {
|
2011-08-19 03:25:23 +07:00
|
|
|
esel &= vcpu_e500->gtlb_params[tlbsel].ways - 1;
|
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel)
|
2011-06-15 06:34:59 +07:00
|
|
|
| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas1 = gtlbe->mas1;
|
|
|
|
vcpu->arch.shared->mas2 = gtlbe->mas2;
|
|
|
|
vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
|
2009-01-04 05:23:10 +07:00
|
|
|
} else {
|
|
|
|
int victim;
|
|
|
|
|
2009-01-14 23:47:37 +07:00
|
|
|
/* since we only have two TLBs, only lower bit is used. */
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
tlbsel = vcpu->arch.shared->mas4 >> 28 & 0x1;
|
2011-08-19 03:25:18 +07:00
|
|
|
victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel)
|
|
|
|
| MAS0_ESEL(victim)
|
2011-06-15 06:34:59 +07:00
|
|
|
| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
vcpu->arch.shared->mas1 =
|
|
|
|
(vcpu->arch.shared->mas6 & MAS6_SPID0)
|
2015-05-25 15:48:39 +07:00
|
|
|
| ((vcpu->arch.shared->mas6 & MAS6_SAS) ? MAS1_TS : 0)
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
| (vcpu->arch.shared->mas4 & MAS4_TSIZED(~0));
|
|
|
|
vcpu->arch.shared->mas2 &= MAS2_EPN;
|
|
|
|
vcpu->arch.shared->mas2 |= vcpu->arch.shared->mas4 &
|
|
|
|
MAS2_ATTRIB_MASK;
|
|
|
|
vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 |
|
|
|
|
MAS3_U2 | MAS3_U3;
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
|
|
|
|
2011-03-29 03:01:24 +07:00
|
|
|
kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
|
2009-01-04 05:23:10 +07:00
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
2013-01-18 01:23:28 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe;
|
|
|
|
int tlbsel, esel;
|
2012-03-23 01:39:11 +07:00
|
|
|
int recal = 0;
|
2013-06-07 07:16:31 +07:00
|
|
|
int idx;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
tlbsel = get_tlb_tlbsel(vcpu);
|
|
|
|
esel = get_tlb_esel(vcpu, tlbsel);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
gtlbe = get_entry(vcpu_e500, tlbsel, esel);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
if (get_tlb_v(gtlbe)) {
|
2011-08-19 03:25:18 +07:00
|
|
|
inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
|
2012-03-23 01:39:11 +07:00
|
|
|
if ((tlbsel == 1) &&
|
|
|
|
kvmppc_need_recalc_tlb1map_range(vcpu_e500, gtlbe))
|
|
|
|
recal = 1;
|
|
|
|
}
|
2009-01-04 05:23:10 +07:00
|
|
|
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
gtlbe->mas1 = vcpu->arch.shared->mas1;
|
|
|
|
gtlbe->mas2 = vcpu->arch.shared->mas2;
|
2012-10-11 13:13:24 +07:00
|
|
|
if (!(vcpu->arch.shared->msr & MSR_CM))
|
|
|
|
gtlbe->mas2 &= 0xffffffffUL;
|
KVM: PPC: Paravirtualize SPRG4-7, ESR, PIR, MASn
This allows additional registers to be accessed by the guest
in PR-mode KVM without trapping.
SPRG4-7 are readable from userspace. On booke, KVM will sync
these registers when it enters the guest, so that accesses from
guest userspace will work. The guest kernel, OTOH, must consistently
use either the real registers or the shared area between exits. This
also applies to the already-paravirted SPRG3.
On non-booke, it's not clear to what extent SPRG4-7 are supported
(they're not architected for book3s, but exist on at least some classic
chips). They are copied in the get/set regs ioctls, but I do not see any
non-booke emulation. I also do not see any syncing with real registers
(in PR-mode) including the user-readable SPRG3. This patch should not
make that situation any worse.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
2011-11-09 07:23:30 +07:00
|
|
|
gtlbe->mas7_3 = vcpu->arch.shared->mas7_3;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-12-20 21:42:56 +07:00
|
|
|
trace_kvm_booke206_gtlb_write(vcpu->arch.shared->mas0, gtlbe->mas1,
|
|
|
|
gtlbe->mas2, gtlbe->mas7_3);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
if (tlbsel == 1) {
|
|
|
|
/*
|
|
|
|
* If a valid tlb1 entry is overwritten then recalculate the
|
|
|
|
* min/max TLB1 map address range otherwise no need to look
|
|
|
|
* in tlb1 array.
|
|
|
|
*/
|
|
|
|
if (recal)
|
|
|
|
kvmppc_recalc_tlb1map_range(vcpu_e500);
|
|
|
|
else
|
|
|
|
kvmppc_set_tlb1map_range(vcpu, gtlbe);
|
|
|
|
}
|
|
|
|
|
2013-06-07 07:16:31 +07:00
|
|
|
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
|
|
|
|
if (tlbe_is_host_safe(vcpu, gtlbe)) {
|
2013-01-18 01:23:28 +07:00
|
|
|
u64 eaddr = get_tlb_eaddr(gtlbe);
|
|
|
|
u64 raddr = get_tlb_raddr(gtlbe);
|
2011-06-15 06:34:59 +07:00
|
|
|
|
2013-01-18 01:23:28 +07:00
|
|
|
if (tlbsel == 0) {
|
2009-01-04 05:23:10 +07:00
|
|
|
gtlbe->mas1 &= ~MAS1_TSIZE(~0);
|
2009-06-05 13:54:29 +07:00
|
|
|
gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K);
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
2011-08-19 03:25:14 +07:00
|
|
|
|
2013-01-18 01:23:28 +07:00
|
|
|
/* Premap the faulting page */
|
|
|
|
kvmppc_mmu_map(vcpu, eaddr, raddr, index_of(tlbsel, esel));
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
|
|
|
|
2013-06-07 07:16:31 +07:00
|
|
|
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
|
|
|
2011-03-29 03:01:24 +07:00
|
|
|
kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
|
2009-01-04 05:23:10 +07:00
|
|
|
return EMULATE_DONE;
|
|
|
|
}
|
|
|
|
|
2011-12-20 22:34:34 +07:00
|
|
|
static int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu,
|
|
|
|
gva_t eaddr, unsigned int pid, int as)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
int esel, tlbsel;
|
|
|
|
|
|
|
|
for (tlbsel = 0; tlbsel < 2; tlbsel++) {
|
|
|
|
esel = kvmppc_e500_tlb_index(vcpu_e500, eaddr, tlbsel, pid, as);
|
|
|
|
if (esel >= 0)
|
|
|
|
return index_of(tlbsel, esel);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 'linear_address' is actually an encoding of AS|PID|EADDR . */
|
|
|
|
int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvm_translation *tr)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
gva_t eaddr;
|
|
|
|
u8 pid;
|
|
|
|
u8 as;
|
|
|
|
|
|
|
|
eaddr = tr->linear_address;
|
|
|
|
pid = (tr->linear_address >> 32) & 0xff;
|
|
|
|
as = (tr->linear_address >> 40) & 0x1;
|
|
|
|
|
|
|
|
index = kvmppc_e500_tlb_search(vcpu, eaddr, pid, as);
|
|
|
|
if (index < 0) {
|
|
|
|
tr->valid = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
tr->physical_address = kvmppc_mmu_xlate(vcpu, index, eaddr);
|
|
|
|
/* XXX what does "writeable" and "usermode" even mean? */
|
|
|
|
tr->valid = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
|
|
|
|
{
|
2010-07-29 19:47:43 +07:00
|
|
|
unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
|
|
|
|
{
|
2010-07-29 19:47:43 +07:00
|
|
|
unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2010-07-29 19:47:43 +07:00
|
|
|
unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2018-05-07 13:20:08 +07:00
|
|
|
kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.regs.nip, as);
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2010-07-29 19:47:43 +07:00
|
|
|
unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.fault_dear, as);
|
|
|
|
}
|
|
|
|
|
|
|
|
gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index,
|
|
|
|
gva_t eaddr)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
2011-08-19 03:25:21 +07:00
|
|
|
struct kvm_book3e_206_tlb_entry *gtlbe;
|
|
|
|
u64 pgmask;
|
|
|
|
|
|
|
|
gtlbe = get_entry(vcpu_e500, tlbsel_of(index), esel_of(index));
|
|
|
|
pgmask = get_tlb_bytes(gtlbe) - 1;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
|
|
|
return get_tlb_raddr(gtlbe) | (eaddr & pgmask);
|
|
|
|
}
|
|
|
|
|
2013-10-07 23:47:53 +07:00
|
|
|
void kvmppc_mmu_destroy_e500(struct kvm_vcpu *vcpu)
|
2009-01-04 05:23:10 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-07-31 05:19:50 +07:00
|
|
|
/*****************************************/
|
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2013-01-18 21:13:19 +07:00
|
|
|
kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
|
2011-12-20 22:34:37 +07:00
|
|
|
kfree(vcpu_e500->g2h_tlb1_map);
|
2011-08-19 03:25:21 +07:00
|
|
|
kfree(vcpu_e500->gtlb_priv[0]);
|
|
|
|
kfree(vcpu_e500->gtlb_priv[1]);
|
|
|
|
|
|
|
|
if (vcpu_e500->shared_tlb_pages) {
|
|
|
|
vfree((void *)(round_down((uintptr_t)vcpu_e500->gtlb_arch,
|
|
|
|
PAGE_SIZE)));
|
|
|
|
|
|
|
|
for (i = 0; i < vcpu_e500->num_shared_tlb_pages; i++) {
|
|
|
|
set_page_dirty_lock(vcpu_e500->shared_tlb_pages[i]);
|
|
|
|
put_page(vcpu_e500->shared_tlb_pages[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
vcpu_e500->num_shared_tlb_pages = 0;
|
2012-08-22 22:04:24 +07:00
|
|
|
|
|
|
|
kfree(vcpu_e500->shared_tlb_pages);
|
2011-08-19 03:25:21 +07:00
|
|
|
vcpu_e500->shared_tlb_pages = NULL;
|
|
|
|
} else {
|
|
|
|
kfree(vcpu_e500->gtlb_arch);
|
|
|
|
}
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_arch = NULL;
|
|
|
|
}
|
|
|
|
|
2011-12-20 22:34:34 +07:00
|
|
|
void kvmppc_get_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
|
|
{
|
|
|
|
sregs->u.e.mas0 = vcpu->arch.shared->mas0;
|
|
|
|
sregs->u.e.mas1 = vcpu->arch.shared->mas1;
|
|
|
|
sregs->u.e.mas2 = vcpu->arch.shared->mas2;
|
|
|
|
sregs->u.e.mas7_3 = vcpu->arch.shared->mas7_3;
|
|
|
|
sregs->u.e.mas4 = vcpu->arch.shared->mas4;
|
|
|
|
sregs->u.e.mas6 = vcpu->arch.shared->mas6;
|
|
|
|
|
|
|
|
sregs->u.e.mmucfg = vcpu->arch.mmucfg;
|
|
|
|
sregs->u.e.tlbcfg[0] = vcpu->arch.tlbcfg[0];
|
|
|
|
sregs->u.e.tlbcfg[1] = vcpu->arch.tlbcfg[1];
|
|
|
|
sregs->u.e.tlbcfg[2] = 0;
|
|
|
|
sregs->u.e.tlbcfg[3] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_set_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
|
|
{
|
|
|
|
if (sregs->u.e.features & KVM_SREGS_E_ARCH206_MMU) {
|
|
|
|
vcpu->arch.shared->mas0 = sregs->u.e.mas0;
|
|
|
|
vcpu->arch.shared->mas1 = sregs->u.e.mas1;
|
|
|
|
vcpu->arch.shared->mas2 = sregs->u.e.mas2;
|
|
|
|
vcpu->arch.shared->mas7_3 = sregs->u.e.mas7_3;
|
|
|
|
vcpu->arch.shared->mas4 = sregs->u.e.mas4;
|
|
|
|
vcpu->arch.shared->mas6 = sregs->u.e.mas6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-11 07:03:08 +07:00
|
|
|
int kvmppc_get_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
|
|
|
|
union kvmppc_one_reg *val)
|
|
|
|
{
|
|
|
|
int r = 0;
|
|
|
|
long int i;
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
case KVM_REG_PPC_MAS0:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas0);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS1:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas1);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS2:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas2);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS7_3:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas7_3);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS4:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas4);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS6:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.shared->mas6);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MMUCFG:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.mmucfg);
|
|
|
|
break;
|
2013-04-11 07:03:11 +07:00
|
|
|
case KVM_REG_PPC_EPTCFG:
|
|
|
|
*val = get_reg_val(id, vcpu->arch.eptcfg);
|
|
|
|
break;
|
2013-04-11 07:03:08 +07:00
|
|
|
case KVM_REG_PPC_TLB0CFG:
|
|
|
|
case KVM_REG_PPC_TLB1CFG:
|
|
|
|
case KVM_REG_PPC_TLB2CFG:
|
|
|
|
case KVM_REG_PPC_TLB3CFG:
|
|
|
|
i = id - KVM_REG_PPC_TLB0CFG;
|
|
|
|
*val = get_reg_val(id, vcpu->arch.tlbcfg[i]);
|
|
|
|
break;
|
2013-04-11 07:03:10 +07:00
|
|
|
case KVM_REG_PPC_TLB0PS:
|
|
|
|
case KVM_REG_PPC_TLB1PS:
|
|
|
|
case KVM_REG_PPC_TLB2PS:
|
|
|
|
case KVM_REG_PPC_TLB3PS:
|
|
|
|
i = id - KVM_REG_PPC_TLB0PS;
|
|
|
|
*val = get_reg_val(id, vcpu->arch.tlbps[i]);
|
|
|
|
break;
|
2013-04-11 07:03:08 +07:00
|
|
|
default:
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_set_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id,
|
|
|
|
union kvmppc_one_reg *val)
|
|
|
|
{
|
|
|
|
int r = 0;
|
|
|
|
long int i;
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
case KVM_REG_PPC_MAS0:
|
|
|
|
vcpu->arch.shared->mas0 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS1:
|
|
|
|
vcpu->arch.shared->mas1 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS2:
|
|
|
|
vcpu->arch.shared->mas2 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS7_3:
|
|
|
|
vcpu->arch.shared->mas7_3 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS4:
|
|
|
|
vcpu->arch.shared->mas4 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
case KVM_REG_PPC_MAS6:
|
|
|
|
vcpu->arch.shared->mas6 = set_reg_val(id, *val);
|
|
|
|
break;
|
|
|
|
/* Only allow MMU registers to be set to the config supported by KVM */
|
|
|
|
case KVM_REG_PPC_MMUCFG: {
|
|
|
|
u32 reg = set_reg_val(id, *val);
|
|
|
|
if (reg != vcpu->arch.mmucfg)
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-11 07:03:11 +07:00
|
|
|
case KVM_REG_PPC_EPTCFG: {
|
|
|
|
u32 reg = set_reg_val(id, *val);
|
|
|
|
if (reg != vcpu->arch.eptcfg)
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-11 07:03:08 +07:00
|
|
|
case KVM_REG_PPC_TLB0CFG:
|
|
|
|
case KVM_REG_PPC_TLB1CFG:
|
|
|
|
case KVM_REG_PPC_TLB2CFG:
|
|
|
|
case KVM_REG_PPC_TLB3CFG: {
|
|
|
|
/* MMU geometry (N_ENTRY/ASSOC) can be set only using SW_TLB */
|
|
|
|
u32 reg = set_reg_val(id, *val);
|
|
|
|
i = id - KVM_REG_PPC_TLB0CFG;
|
|
|
|
if (reg != vcpu->arch.tlbcfg[i])
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-11 07:03:10 +07:00
|
|
|
case KVM_REG_PPC_TLB0PS:
|
|
|
|
case KVM_REG_PPC_TLB1PS:
|
|
|
|
case KVM_REG_PPC_TLB2PS:
|
|
|
|
case KVM_REG_PPC_TLB3PS: {
|
|
|
|
u32 reg = set_reg_val(id, *val);
|
|
|
|
i = id - KVM_REG_PPC_TLB0PS;
|
|
|
|
if (reg != vcpu->arch.tlbps[i])
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-11 07:03:08 +07:00
|
|
|
default:
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-04-11 07:03:09 +07:00
|
|
|
static int vcpu_mmu_geometry_update(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvm_book3e_206_tlb_params *params)
|
|
|
|
{
|
|
|
|
vcpu->arch.tlbcfg[0] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
|
|
|
|
if (params->tlb_sizes[0] <= 2048)
|
|
|
|
vcpu->arch.tlbcfg[0] |= params->tlb_sizes[0];
|
|
|
|
vcpu->arch.tlbcfg[0] |= params->tlb_ways[0] << TLBnCFG_ASSOC_SHIFT;
|
|
|
|
|
|
|
|
vcpu->arch.tlbcfg[1] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
|
|
|
|
vcpu->arch.tlbcfg[1] |= params->tlb_sizes[1];
|
|
|
|
vcpu->arch.tlbcfg[1] |= params->tlb_ways[1] << TLBnCFG_ASSOC_SHIFT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvm_config_tlb *cfg)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
|
|
|
struct kvm_book3e_206_tlb_params params;
|
|
|
|
char *virt;
|
|
|
|
struct page **pages;
|
|
|
|
struct tlbe_priv *privs[2] = {};
|
2016-08-28 22:37:10 +07:00
|
|
|
u64 *g2h_bitmap;
|
2011-08-19 03:25:21 +07:00
|
|
|
size_t array_len;
|
|
|
|
u32 sets;
|
|
|
|
int num_pages, ret, i;
|
|
|
|
|
|
|
|
if (cfg->mmu_type != KVM_MMU_FSL_BOOKE_NOHV)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (copy_from_user(¶ms, (void __user *)(uintptr_t)cfg->params,
|
|
|
|
sizeof(params)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (params.tlb_sizes[1] > 64)
|
|
|
|
return -EINVAL;
|
|
|
|
if (params.tlb_ways[1] != params.tlb_sizes[1])
|
|
|
|
return -EINVAL;
|
|
|
|
if (params.tlb_sizes[2] != 0 || params.tlb_sizes[3] != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (params.tlb_ways[2] != 0 || params.tlb_ways[3] != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!is_power_of_2(params.tlb_ways[0]))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sets = params.tlb_sizes[0] >> ilog2(params.tlb_ways[0]);
|
|
|
|
if (!is_power_of_2(sets))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
array_len = params.tlb_sizes[0] + params.tlb_sizes[1];
|
|
|
|
array_len *= sizeof(struct kvm_book3e_206_tlb_entry);
|
|
|
|
|
|
|
|
if (cfg->array_len < array_len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
num_pages = DIV_ROUND_UP(cfg->array + array_len - 1, PAGE_SIZE) -
|
|
|
|
cfg->array / PAGE_SIZE;
|
2016-08-28 21:30:07 +07:00
|
|
|
pages = kmalloc_array(num_pages, sizeof(*pages), GFP_KERNEL);
|
2011-08-19 03:25:21 +07:00
|
|
|
if (!pages)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-05-14 07:17:11 +07:00
|
|
|
ret = get_user_pages_fast(cfg->array, num_pages, FOLL_WRITE, pages);
|
2011-08-19 03:25:21 +07:00
|
|
|
if (ret < 0)
|
2016-08-28 22:34:46 +07:00
|
|
|
goto free_pages;
|
2011-08-19 03:25:21 +07:00
|
|
|
|
|
|
|
if (ret != num_pages) {
|
|
|
|
num_pages = ret;
|
|
|
|
ret = -EFAULT;
|
2016-08-28 22:34:46 +07:00
|
|
|
goto put_pages;
|
2011-08-19 03:25:21 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
virt = vmap(pages, num_pages, VM_MAP, PAGE_KERNEL);
|
2012-08-05 06:52:33 +07:00
|
|
|
if (!virt) {
|
|
|
|
ret = -ENOMEM;
|
2016-08-28 22:34:46 +07:00
|
|
|
goto put_pages;
|
2012-08-05 06:52:33 +07:00
|
|
|
}
|
2011-08-19 03:25:21 +07:00
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
privs[0] = kcalloc(params.tlb_sizes[0], sizeof(*privs[0]), GFP_KERNEL);
|
2016-08-28 22:34:46 +07:00
|
|
|
if (!privs[0]) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto put_pages;
|
|
|
|
}
|
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
privs[1] = kcalloc(params.tlb_sizes[1], sizeof(*privs[1]), GFP_KERNEL);
|
2016-08-28 22:34:46 +07:00
|
|
|
if (!privs[1]) {
|
2012-08-05 06:52:33 +07:00
|
|
|
ret = -ENOMEM;
|
2016-08-28 22:34:46 +07:00
|
|
|
goto free_privs_first;
|
2012-08-05 06:52:33 +07:00
|
|
|
}
|
2011-08-19 03:25:21 +07:00
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
g2h_bitmap = kcalloc(params.tlb_sizes[1],
|
|
|
|
sizeof(*g2h_bitmap),
|
|
|
|
GFP_KERNEL);
|
2012-08-05 06:52:33 +07:00
|
|
|
if (!g2h_bitmap) {
|
|
|
|
ret = -ENOMEM;
|
2016-08-28 22:34:46 +07:00
|
|
|
goto free_privs_second;
|
2012-08-05 06:52:33 +07:00
|
|
|
}
|
2011-12-20 22:34:37 +07:00
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
free_gtlb(vcpu_e500);
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_priv[0] = privs[0];
|
|
|
|
vcpu_e500->gtlb_priv[1] = privs[1];
|
2011-12-20 22:34:37 +07:00
|
|
|
vcpu_e500->g2h_tlb1_map = g2h_bitmap;
|
2011-08-19 03:25:21 +07:00
|
|
|
|
|
|
|
vcpu_e500->gtlb_arch = (struct kvm_book3e_206_tlb_entry *)
|
|
|
|
(virt + (cfg->array & (PAGE_SIZE - 1)));
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_params[0].entries = params.tlb_sizes[0];
|
|
|
|
vcpu_e500->gtlb_params[1].entries = params.tlb_sizes[1];
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_offset[0] = 0;
|
|
|
|
vcpu_e500->gtlb_offset[1] = params.tlb_sizes[0];
|
|
|
|
|
2013-04-11 07:03:09 +07:00
|
|
|
/* Update vcpu's MMU geometry based on SW_TLB input */
|
|
|
|
vcpu_mmu_geometry_update(vcpu, ¶ms);
|
2011-08-19 03:25:21 +07:00
|
|
|
|
|
|
|
vcpu_e500->shared_tlb_pages = pages;
|
|
|
|
vcpu_e500->num_shared_tlb_pages = num_pages;
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_params[0].ways = params.tlb_ways[0];
|
|
|
|
vcpu_e500->gtlb_params[0].sets = sets;
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_params[1].ways = params.tlb_sizes[1];
|
|
|
|
vcpu_e500->gtlb_params[1].sets = 1;
|
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
kvmppc_recalc_tlb1map_range(vcpu_e500);
|
2011-08-19 03:25:21 +07:00
|
|
|
return 0;
|
2016-08-28 22:34:46 +07:00
|
|
|
free_privs_second:
|
2011-08-19 03:25:21 +07:00
|
|
|
kfree(privs[1]);
|
2016-08-28 22:34:46 +07:00
|
|
|
free_privs_first:
|
|
|
|
kfree(privs[0]);
|
|
|
|
put_pages:
|
2011-08-19 03:25:21 +07:00
|
|
|
for (i = 0; i < num_pages; i++)
|
|
|
|
put_page(pages[i]);
|
2016-08-28 22:34:46 +07:00
|
|
|
free_pages:
|
2011-08-19 03:25:21 +07:00
|
|
|
kfree(pages);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvm_dirty_tlb *dirty)
|
|
|
|
{
|
|
|
|
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
2012-03-23 01:39:11 +07:00
|
|
|
kvmppc_recalc_tlb1map_range(vcpu_e500);
|
2013-01-18 21:13:19 +07:00
|
|
|
kvmppc_core_flush_tlb(vcpu);
|
2011-08-19 03:25:21 +07:00
|
|
|
return 0;
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|
|
|
|
|
2013-04-11 07:03:09 +07:00
|
|
|
/* Vcpu's MMU default configuration */
|
|
|
|
static int vcpu_mmu_init(struct kvm_vcpu *vcpu,
|
|
|
|
struct kvmppc_e500_tlb_params *params)
|
|
|
|
{
|
|
|
|
/* Initialize RASIZE, PIDSIZE, NTLBS and MAVN fields with host values*/
|
|
|
|
vcpu->arch.mmucfg = mfspr(SPRN_MMUCFG) & ~MMUCFG_LPIDSIZE;
|
|
|
|
|
|
|
|
/* Initialize TLBnCFG fields with host values and SW_TLB geometry*/
|
|
|
|
vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) &
|
|
|
|
~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
|
|
|
|
vcpu->arch.tlbcfg[0] |= params[0].entries;
|
|
|
|
vcpu->arch.tlbcfg[0] |= params[0].ways << TLBnCFG_ASSOC_SHIFT;
|
|
|
|
|
|
|
|
vcpu->arch.tlbcfg[1] = mfspr(SPRN_TLB1CFG) &
|
|
|
|
~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
|
|
|
|
vcpu->arch.tlbcfg[1] |= params[1].entries;
|
|
|
|
vcpu->arch.tlbcfg[1] |= params[1].ways << TLBnCFG_ASSOC_SHIFT;
|
|
|
|
|
2013-04-11 07:03:10 +07:00
|
|
|
if (has_feature(vcpu, VCPU_FTR_MMU_V2)) {
|
|
|
|
vcpu->arch.tlbps[0] = mfspr(SPRN_TLB0PS);
|
|
|
|
vcpu->arch.tlbps[1] = mfspr(SPRN_TLB1PS);
|
2013-04-11 07:03:11 +07:00
|
|
|
|
2013-04-11 07:03:12 +07:00
|
|
|
vcpu->arch.mmucfg &= ~MMUCFG_LRAT;
|
|
|
|
|
2013-04-11 07:03:11 +07:00
|
|
|
/* Guest mmu emulation currently doesn't handle E.PT */
|
|
|
|
vcpu->arch.eptcfg = 0;
|
2013-04-11 07:03:12 +07:00
|
|
|
vcpu->arch.tlbcfg[0] &= ~TLBnCFG_PT;
|
|
|
|
vcpu->arch.tlbcfg[1] &= ~TLBnCFG_IND;
|
2013-04-11 07:03:10 +07:00
|
|
|
}
|
|
|
|
|
2013-04-11 07:03:09 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-04 05:23:10 +07:00
|
|
|
int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
|
{
|
2011-12-20 22:34:34 +07:00
|
|
|
struct kvm_vcpu *vcpu = &vcpu_e500->vcpu;
|
2011-08-19 03:25:21 +07:00
|
|
|
|
2013-01-11 21:22:45 +07:00
|
|
|
if (e500_mmu_host_init(vcpu_e500))
|
2016-09-13 03:33:53 +07:00
|
|
|
goto free_vcpu;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
vcpu_e500->gtlb_params[0].entries = KVM_E500_TLB0_SIZE;
|
|
|
|
vcpu_e500->gtlb_params[1].entries = KVM_E500_TLB1_SIZE;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2011-08-19 03:25:21 +07:00
|
|
|
vcpu_e500->gtlb_params[0].ways = KVM_E500_TLB0_WAY_NUM;
|
|
|
|
vcpu_e500->gtlb_params[0].sets =
|
|
|
|
KVM_E500_TLB0_SIZE / KVM_E500_TLB0_WAY_NUM;
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_params[1].ways = KVM_E500_TLB1_SIZE;
|
|
|
|
vcpu_e500->gtlb_params[1].sets = 1;
|
|
|
|
|
2016-08-28 23:40:08 +07:00
|
|
|
vcpu_e500->gtlb_arch = kmalloc_array(KVM_E500_TLB0_SIZE +
|
|
|
|
KVM_E500_TLB1_SIZE,
|
|
|
|
sizeof(*vcpu_e500->gtlb_arch),
|
|
|
|
GFP_KERNEL);
|
2011-08-19 03:25:21 +07:00
|
|
|
if (!vcpu_e500->gtlb_arch)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
vcpu_e500->gtlb_offset[0] = 0;
|
|
|
|
vcpu_e500->gtlb_offset[1] = KVM_E500_TLB0_SIZE;
|
2011-08-19 03:25:18 +07:00
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
vcpu_e500->gtlb_priv[0] = kcalloc(vcpu_e500->gtlb_params[0].entries,
|
|
|
|
sizeof(struct tlbe_ref),
|
2011-08-19 03:25:21 +07:00
|
|
|
GFP_KERNEL);
|
2011-08-19 03:25:18 +07:00
|
|
|
if (!vcpu_e500->gtlb_priv[0])
|
2016-09-13 03:33:53 +07:00
|
|
|
goto free_vcpu;
|
2011-08-19 03:25:18 +07:00
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
vcpu_e500->gtlb_priv[1] = kcalloc(vcpu_e500->gtlb_params[1].entries,
|
|
|
|
sizeof(struct tlbe_ref),
|
2011-08-19 03:25:21 +07:00
|
|
|
GFP_KERNEL);
|
2011-08-19 03:25:18 +07:00
|
|
|
if (!vcpu_e500->gtlb_priv[1])
|
2016-09-13 03:33:53 +07:00
|
|
|
goto free_vcpu;
|
2009-01-04 05:23:10 +07:00
|
|
|
|
2016-08-28 23:30:38 +07:00
|
|
|
vcpu_e500->g2h_tlb1_map = kcalloc(vcpu_e500->gtlb_params[1].entries,
|
|
|
|
sizeof(*vcpu_e500->g2h_tlb1_map),
|
2011-12-20 22:34:37 +07:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (!vcpu_e500->g2h_tlb1_map)
|
2016-09-13 03:33:53 +07:00
|
|
|
goto free_vcpu;
|
2011-12-20 22:34:37 +07:00
|
|
|
|
2013-04-11 07:03:09 +07:00
|
|
|
vcpu_mmu_init(vcpu, vcpu_e500->gtlb_params);
|
2010-01-22 18:36:53 +07:00
|
|
|
|
2012-03-23 01:39:11 +07:00
|
|
|
kvmppc_recalc_tlb1map_range(vcpu_e500);
|
2009-01-04 05:23:10 +07:00
|
|
|
return 0;
|
2016-09-13 03:33:53 +07:00
|
|
|
free_vcpu:
|
2011-08-19 03:25:21 +07:00
|
|
|
free_gtlb(vcpu_e500);
|
2009-01-04 05:23:10 +07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
|
|
|
|
{
|
2011-08-19 03:25:21 +07:00
|
|
|
free_gtlb(vcpu_e500);
|
2013-01-11 21:22:45 +07:00
|
|
|
e500_mmu_host_uninit(vcpu_e500);
|
2009-01-04 05:23:10 +07:00
|
|
|
}
|