/* * 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>
*/
if (idx >= 0) {
write_c0_entryhi(UNIQUE_ENTRYHI(idx));
write_c0_entrylo0(0);
write_c0_entrylo1(0);
mtc0_tlbw_hazard();
tlb_write_indexed();
tlbw_use_hazard();
}
return idx;
}
/* GuestID management */
/** * clear_root_gid() - Set GuestCtl1.RID for normal root operation.
*/ staticinlinevoid 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.
*/ staticinlinevoid set_root_gid_to_guest_gid(void)
{ unsignedint guestctl1;
/** * 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: Pointer 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, unsignedlong gva, unsignedlong *gpa)
{ unsignedlong o_entryhi, o_entrylo[2], o_pagemask; unsignedint o_index; unsignedlong entrylo[2], pagemask, pagemaskbit, pa; unsignedlong 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();
/* 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);
/** * 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, unsignedint index, unsignedint count)
{ unsignedint end = index + count; unsignedlong old_entryhi, old_entrylo0, old_entrylo1, old_pagemask; unsignedint 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);
/** * 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(conststruct kvm_mips_tlb *buf, unsignedint index, unsignedint count)
{ unsignedint end = index + count; unsignedlong 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();
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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.