/*
* Low level TLB miss handlers for Book3E
*
* Copyright (C) 2008-2009
* Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/processor.h>
#include <asm/reg.h>
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/cputable.h>
#include <asm/pgtable.h>
#include <asm/exception-64e.h>
#include <asm/ppc-opcode.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_booke_hv_asm.h>
#ifdef CONFIG_PPC_64K_PAGES
#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE+1)
#else
#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE)
#endif
#define VPTE_PUD_SHIFT (VPTE_PMD_SHIFT + PMD_INDEX_SIZE)
#define VPTE_PGD_SHIFT (VPTE_PUD_SHIFT + PUD_INDEX_SIZE)
#define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE)
/**********************************************************************
* *
* TLB miss handling for Book3E with a bolted linear mapping *
* No virtual page table, no nested TLB misses *
* *
**********************************************************************/
/*
* Note that, unlike non-bolted handlers, TLB_EXFRAME is not
* modified by the TLB miss handlers themselves, since the TLB miss
* handler code will not itself cause a recursive TLB miss.
*
* TLB_EXFRAME will be modified when crit/mc/debug exceptions are
* entered/exited.
*/
.macro tlb_prolog_bolted intnum addr
mtspr SPRN_SPRG_GEN_SCRATCH,r12
mfspr r12,SPRN_SPRG_TLB_EXFRAME
std r13,EX_TLB_R13(r12)
std r10,EX_TLB_R10(r12)
mfspr r13,SPRN_SPRG_PACA
mfcr r10
std r11,EX_TLB_R11(r12)
#ifdef CONFIG_KVM_BOOKE_HV
BEGIN_FTR_SECTION
mfspr r11, SPRN_SRR1
END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
#endif
DO_KVM \intnum, SPRN_SRR1
std r16,EX_TLB_R16(r12)
mfspr r16,\addr /* get faulting address */
std r14,EX_TLB_R14(r12)
ld r14,PACAPGD(r13)
std r15,EX_TLB_R15(r12)
std r10,EX_TLB_CR(r12)
TLB_MISS_PROLOG_STATS
.endm
.macro tlb_epilog_bolted
ld r14,EX_TLB_CR(r12)
ld r10,EX_TLB_R10(r12)
ld r11,EX_TLB_R11(r12)
ld r13,EX_TLB_R13(r12)
mtcr r14
ld r14,EX_TLB_R14(r12)
ld r15,EX_TLB_R15(r12)
TLB_MISS_RESTORE_STATS
ld r16,EX_TLB_R16(r12)
mfspr r12,SPRN_SPRG_GEN_SCRATCH
.endm
/* Data TLB miss */
START_EXCEPTION(data_tlb_miss_bolted)
tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR
/* We need _PAGE_PRESENT and _PAGE_ACCESSED set */
/* We do the user/kernel test for the PID here along with the RW test
*/
/* We pre-test some combination of permissions to avoid double
* faults:
*
* We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE
* ESR_ST is 0x00800000
* _PAGE_BAP_SW is 0x00000010
* So the shift is >> 19. This tests for supervisor writeability.
* If the page happens to be supervisor writeable and not user
* writeable, we will take a new fault later, but that should be
* a rare enough case.
*
* We also move ESR_ST in _PAGE_DIRTY position
* _PAGE_DIRTY is 0x00001000 so the shift is >> 11
*
* MAS1 is preset for all we need except for TID that needs to
* be cleared for kernel translations
*/
mfspr r11,SPRN_ESR
srdi r15,r16,60 /* get region */
rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
bne- dtlb_miss_fault_bolted /* Bail if fault addr is invalid */
rlwinm r10,r11,32-19,27,27
rlwimi r10,r11,32-16,19,19
cmpwi r15,0 /* user vs kernel check */
ori r10,r10,_PAGE_PRESENT
oris r11,r10,_PAGE_ACCESSED@h
TLB_MISS_STATS_SAVE_INFO_BOLTED
bne tlb_miss_kernel_bolted
tlb_miss_common_bolted:
/*
* This is the guts of the TLB miss handler for bolted-linear.
* We are entered with:
*
* r16 = faulting address
* r15 = crap (free to use)
* r14 = page table base
* r13 = PACA
* r11 = PTE permission mask
* r10 = crap (free to use)
*/
rldicl r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3
cmpldi cr0,r14,0
clrrdi r15,r15,3
beq tlb_miss_fault_bolted /* No PGDIR, bail */
BEGIN_MMU_FTR_SECTION
/* Set the TLB reservation and search for existing entry. Then load
* the entry.
*/
PPC_TLBSRX_DOT(0,R16)
ldx r14,r14,r15 /* grab pgd entry */
beq tlb_miss_done_bolted /* tlb exists already, bail */
MMU_FTR_SECTION_ELSE
ldx r14,r14,r15 /* grab pgd entry */
ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV)
#ifndef CONFIG_PPC_64K_PAGES
rldicl r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
clrrdi r15,r15,3
cmpdi cr0,r14,0
bge tlb_miss_fault_bolted /* Bad pgd entry or hugepage; bail */
ldx r14,r14,r15 /* grab pud entry */
#endif /* CONFIG_PPC_64K_PAGES */
rldicl r15,r16,64-