2012-11-21 18:34:05 -08:00
/*
2014-06-26 12:11:34 -07:00
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* KVM / MIPS TLB handling , this file is part of the Linux host kernel so that
* TLB handlers run from KSEG0
*
* Copyright ( C ) 2012 MIPS Technologies , Inc . All rights reserved .
* Authors : Sanjay Lal < sanjayl @ kymasys . com >
*/
2012-11-21 18:34:05 -08:00
# include <linux/sched.h>
# include <linux/smp.h>
# include <linux/mm.h>
# include <linux/delay.h>
2016-06-09 14:19:10 +01:00
# include <linux/export.h>
2012-11-21 18:34:05 -08:00
# include <linux/kvm_host.h>
2013-05-18 06:54:24 -07:00
# include <linux/srcu.h>
2012-11-21 18:34:05 -08:00
# include <asm/cpu.h>
# include <asm/bootinfo.h>
2020-05-23 15:56:39 +08:00
# include <asm/mipsregs.h>
2012-11-21 18:34:05 -08:00
# include <asm/mmu_context.h>
# include <asm/cacheflush.h>
2014-01-17 12:01:30 +00:00
# include <asm/tlb.h>
2016-06-09 14:19:16 +01:00
# include <asm/tlbdebug.h>
2012-11-21 18:34:05 -08:00
# undef CONFIG_MIPS_MT
# include <asm/r4kcache.h>
# define CONFIG_MIPS_MT
# define KVM_GUEST_PC_TLB 0
# define KVM_GUEST_SP_TLB 1
2017-03-14 10:15:27 +00:00
# ifdef CONFIG_KVM_MIPS_VZ
2017-03-14 10:15:31 +00:00
unsigned long GUESTID_MASK ;
EXPORT_SYMBOL_GPL ( GUESTID_MASK ) ;
unsigned long GUESTID_FIRST_VERSION ;
EXPORT_SYMBOL_GPL ( GUESTID_FIRST_VERSION ) ;
unsigned long GUESTID_VERSION_MASK ;
EXPORT_SYMBOL_GPL ( GUESTID_VERSION_MASK ) ;
2017-03-14 10:15:27 +00:00
static u32 kvm_mips_get_root_asid ( struct kvm_vcpu * vcpu )
{
struct mm_struct * gpa_mm = & vcpu - > kvm - > arch . gpa_mm ;
if ( cpu_has_guestid )
return 0 ;
else
return cpu_asid ( smp_processor_id ( ) , gpa_mm ) ;
}
# endif
2016-06-09 14:19:10 +01:00
static u32 kvm_mips_get_kernel_asid ( struct kvm_vcpu * vcpu )
2012-11-21 18:34:05 -08:00
{
2016-10-11 23:14:39 +01:00
struct mm_struct * kern_mm = & vcpu - > arch . guest_kernel_mm ;
2016-05-06 14:36:23 +01:00
int cpu = smp_processor_id ( ) ;
2016-10-11 23:14:39 +01:00
return cpu_asid ( cpu , kern_mm ) ;
2012-11-21 18:34:05 -08:00
}
2016-06-09 14:19:10 +01:00
static u32 kvm_mips_get_user_asid ( struct kvm_vcpu * vcpu )
2012-11-21 18:34:05 -08:00
{
2016-10-11 23:14:39 +01:00
struct mm_struct * user_mm = & vcpu - > arch . guest_user_mm ;
2016-05-06 14:36:23 +01:00
int cpu = smp_processor_id ( ) ;
2016-10-11 23:14:39 +01:00
return cpu_asid ( cpu , user_mm ) ;
2012-11-21 18:34:05 -08:00
}
2014-06-26 12:11:34 -07:00
/* Structure defining an tlb entry data set. */
2012-11-21 18:34:05 -08:00
void kvm_mips_dump_host_tlbs ( void )
{
unsigned long flags ;
local_irq_save ( flags ) ;
2014-06-26 12:11:35 -07:00
kvm_info ( " HOST TLBs: \n " ) ;
2016-06-09 14:19:16 +01:00
dump_tlb_regs ( ) ;
pr_info ( " \n " ) ;
dump_tlb_all ( ) ;
2012-11-21 18:34:05 -08:00
local_irq_restore ( flags ) ;
}
2015-12-16 23:49:30 +00:00
EXPORT_SYMBOL_GPL ( kvm_mips_dump_host_tlbs ) ;
2012-11-21 18:34:05 -08:00
void kvm_mips_dump_guest_tlbs ( struct kvm_vcpu * vcpu )
{
struct mips_coproc * cop0 = vcpu - > arch . cop0 ;
struct kvm_mips_tlb tlb ;
int i ;
2014-06-26 12:11:35 -07:00
kvm_info ( " Guest TLBs: \n " ) ;
kvm_info ( " Guest EntryHi: %#lx \n " , kvm_read_c0_guest_entryhi ( cop0 ) ) ;
2012-11-21 18:34:05 -08:00
for ( i = 0 ; i < KVM_MIPS_GUEST_TLB_SIZE ; i + + ) {
tlb = vcpu - > arch . guest_tlb [ i ] ;
2014-06-26 12:11:35 -07:00
kvm_info ( " TLB%c%3d Hi 0x%08lx " ,
2016-06-09 14:19:19 +01:00
( tlb . tlb_lo [ 0 ] | tlb . tlb_lo [ 1 ] ) & ENTRYLO_V
2016-06-09 14:19:17 +01:00
? ' ' : ' * ' ,
2014-06-26 12:11:35 -07:00
i , tlb . tlb_hi ) ;
2016-06-09 14:19:08 +01:00
kvm_info ( " Lo0=0x%09llx %c%c attr %lx " ,
2016-06-09 14:19:17 +01:00
( u64 ) mips3_tlbpfn_to_paddr ( tlb . tlb_lo [ 0 ] ) ,
2016-06-09 14:19:19 +01:00
( tlb . tlb_lo [ 0 ] & ENTRYLO_D ) ? ' D ' : ' ' ,
( tlb . tlb_lo [ 0 ] & ENTRYLO_G ) ? ' G ' : ' ' ,
( tlb . tlb_lo [ 0 ] & ENTRYLO_C ) > > ENTRYLO_C_SHIFT ) ;
2016-06-09 14:19:08 +01:00
kvm_info ( " Lo1=0x%09llx %c%c attr %lx sz=%lx \n " ,
2016-06-09 14:19:17 +01:00
( u64 ) mips3_tlbpfn_to_paddr ( tlb . tlb_lo [ 1 ] ) ,
2016-06-09 14:19:19 +01:00
( tlb . tlb_lo [ 1 ] & ENTRYLO_D ) ? ' D ' : ' ' ,
( tlb . tlb_lo [ 1 ] & ENTRYLO_G ) ? ' G ' : ' ' ,
( tlb . tlb_lo [ 1 ] & ENTRYLO_C ) > > ENTRYLO_C_SHIFT ,
tlb . tlb_mask ) ;
2012-11-21 18:34:05 -08:00
}
}
2015-12-16 23:49:30 +00:00
EXPORT_SYMBOL_GPL ( kvm_mips_dump_guest_tlbs ) ;
2012-11-21 18:34:05 -08:00
int kvm_mips_guest_tlb_lookup ( struct kvm_vcpu * vcpu , unsigned long entryhi )
{
int i ;
int index = - 1 ;
struct kvm_mips_tlb * tlb = vcpu - > arch . guest_tlb ;
for ( i = 0 ; i < KVM_MIPS_GUEST_TLB_SIZE ; i + + ) {
2014-06-26 12:11:34 -07:00
if ( TLB_HI_VPN2_HIT ( tlb [ i ] , entryhi ) & &
TLB_HI_ASID_HIT ( tlb [ i ] , entryhi ) ) {
2012-11-21 18:34:05 -08:00
index = i ;
break ;
}
}
kvm_debug ( " %s: entryhi: %#lx, index: %d lo0: %#lx, lo1: %#lx \n " ,
2016-06-09 14:19:17 +01:00
__func__ , entryhi , index , tlb [ i ] . tlb_lo [ 0 ] , tlb [ i ] . tlb_lo [ 1 ] ) ;
2012-11-21 18:34:05 -08:00
return index ;
}
2015-12-16 23:49:30 +00:00
EXPORT_SYMBOL_GPL ( kvm_mips_guest_tlb_lookup ) ;
2012-11-21 18:34:05 -08:00
2016-10-08 00:15:52 +01:00
static int _kvm_mips_host_tlb_inv ( unsigned long entryhi )
2012-11-21 18:34:05 -08:00
{
int idx ;
2016-10-08 00:15:52 +01:00
write_c0_entryhi ( entryhi ) ;
2012-11-21 18:34:05 -08:00
mtc0_tlbw_hazard ( ) ;
tlb_probe ( ) ;
tlb_probe_hazard ( ) ;
idx = read_c0_index ( ) ;
if ( idx > = current_cpu_data . tlbsize )
BUG ( ) ;
2016-10-07 22:01:05 +01:00
if ( idx > = 0 ) {
2012-11-21 18:34:05 -08:00
write_c0_entryhi ( UNIQUE_ENTRYHI ( idx ) ) ;
write_c0_entrylo0 ( 0 ) ;
write_c0_entrylo1 ( 0 ) ;
mtc0_tlbw_hazard ( ) ;
tlb_write_indexed ( ) ;
2016-06-09 14:19:15 +01:00
tlbw_use_hazard ( ) ;
2012-11-21 18:34:05 -08:00
}
2016-10-08 00:15:52 +01:00
return idx ;
}
int kvm_mips_host_tlb_inv ( struct kvm_vcpu * vcpu , unsigned long va ,
bool user , bool kernel )
{
KVM: MIPS: Fix maybe-uninitialized build failure
This commit fixes a "maybe-uninitialized" build failure in
arch/mips/kvm/tlb.c when KVM, DYNAMIC_DEBUG and JUMP_LABEL are all
enabled. The failure is:
In file included from ./include/linux/printk.h:329:0,
from ./include/linux/kernel.h:13,
from ./include/asm-generic/bug.h:15,
from ./arch/mips/include/asm/bug.h:41,
from ./include/linux/bug.h:4,
from ./include/linux/thread_info.h:11,
from ./include/asm-generic/current.h:4,
from ./arch/mips/include/generated/asm/current.h:1,
from ./include/linux/sched.h:11,
from arch/mips/kvm/tlb.c:13:
arch/mips/kvm/tlb.c: In function ‘kvm_mips_host_tlb_inv’:
./include/linux/dynamic_debug.h:126:3: error: ‘idx_kernel’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
__dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
^~~~~~~~~~~~~~~~~~
arch/mips/kvm/tlb.c:169:16: note: ‘idx_kernel’ was declared here
int idx_user, idx_kernel;
^~~~~~~~~~
There is a similar error relating to "idx_user". Both errors were
observed with GCC 6.
As far as I can tell, it is impossible for either idx_user or idx_kernel
to be uninitialized when they are later read in the calls to kvm_debug,
but to satisfy the compiler, add zero initializers to both variables.
Signed-off-by: James Cowgill <James.Cowgill@imgtec.com>
Fixes: 57e3869cfaae ("KVM: MIPS/TLB: Generalise host TLB invalidate to kernel ASID")
Cc: <stable@vger.kernel.org> # 4.11+
Acked-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
2017-06-20 10:57:51 +01:00
/*
* Initialize idx_user and idx_kernel to workaround bogus
* maybe - initialized warning when using GCC 6.
*/
int idx_user = 0 , idx_kernel = 0 ;
2016-10-08 00:15:52 +01:00
unsigned long flags , old_entryhi ;
local_irq_save ( flags ) ;
old_entryhi = read_c0_entryhi ( ) ;
if ( user )
idx_user = _kvm_mips_host_tlb_inv ( ( va & VPN2_MASK ) |
kvm_mips_get_user_asid ( vcpu ) ) ;
if ( kernel )
idx_kernel = _kvm_mips_host_tlb_inv ( ( va & VPN2_MASK ) |
kvm_mips_get_kernel_asid ( vcpu ) ) ;
2012-11-21 18:34:05 -08:00
write_c0_entryhi ( old_entryhi ) ;
mtc0_tlbw_hazard ( ) ;
local_irq_restore ( flags ) ;
2017-03-14 10:25:46 +00:00
/*
* We don ' t want to get reserved instruction exceptions for missing tlb
* entries .
*/
if ( cpu_has_vtag_icache )
flush_icache_all ( ) ;
2016-10-08 00:15:52 +01:00
if ( user & & idx_user > = 0 )
kvm_debug ( " %s: Invalidated guest user entryhi %#lx @ idx %d \n " ,
__func__ , ( va & VPN2_MASK ) |
kvm_mips_get_user_asid ( vcpu ) , idx_user ) ;
if ( kernel & & idx_kernel > = 0 )
kvm_debug ( " %s: Invalidated guest kernel entryhi %#lx @ idx %d \n " ,
__func__ , ( va & VPN2_MASK ) |
kvm_mips_get_kernel_asid ( vcpu ) , idx_kernel ) ;
2012-11-21 18:34:05 -08:00
return 0 ;
}
2015-12-16 23:49:30 +00:00
EXPORT_SYMBOL_GPL ( kvm_mips_host_tlb_inv ) ;
2012-11-21 18:34:05 -08:00
2017-03-14 10:15:27 +00:00
# ifdef CONFIG_KVM_MIPS_VZ
/* GuestID management */
/**
* clear_root_gid ( ) - Set GuestCtl1 . RID for normal root operation .
*/
static inline void clear_root_gid ( void )
{
if ( cpu_has_guestid ) {
clear_c0_guestctl1 ( MIPS_GCTL1_RID ) ;
mtc0_tlbw_hazard ( ) ;
}
}
/**
* set_root_gid_to_guest_gid ( ) - Set GuestCtl1 . RID to match GuestCtl1 . ID .
*
* Sets the root GuestID to match the current guest GuestID , for TLB operation
* on the GPA - > RPA mappings in the root TLB .
*
* The caller must be sure to disable HTW while the root GID is set , and
* possibly longer if TLB registers are modified .
*/
static inline void set_root_gid_to_guest_gid ( void )
{
unsigned int guestctl1 ;
if ( cpu_has_guestid ) {
back_to_back_c0_hazard ( ) ;
guestctl1 = read_c0_guestctl1 ( ) ;
guestctl1 = ( guestctl1 & ~ MIPS_GCTL1_RID ) |
( ( guestctl1 & MIPS_GCTL1_ID ) > > MIPS_GCTL1_ID_SHIFT )
< < MIPS_GCTL1_RID_SHIFT ;
write_c0_guestctl1 ( guestctl1 ) ;
mtc0_tlbw_hazard ( ) ;
}
}
int kvm_vz_host_tlb_inv ( struct kvm_vcpu * vcpu , unsigned long va )
{
int idx ;
unsigned long flags , old_entryhi ;
local_irq_save ( flags ) ;
htw_stop ( ) ;
/* Set root GuestID for root probe and write of guest TLB entry */
set_root_gid_to_guest_gid ( ) ;
old_entryhi = read_c0_entryhi ( ) ;
idx = _kvm_mips_host_tlb_inv ( ( va & VPN2_MASK ) |
kvm_mips_get_root_asid ( vcpu ) ) ;
write_c0_entryhi ( old_entryhi ) ;
clear_root_gid ( ) ;
mtc0_tlbw_hazard ( ) ;
htw_start ( ) ;
local_irq_restore ( flags ) ;
2017-03-14 10:25:46 +00:00
/*
* We don ' t want to get reserved instruction exceptions for missing tlb
* entries .
*/
if ( cpu_has_vtag_icache )
flush_icache_all ( ) ;
2017-03-14 10:15:27 +00:00
if ( idx > 0 )
kvm_debug ( " %s: Invalidated root entryhi %#lx @ idx %d \n " ,
__func__ , ( va & VPN2_MASK ) |
kvm_mips_get_root_asid ( vcpu ) , idx ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_host_tlb_inv ) ;
/**
* kvm_vz_guest_tlb_lookup ( ) - Lookup a guest VZ TLB mapping .
* @ vcpu : KVM VCPU pointer .
* @ gpa : Guest virtual address in a TLB mapped guest segment .
* @ gpa : Ponter to output guest physical address it maps to .
*
* Converts a guest virtual address in a guest TLB mapped segment to a guest
* physical address , by probing the guest TLB .
*
* Returns : 0 if guest TLB mapping exists for @ gva . * @ gpa will have been
* written .
* - EFAULT if no guest TLB mapping exists for @ gva . * @ gpa may not
* have been written .
*/
int kvm_vz_guest_tlb_lookup ( struct kvm_vcpu * vcpu , unsigned long gva ,
unsigned long * gpa )
{
unsigned long o_entryhi , o_entrylo [ 2 ] , o_pagemask ;
unsigned int o_index ;
unsigned long entrylo [ 2 ] , pagemask , pagemaskbit , pa ;
unsigned long flags ;
int index ;
/* Probe the guest TLB for a mapping */
local_irq_save ( flags ) ;
/* Set root GuestID for root probe of guest TLB entry */
htw_stop ( ) ;
set_root_gid_to_guest_gid ( ) ;
o_entryhi = read_gc0_entryhi ( ) ;
o_index = read_gc0_index ( ) ;
write_gc0_entryhi ( ( o_entryhi & 0x3ff ) | ( gva & ~ 0xfffl ) ) ;
mtc0_tlbw_hazard ( ) ;
guest_tlb_probe ( ) ;
tlb_probe_hazard ( ) ;
index = read_gc0_index ( ) ;
if ( index < 0 ) {
/* No match, fail */
write_gc0_entryhi ( o_entryhi ) ;
write_gc0_index ( o_index ) ;
clear_root_gid ( ) ;
htw_start ( ) ;
local_irq_restore ( flags ) ;
return - EFAULT ;
}
/* Match! read the TLB entry */
o_entrylo [ 0 ] = read_gc0_entrylo0 ( ) ;
o_entrylo [ 1 ] = read_gc0_entrylo1 ( ) ;
o_pagemask = read_gc0_pagemask ( ) ;
mtc0_tlbr_hazard ( ) ;
guest_tlb_read ( ) ;
tlb_read_hazard ( ) ;
entrylo [ 0 ] = read_gc0_entrylo0 ( ) ;
entrylo [ 1 ] = read_gc0_entrylo1 ( ) ;
pagemask = ~ read_gc0_pagemask ( ) & ~ 0x1fffl ;
write_gc0_entryhi ( o_entryhi ) ;
write_gc0_index ( o_index ) ;
write_gc0_entrylo0 ( o_entrylo [ 0 ] ) ;
write_gc0_entrylo1 ( o_entrylo [ 1 ] ) ;
write_gc0_pagemask ( o_pagemask ) ;
clear_root_gid ( ) ;
htw_start ( ) ;
local_irq_restore ( flags ) ;
/* Select one of the EntryLo values and interpret the GPA */
pagemaskbit = ( pagemask ^ ( pagemask & ( pagemask - 1 ) ) ) > > 1 ;
pa = entrylo [ ! ! ( gva & pagemaskbit ) ] ;
/*
* TLB entry may have become invalid since TLB probe if physical FTLB
* entries are shared between threads ( e . g . I6400 ) .
*/
if ( ! ( pa & ENTRYLO_V ) )
return - EFAULT ;
/*
* Note , this doesn ' t take guest MIPS32 XPA into account , where PFN is
* split with XI / RI in the middle .
*/
pa = ( pa < < 6 ) & ~ 0xfffl ;
pa | = gva & ~ ( pagemask | pagemaskbit ) ;
* gpa = pa ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_guest_tlb_lookup ) ;
/**
* kvm_vz_local_flush_roottlb_all_guests ( ) - Flush all root TLB entries for
* guests .
*
* Invalidate all entries in root tlb which are GPA mappings .
*/
void kvm_vz_local_flush_roottlb_all_guests ( void )
{
unsigned long flags ;
unsigned long old_entryhi , old_pagemask , old_guestctl1 ;
int entry ;
if ( WARN_ON ( ! cpu_has_guestid ) )
return ;
local_irq_save ( flags ) ;
htw_stop ( ) ;
/* TLBR may clobber EntryHi.ASID, PageMask, and GuestCtl1.RID */
old_entryhi = read_c0_entryhi ( ) ;
old_pagemask = read_c0_pagemask ( ) ;
old_guestctl1 = read_c0_guestctl1 ( ) ;
/*
* Invalidate guest entries in root TLB while leaving root entries
* intact when possible .
*/
for ( entry = 0 ; entry < current_cpu_data . tlbsize ; entry + + ) {
write_c0_index ( entry ) ;
mtc0_tlbw_hazard ( ) ;
tlb_read ( ) ;
tlb_read_hazard ( ) ;
/* Don't invalidate non-guest (RVA) mappings in the root TLB */
if ( ! ( read_c0_guestctl1 ( ) & MIPS_GCTL1_RID ) )
continue ;
/* Make sure all entries differ. */
write_c0_entryhi ( UNIQUE_ENTRYHI ( entry ) ) ;
write_c0_entrylo0 ( 0 ) ;
write_c0_entrylo1 ( 0 ) ;
write_c0_guestctl1 ( 0 ) ;
mtc0_tlbw_hazard ( ) ;
tlb_write_indexed ( ) ;
}
write_c0_entryhi ( old_entryhi ) ;
write_c0_pagemask ( old_pagemask ) ;
write_c0_guestctl1 ( old_guestctl1 ) ;
tlbw_use_hazard ( ) ;
htw_start ( ) ;
local_irq_restore ( flags ) ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_local_flush_roottlb_all_guests ) ;
/**
* kvm_vz_local_flush_guesttlb_all ( ) - Flush all guest TLB entries .
*
* Invalidate all entries in guest tlb irrespective of guestid .
*/
void kvm_vz_local_flush_guesttlb_all ( void )
{
unsigned long flags ;
unsigned long old_index ;
unsigned long old_entryhi ;
unsigned long old_entrylo [ 2 ] ;
unsigned long old_pagemask ;
int entry ;
2017-03-14 10:25:48 +00:00
u64 cvmmemctl2 = 0 ;
2017-03-14 10:15:27 +00:00
local_irq_save ( flags ) ;
/* Preserve all clobbered guest registers */
old_index = read_gc0_index ( ) ;
old_entryhi = read_gc0_entryhi ( ) ;
old_entrylo [ 0 ] = read_gc0_entrylo0 ( ) ;
old_entrylo [ 1 ] = read_gc0_entrylo1 ( ) ;
old_pagemask = read_gc0_pagemask ( ) ;
2017-03-14 10:25:48 +00:00
switch ( current_cpu_type ( ) ) {
case CPU_CAVIUM_OCTEON3 :
/* Inhibit machine check due to multiple matching TLB entries */
cvmmemctl2 = read_c0_cvmmemctl2 ( ) ;
cvmmemctl2 | = CVMMEMCTL2_INHIBITTS ;
write_c0_cvmmemctl2 ( cvmmemctl2 ) ;
break ;
2020-04-28 14:32:45 +08:00
}
2017-03-14 10:25:48 +00:00
2017-03-14 10:15:27 +00:00
/* Invalidate guest entries in guest TLB */
write_gc0_entrylo0 ( 0 ) ;
write_gc0_entrylo1 ( 0 ) ;
write_gc0_pagemask ( 0 ) ;
for ( entry = 0 ; entry < current_cpu_data . guest . tlbsize ; entry + + ) {
/* Make sure all entries differ. */
write_gc0_index ( entry ) ;
write_gc0_entryhi ( UNIQUE_GUEST_ENTRYHI ( entry ) ) ;
mtc0_tlbw_hazard ( ) ;
guest_tlb_write_indexed ( ) ;
}
2017-03-14 10:25:48 +00:00
if ( cvmmemctl2 ) {
cvmmemctl2 & = ~ CVMMEMCTL2_INHIBITTS ;
write_c0_cvmmemctl2 ( cvmmemctl2 ) ;
2020-04-28 14:32:45 +08:00
}
2017-03-14 10:25:48 +00:00
2017-03-14 10:15:27 +00:00
write_gc0_index ( old_index ) ;
write_gc0_entryhi ( old_entryhi ) ;
write_gc0_entrylo0 ( old_entrylo [ 0 ] ) ;
write_gc0_entrylo1 ( old_entrylo [ 1 ] ) ;
write_gc0_pagemask ( old_pagemask ) ;
tlbw_use_hazard ( ) ;
local_irq_restore ( flags ) ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_local_flush_guesttlb_all ) ;
/**
* kvm_vz_save_guesttlb ( ) - Save a range of guest TLB entries .
* @ buf : Buffer to write TLB entries into .
* @ index : Start index .
* @ count : Number of entries to save .
*
* Save a range of guest TLB entries . The caller must ensure interrupts are
* disabled .
*/
void kvm_vz_save_guesttlb ( struct kvm_mips_tlb * buf , unsigned int index ,
unsigned int count )
{
unsigned int end = index + count ;
unsigned long old_entryhi , old_entrylo0 , old_entrylo1 , old_pagemask ;
unsigned int guestctl1 = 0 ;
int old_index , i ;
/* Save registers we're about to clobber */
old_index = read_gc0_index ( ) ;
old_entryhi = read_gc0_entryhi ( ) ;
old_entrylo0 = read_gc0_entrylo0 ( ) ;
old_entrylo1 = read_gc0_entrylo1 ( ) ;
old_pagemask = read_gc0_pagemask ( ) ;
/* Set root GuestID for root probe */
htw_stop ( ) ;
set_root_gid_to_guest_gid ( ) ;
if ( cpu_has_guestid )
guestctl1 = read_c0_guestctl1 ( ) ;
/* Read each entry from guest TLB */
for ( i = index ; i < end ; + + i , + + buf ) {
write_gc0_index ( i ) ;
mtc0_tlbr_hazard ( ) ;
guest_tlb_read ( ) ;
tlb_read_hazard ( ) ;
if ( cpu_has_guestid & &
( read_c0_guestctl1 ( ) ^ guestctl1 ) & MIPS_GCTL1_RID ) {
/* Entry invalid or belongs to another guest */
buf - > tlb_hi = UNIQUE_GUEST_ENTRYHI ( i ) ;
buf - > tlb_lo [ 0 ] = 0 ;
buf - > tlb_lo [ 1 ] = 0 ;
buf - > tlb_mask = 0 ;
} else {
/* Entry belongs to the right guest */
buf - > tlb_hi = read_gc0_entryhi ( ) ;
buf - > tlb_lo [ 0 ] = read_gc0_entrylo0 ( ) ;
buf - > tlb_lo [ 1 ] = read_gc0_entrylo1 ( ) ;
buf - > tlb_mask = read_gc0_pagemask ( ) ;
}
}
/* Clear root GuestID again */
clear_root_gid ( ) ;
htw_start ( ) ;
/* Restore clobbered registers */
write_gc0_index ( old_index ) ;
write_gc0_entryhi ( old_entryhi ) ;
write_gc0_entrylo0 ( old_entrylo0 ) ;
write_gc0_entrylo1 ( old_entrylo1 ) ;
write_gc0_pagemask ( old_pagemask ) ;
tlbw_use_hazard ( ) ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_save_guesttlb ) ;
/**
* kvm_vz_load_guesttlb ( ) - Save a range of guest TLB entries .
* @ buf : Buffer to read TLB entries from .
* @ index : Start index .
* @ count : Number of entries to load .
*
* Load a range of guest TLB entries . The caller must ensure interrupts are
* disabled .
*/
void kvm_vz_load_guesttlb ( const struct kvm_mips_tlb * buf , unsigned int index ,
unsigned int count )
{
unsigned int end = index + count ;
unsigned long old_entryhi , old_entrylo0 , old_entrylo1 , old_pagemask ;
int old_index , i ;
/* Save registers we're about to clobber */
old_index = read_gc0_index ( ) ;
old_entryhi = read_gc0_entryhi ( ) ;
old_entrylo0 = read_gc0_entrylo0 ( ) ;
old_entrylo1 = read_gc0_entrylo1 ( ) ;
old_pagemask = read_gc0_pagemask ( ) ;
/* Set root GuestID for root probe */
htw_stop ( ) ;
set_root_gid_to_guest_gid ( ) ;
/* Write each entry to guest TLB */
for ( i = index ; i < end ; + + i , + + buf ) {
write_gc0_index ( i ) ;
write_gc0_entryhi ( buf - > tlb_hi ) ;
write_gc0_entrylo0 ( buf - > tlb_lo [ 0 ] ) ;
write_gc0_entrylo1 ( buf - > tlb_lo [ 1 ] ) ;
write_gc0_pagemask ( buf - > tlb_mask ) ;
mtc0_tlbw_hazard ( ) ;
guest_tlb_write_indexed ( ) ;
}
/* Clear root GuestID again */
clear_root_gid ( ) ;
htw_start ( ) ;
/* Restore clobbered registers */
write_gc0_index ( old_index ) ;
write_gc0_entryhi ( old_entryhi ) ;
write_gc0_entrylo0 ( old_entrylo0 ) ;
write_gc0_entrylo1 ( old_entrylo1 ) ;
write_gc0_pagemask ( old_pagemask ) ;
tlbw_use_hazard ( ) ;
}
EXPORT_SYMBOL_GPL ( kvm_vz_load_guesttlb ) ;
2020-05-23 15:56:39 +08:00
# ifdef CONFIG_CPU_LOONGSON64
void kvm_loongson_clear_guest_vtlb ( void )
{
int idx = read_gc0_index ( ) ;
/* Set root GuestID for root probe and write of guest TLB entry */
set_root_gid_to_guest_gid ( ) ;
write_gc0_index ( 0 ) ;
guest_tlbinvf ( ) ;
write_gc0_index ( idx ) ;
clear_root_gid ( ) ;
set_c0_diag ( LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB ) ;
}
EXPORT_SYMBOL_GPL ( kvm_loongson_clear_guest_vtlb ) ;
void kvm_loongson_clear_guest_ftlb ( void )
{
int i ;
int idx = read_gc0_index ( ) ;
/* Set root GuestID for root probe and write of guest TLB entry */
set_root_gid_to_guest_gid ( ) ;
for ( i = current_cpu_data . tlbsizevtlb ;
i < ( current_cpu_data . tlbsizevtlb +
current_cpu_data . tlbsizeftlbsets ) ;
i + + ) {
write_gc0_index ( i ) ;
guest_tlbinvf ( ) ;
}
write_gc0_index ( idx ) ;
clear_root_gid ( ) ;
set_c0_diag ( LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB ) ;
}
EXPORT_SYMBOL_GPL ( kvm_loongson_clear_guest_ftlb ) ;
# endif
2017-03-14 10:15:27 +00:00
# endif
2016-11-15 00:06:05 +00:00
/**
* kvm_mips_suspend_mm ( ) - Suspend the active mm .
* @ cpu The CPU we ' re running on .
*
* Suspend the active_mm , ready for a switch to a KVM guest virtual address
* space . This is left active for the duration of guest context , including time
* with interrupts enabled , so we need to be careful not to confuse e . g . cache
* management IPIs .
*
* kvm_mips_resume_mm ( ) should be called before context switching to a different
* process so we don ' t need to worry about reference counting .
*
* This needs to be in static kernel code to avoid exporting init_mm .
*/
void kvm_mips_suspend_mm ( int cpu )
{
cpumask_clear_cpu ( cpu , mm_cpumask ( current - > active_mm ) ) ;
current - > active_mm = & init_mm ;
}
EXPORT_SYMBOL_GPL ( kvm_mips_suspend_mm ) ;
/**
* kvm_mips_resume_mm ( ) - Resume the current process mm .
* @ cpu The CPU we ' re running on .
*
* Resume the mm of the current process , after a switch back from a KVM guest
* virtual address space ( see kvm_mips_suspend_mm ( ) ) .
*/
void kvm_mips_resume_mm ( int cpu )
{
cpumask_set_cpu ( cpu , mm_cpumask ( current - > mm ) ) ;
current - > active_mm = current - > mm ;
}
EXPORT_SYMBOL_GPL ( kvm_mips_resume_mm ) ;