forked from Minki/linux
7924bd4109
Formerly, we used to maintain a per-vcpu shadow TLB and on every entry to the guest would load this array into the hardware TLB. This consumed 1280 bytes of memory (64 entries of 16 bytes plus a struct page pointer each), and also required some assembly to loop over the array on every entry. Instead of saving a copy in memory, we can just store shadow mappings directly into the hardware TLB, accepting that the host kernel will clobber these as part of the normal 440 TLB round robin. When we do that we need less than half the memory, and we have decreased the exit handling time for all guest exits, at the cost of increased number of TLB misses because the host overwrites some guest entries. These savings will be increased on processors with larger TLBs or which implement intelligent flush instructions like tlbivax (which will avoid the need to walk arrays in software). In addition to that and to the code simplification, we have a greater chance of leaving other host userspace mappings in the TLB, instead of forcing all subsequent tasks to re-fault all their mappings. Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
96 lines
2.7 KiB
C
96 lines
2.7 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Copyright IBM Corp. 2007
|
|
*
|
|
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
|
|
*/
|
|
|
|
#ifndef __KVM_POWERPC_TLB_H__
|
|
#define __KVM_POWERPC_TLB_H__
|
|
|
|
#include <linux/kvm_host.h>
|
|
#include <asm/mmu-44x.h>
|
|
|
|
extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|
unsigned int pid, unsigned int as);
|
|
extern int kvmppc_44x_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
|
|
extern int kvmppc_44x_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
|
|
|
|
extern int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb,
|
|
u8 rc);
|
|
extern int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws);
|
|
|
|
/* TLB helper functions */
|
|
static inline unsigned int get_tlb_size(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return (tlbe->word0 >> 4) & 0xf;
|
|
}
|
|
|
|
static inline gva_t get_tlb_eaddr(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return tlbe->word0 & 0xfffffc00;
|
|
}
|
|
|
|
static inline gva_t get_tlb_bytes(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
unsigned int pgsize = get_tlb_size(tlbe);
|
|
return 1 << 10 << (pgsize << 1);
|
|
}
|
|
|
|
static inline gva_t get_tlb_end(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return get_tlb_eaddr(tlbe) + get_tlb_bytes(tlbe) - 1;
|
|
}
|
|
|
|
static inline u64 get_tlb_raddr(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
u64 word1 = tlbe->word1;
|
|
return ((word1 & 0xf) << 32) | (word1 & 0xfffffc00);
|
|
}
|
|
|
|
static inline unsigned int get_tlb_tid(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return tlbe->tid & 0xff;
|
|
}
|
|
|
|
static inline unsigned int get_tlb_ts(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return (tlbe->word0 >> 8) & 0x1;
|
|
}
|
|
|
|
static inline unsigned int get_tlb_v(const struct kvmppc_44x_tlbe *tlbe)
|
|
{
|
|
return (tlbe->word0 >> 9) & 0x1;
|
|
}
|
|
|
|
static inline unsigned int get_mmucr_stid(const struct kvm_vcpu *vcpu)
|
|
{
|
|
return vcpu->arch.mmucr & 0xff;
|
|
}
|
|
|
|
static inline unsigned int get_mmucr_sts(const struct kvm_vcpu *vcpu)
|
|
{
|
|
return (vcpu->arch.mmucr >> 16) & 0x1;
|
|
}
|
|
|
|
static inline gpa_t tlb_xlate(struct kvmppc_44x_tlbe *tlbe, gva_t eaddr)
|
|
{
|
|
unsigned int pgmask = get_tlb_bytes(tlbe) - 1;
|
|
|
|
return get_tlb_raddr(tlbe) | (eaddr & pgmask);
|
|
}
|
|
|
|
#endif /* __KVM_POWERPC_TLB_H__ */
|