arch/powerpc/kvm/book3s_64_mmu.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kvm/book3s_64_mmu.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kvm/book3s_64_mmu.c
Extension
.c
Size
15625 bytes
Lines
671
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if ((pte0 & v_mask) == v_val) {
			/* If large page bit is set, check pgsize encoding */
			if (slbe->large &&
			    (vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE)) {
				pgsize = decode_pagesize(slbe, pte1);
				if (pgsize < 0)
					continue;
			}
			found = true;
			break;
		}
	}

	if (!found) {
		if (second)
			goto no_page_found;
		v_val |= HPTE_V_SECONDARY;
		second = true;
		goto do_second;
	}

	r = be64_to_cpu(pteg[i+1]);
	pp = (r & HPTE_R_PP) | key;
	if (r & HPTE_R_PP0)
		pp |= 8;

	gpte->eaddr = eaddr;
	gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);

	eaddr_mask = (1ull << mmu_pagesize(pgsize)) - 1;
	gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask);
	gpte->page_size = pgsize;
	gpte->may_execute = ((r & HPTE_R_N) ? false : true);
	if (unlikely(vcpu->arch.disable_kernel_nx) &&
	    !(kvmppc_get_msr(vcpu) & MSR_PR))
		gpte->may_execute = true;
	gpte->may_read = false;
	gpte->may_write = false;
	gpte->wimg = r & HPTE_R_WIMG;

	switch (pp) {
	case 0:
	case 1:
	case 2:
	case 6:
		gpte->may_write = true;
		fallthrough;
	case 3:
	case 5:
	case 7:
	case 10:
		gpte->may_read = true;
		break;
	}

	dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
		"-> 0x%lx\n",
		eaddr, avpn, gpte->vpage, gpte->raddr);

	/* Update PTE R and C bits, so the guest's swapper knows we used the
	 * page */
	if (gpte->may_read && !(r & HPTE_R_R)) {
		/*
		 * Set the accessed flag.
		 * We have to write this back with a single byte write
		 * because another vcpu may be accessing this on
		 * non-PAPR platforms such as mac99, and this is
		 * what real hardware does.
		 */
                char __user *addr = (char __user *) (ptegp + (i + 1) * sizeof(u64));
		r |= HPTE_R_R;
		put_user(r >> 8, addr + 6);
	}
	if (iswrite && gpte->may_write && !(r & HPTE_R_C)) {
		/* Set the dirty flag */
		/* Use a single byte write */
                char __user *addr = (char __user *) (ptegp + (i + 1) * sizeof(u64));
		r |= HPTE_R_C;
		put_user(r, addr + 7);
	}

	mutex_unlock(&vcpu->kvm->arch.hpt_mutex);

	if (!gpte->may_read || (iswrite && !gpte->may_write))
		return -EPERM;
	return 0;

no_page_found:
	mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
	return -ENOENT;

Annotation

Implementation Notes