162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Low level TLB miss handlers for Book3E
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2008-2009
662306a36Sopenharmony_ci *      Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/pgtable.h>
1062306a36Sopenharmony_ci#include <asm/processor.h>
1162306a36Sopenharmony_ci#include <asm/reg.h>
1262306a36Sopenharmony_ci#include <asm/page.h>
1362306a36Sopenharmony_ci#include <asm/mmu.h>
1462306a36Sopenharmony_ci#include <asm/ppc_asm.h>
1562306a36Sopenharmony_ci#include <asm/asm-offsets.h>
1662306a36Sopenharmony_ci#include <asm/cputable.h>
1762306a36Sopenharmony_ci#include <asm/exception-64e.h>
1862306a36Sopenharmony_ci#include <asm/ppc-opcode.h>
1962306a36Sopenharmony_ci#include <asm/kvm_asm.h>
2062306a36Sopenharmony_ci#include <asm/kvm_booke_hv_asm.h>
2162306a36Sopenharmony_ci#include <asm/feature-fixups.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define VPTE_PMD_SHIFT	(PTE_INDEX_SIZE)
2462306a36Sopenharmony_ci#define VPTE_PUD_SHIFT	(VPTE_PMD_SHIFT + PMD_INDEX_SIZE)
2562306a36Sopenharmony_ci#define VPTE_PGD_SHIFT	(VPTE_PUD_SHIFT + PUD_INDEX_SIZE)
2662306a36Sopenharmony_ci#define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**********************************************************************
2962306a36Sopenharmony_ci *                                                                    *
3062306a36Sopenharmony_ci * TLB miss handling for Book3E with a bolted linear mapping          *
3162306a36Sopenharmony_ci * No virtual page table, no nested TLB misses                        *
3262306a36Sopenharmony_ci *                                                                    *
3362306a36Sopenharmony_ci **********************************************************************/
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Note that, unlike non-bolted handlers, TLB_EXFRAME is not
3762306a36Sopenharmony_ci * modified by the TLB miss handlers themselves, since the TLB miss
3862306a36Sopenharmony_ci * handler code will not itself cause a recursive TLB miss.
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * TLB_EXFRAME will be modified when crit/mc/debug exceptions are
4162306a36Sopenharmony_ci * entered/exited.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci.macro tlb_prolog_bolted intnum addr
4462306a36Sopenharmony_ci	mtspr	SPRN_SPRG_GEN_SCRATCH,r12
4562306a36Sopenharmony_ci	mfspr	r12,SPRN_SPRG_TLB_EXFRAME
4662306a36Sopenharmony_ci	std	r13,EX_TLB_R13(r12)
4762306a36Sopenharmony_ci	std	r10,EX_TLB_R10(r12)
4862306a36Sopenharmony_ci	mfspr	r13,SPRN_SPRG_PACA
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	mfcr	r10
5162306a36Sopenharmony_ci	std	r11,EX_TLB_R11(r12)
5262306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV
5362306a36Sopenharmony_ciBEGIN_FTR_SECTION
5462306a36Sopenharmony_ci	mfspr	r11, SPRN_SRR1
5562306a36Sopenharmony_ciEND_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
5662306a36Sopenharmony_ci#endif
5762306a36Sopenharmony_ci	DO_KVM	\intnum, SPRN_SRR1
5862306a36Sopenharmony_ci	std	r16,EX_TLB_R16(r12)
5962306a36Sopenharmony_ci	mfspr	r16,\addr		/* get faulting address */
6062306a36Sopenharmony_ci	std	r14,EX_TLB_R14(r12)
6162306a36Sopenharmony_ci	ld	r14,PACAPGD(r13)
6262306a36Sopenharmony_ci	std	r15,EX_TLB_R15(r12)
6362306a36Sopenharmony_ci	std	r10,EX_TLB_CR(r12)
6462306a36Sopenharmony_ciSTART_BTB_FLUSH_SECTION
6562306a36Sopenharmony_ci	mfspr r11, SPRN_SRR1
6662306a36Sopenharmony_ci	andi. r10,r11,MSR_PR
6762306a36Sopenharmony_ci	beq 1f
6862306a36Sopenharmony_ci	BTB_FLUSH(r10)
6962306a36Sopenharmony_ci1:
7062306a36Sopenharmony_ciEND_BTB_FLUSH_SECTION
7162306a36Sopenharmony_ci	std	r7,EX_TLB_R7(r12)
7262306a36Sopenharmony_ci.endm
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci.macro tlb_epilog_bolted
7562306a36Sopenharmony_ci	ld	r14,EX_TLB_CR(r12)
7662306a36Sopenharmony_ci	ld	r7,EX_TLB_R7(r12)
7762306a36Sopenharmony_ci	ld	r10,EX_TLB_R10(r12)
7862306a36Sopenharmony_ci	ld	r11,EX_TLB_R11(r12)
7962306a36Sopenharmony_ci	ld	r13,EX_TLB_R13(r12)
8062306a36Sopenharmony_ci	mtcr	r14
8162306a36Sopenharmony_ci	ld	r14,EX_TLB_R14(r12)
8262306a36Sopenharmony_ci	ld	r15,EX_TLB_R15(r12)
8362306a36Sopenharmony_ci	ld	r16,EX_TLB_R16(r12)
8462306a36Sopenharmony_ci	mfspr	r12,SPRN_SPRG_GEN_SCRATCH
8562306a36Sopenharmony_ci.endm
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Data TLB miss */
8862306a36Sopenharmony_ci	START_EXCEPTION(data_tlb_miss_bolted)
8962306a36Sopenharmony_ci	tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* We need _PAGE_PRESENT and  _PAGE_ACCESSED set */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
9462306a36Sopenharmony_ci	 */
9562306a36Sopenharmony_ci	/* We pre-test some combination of permissions to avoid double
9662306a36Sopenharmony_ci	 * faults:
9762306a36Sopenharmony_ci	 *
9862306a36Sopenharmony_ci	 * We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE
9962306a36Sopenharmony_ci	 * ESR_ST   is 0x00800000
10062306a36Sopenharmony_ci	 * _PAGE_BAP_SW is 0x00000010
10162306a36Sopenharmony_ci	 * So the shift is >> 19. This tests for supervisor writeability.
10262306a36Sopenharmony_ci	 * If the page happens to be supervisor writeable and not user
10362306a36Sopenharmony_ci	 * writeable, we will take a new fault later, but that should be
10462306a36Sopenharmony_ci	 * a rare enough case.
10562306a36Sopenharmony_ci	 *
10662306a36Sopenharmony_ci	 * We also move ESR_ST in _PAGE_DIRTY position
10762306a36Sopenharmony_ci	 * _PAGE_DIRTY is 0x00001000 so the shift is >> 11
10862306a36Sopenharmony_ci	 *
10962306a36Sopenharmony_ci	 * MAS1 is preset for all we need except for TID that needs to
11062306a36Sopenharmony_ci	 * be cleared for kernel translations
11162306a36Sopenharmony_ci	 */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	mfspr	r11,SPRN_ESR
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	srdi	r15,r16,60		/* get region */
11662306a36Sopenharmony_ci	rldicl.	r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
11762306a36Sopenharmony_ci	bne-	dtlb_miss_fault_bolted	/* Bail if fault addr is invalid */
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	rlwinm	r10,r11,32-19,27,27
12062306a36Sopenharmony_ci	rlwimi	r10,r11,32-16,19,19
12162306a36Sopenharmony_ci	cmpwi	r15,0			/* user vs kernel check */
12262306a36Sopenharmony_ci	ori	r10,r10,_PAGE_PRESENT
12362306a36Sopenharmony_ci	oris	r11,r10,_PAGE_ACCESSED@h
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	bne	tlb_miss_kernel_bolted
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_citlb_miss_user_bolted:
12862306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
12962306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
13062306a36Sopenharmony_ci	rlwinm.	r10,r10,0,0x3fff0000
13162306a36Sopenharmony_ci	beq-	tlb_miss_fault_bolted /* KUAP fault */
13262306a36Sopenharmony_ci#endif
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_citlb_miss_common_bolted:
13562306a36Sopenharmony_ci/*
13662306a36Sopenharmony_ci * This is the guts of the TLB miss handler for bolted-linear.
13762306a36Sopenharmony_ci * We are entered with:
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * r16 = faulting address
14062306a36Sopenharmony_ci * r15 = crap (free to use)
14162306a36Sopenharmony_ci * r14 = page table base
14262306a36Sopenharmony_ci * r13 = PACA
14362306a36Sopenharmony_ci * r11 = PTE permission mask
14462306a36Sopenharmony_ci * r10 = crap (free to use)
14562306a36Sopenharmony_ci */
14662306a36Sopenharmony_ci	rldicl	r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3
14762306a36Sopenharmony_ci	cmpldi	cr0,r14,0
14862306a36Sopenharmony_ci	clrrdi	r15,r15,3
14962306a36Sopenharmony_ci	beq	tlb_miss_fault_bolted	/* No PGDIR, bail */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	ldx	r14,r14,r15		/* grab pgd entry */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	rldicl	r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
15462306a36Sopenharmony_ci	clrrdi	r15,r15,3
15562306a36Sopenharmony_ci	cmpdi	cr0,r14,0
15662306a36Sopenharmony_ci	bge	tlb_miss_fault_bolted	/* Bad pgd entry or hugepage; bail */
15762306a36Sopenharmony_ci	ldx	r14,r14,r15		/* grab pud entry */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	rldicl	r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3
16062306a36Sopenharmony_ci	clrrdi	r15,r15,3
16162306a36Sopenharmony_ci	cmpdi	cr0,r14,0
16262306a36Sopenharmony_ci	bge	tlb_miss_fault_bolted
16362306a36Sopenharmony_ci	ldx	r14,r14,r15		/* Grab pmd entry */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	rldicl	r15,r16,64-PAGE_SHIFT+3,64-PTE_INDEX_SIZE-3
16662306a36Sopenharmony_ci	clrrdi	r15,r15,3
16762306a36Sopenharmony_ci	cmpdi	cr0,r14,0
16862306a36Sopenharmony_ci	bge	tlb_miss_fault_bolted
16962306a36Sopenharmony_ci	ldx	r14,r14,r15		/* Grab PTE, normal (!huge) page */
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Check if required permissions are met */
17262306a36Sopenharmony_ci	andc.	r15,r11,r14
17362306a36Sopenharmony_ci	rldicr	r15,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
17462306a36Sopenharmony_ci	bne-	tlb_miss_fault_bolted
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Now we build the MAS:
17762306a36Sopenharmony_ci	 *
17862306a36Sopenharmony_ci	 * MAS 0   :	Fully setup with defaults in MAS4 and TLBnCFG
17962306a36Sopenharmony_ci	 * MAS 1   :	Almost fully setup
18062306a36Sopenharmony_ci	 *               - PID already updated by caller if necessary
18162306a36Sopenharmony_ci	 *               - TSIZE need change if !base page size, not
18262306a36Sopenharmony_ci	 *                 yet implemented for now
18362306a36Sopenharmony_ci	 * MAS 2   :	Defaults not useful, need to be redone
18462306a36Sopenharmony_ci	 * MAS 3+7 :	Needs to be done
18562306a36Sopenharmony_ci	 */
18662306a36Sopenharmony_ci	clrrdi	r11,r16,12		/* Clear low crap in EA */
18762306a36Sopenharmony_ci	clrldi	r15,r15,12		/* Clear crap at the top */
18862306a36Sopenharmony_ci	rlwimi	r11,r14,32-19,27,31	/* Insert WIMGE */
18962306a36Sopenharmony_ci	rlwimi	r15,r14,32-8,22,25	/* Move in U bits */
19062306a36Sopenharmony_ci	mtspr	SPRN_MAS2,r11
19162306a36Sopenharmony_ci	andi.	r11,r14,_PAGE_DIRTY
19262306a36Sopenharmony_ci	rlwimi	r15,r14,32-2,26,31	/* Move in BAP bits */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* Mask out SW and UW if !DIRTY (XXX optimize this !) */
19562306a36Sopenharmony_ci	bne	1f
19662306a36Sopenharmony_ci	li	r11,MAS3_SW|MAS3_UW
19762306a36Sopenharmony_ci	andc	r15,r15,r11
19862306a36Sopenharmony_ci1:
19962306a36Sopenharmony_ci	mtspr	SPRN_MAS7_MAS3,r15
20062306a36Sopenharmony_ci	tlbwe
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_citlb_miss_done_bolted:
20362306a36Sopenharmony_ci	tlb_epilog_bolted
20462306a36Sopenharmony_ci	rfi
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciitlb_miss_kernel_bolted:
20762306a36Sopenharmony_ci	li	r11,_PAGE_PRESENT|_PAGE_BAP_SX	/* Base perm */
20862306a36Sopenharmony_ci	oris	r11,r11,_PAGE_ACCESSED@h
20962306a36Sopenharmony_citlb_miss_kernel_bolted:
21062306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
21162306a36Sopenharmony_ci	ld	r14,PACA_KERNELPGD(r13)
21262306a36Sopenharmony_ci	srdi	r15,r16,44		/* get kernel region */
21362306a36Sopenharmony_ci	andi.	r15,r15,1		/* Check for vmalloc region */
21462306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1		/* Clear TID */
21562306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
21662306a36Sopenharmony_ci	bne+	tlb_miss_common_bolted
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_citlb_miss_fault_bolted:
21962306a36Sopenharmony_ci	/* We need to check if it was an instruction miss */
22062306a36Sopenharmony_ci	andi.	r10,r11,_PAGE_BAP_UX|_PAGE_BAP_SX
22162306a36Sopenharmony_ci	bne	itlb_miss_fault_bolted
22262306a36Sopenharmony_cidtlb_miss_fault_bolted:
22362306a36Sopenharmony_ci	tlb_epilog_bolted
22462306a36Sopenharmony_ci	b	exc_data_storage_book3e
22562306a36Sopenharmony_ciitlb_miss_fault_bolted:
22662306a36Sopenharmony_ci	tlb_epilog_bolted
22762306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* Instruction TLB miss */
23062306a36Sopenharmony_ci	START_EXCEPTION(instruction_tlb_miss_bolted)
23162306a36Sopenharmony_ci	tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	rldicl.	r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
23462306a36Sopenharmony_ci	srdi	r15,r16,60		/* get region */
23562306a36Sopenharmony_ci	bne-	itlb_miss_fault_bolted
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	li	r11,_PAGE_PRESENT|_PAGE_BAP_UX	/* Base perm */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
24062306a36Sopenharmony_ci	 */
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	cmpldi	cr0,r15,0			/* Check for user region */
24362306a36Sopenharmony_ci	oris	r11,r11,_PAGE_ACCESSED@h
24462306a36Sopenharmony_ci	beq	tlb_miss_user_bolted
24562306a36Sopenharmony_ci	b	itlb_miss_kernel_bolted
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/*
24862306a36Sopenharmony_ci * TLB miss handling for e6500 and derivatives, using hardware tablewalk.
24962306a36Sopenharmony_ci *
25062306a36Sopenharmony_ci * Linear mapping is bolted: no virtual page table or nested TLB misses
25162306a36Sopenharmony_ci * Indirect entries in TLB1, hardware loads resulting direct entries
25262306a36Sopenharmony_ci *    into TLB0
25362306a36Sopenharmony_ci * No HES or NV hint on TLB1, so we need to do software round-robin
25462306a36Sopenharmony_ci * No tlbsrx. so we need a spinlock, and we have to deal
25562306a36Sopenharmony_ci *    with MAS-damage caused by tlbsx
25662306a36Sopenharmony_ci * 4K pages only
25762306a36Sopenharmony_ci */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	START_EXCEPTION(instruction_tlb_miss_e6500)
26062306a36Sopenharmony_ci	tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ld	r11,PACA_TCD_PTR(r13)
26362306a36Sopenharmony_ci	srdi.	r15,r16,60		/* get region */
26462306a36Sopenharmony_ci	ori	r16,r16,1
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	bne	tlb_miss_kernel_e6500	/* user/kernel test */
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	b	tlb_miss_common_e6500
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	START_EXCEPTION(data_tlb_miss_e6500)
27162306a36Sopenharmony_ci	tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	ld	r11,PACA_TCD_PTR(r13)
27462306a36Sopenharmony_ci	srdi.	r15,r16,60		/* get region */
27562306a36Sopenharmony_ci	rldicr	r16,r16,0,62
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	bne	tlb_miss_kernel_e6500	/* user vs kernel check */
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/*
28062306a36Sopenharmony_ci * This is the guts of the TLB miss handler for e6500 and derivatives.
28162306a36Sopenharmony_ci * We are entered with:
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * r16 = page of faulting address (low bit 0 if data, 1 if instruction)
28462306a36Sopenharmony_ci * r15 = crap (free to use)
28562306a36Sopenharmony_ci * r14 = page table base
28662306a36Sopenharmony_ci * r13 = PACA
28762306a36Sopenharmony_ci * r11 = tlb_per_core ptr
28862306a36Sopenharmony_ci * r10 = crap (free to use)
28962306a36Sopenharmony_ci * r7  = esel_next
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_citlb_miss_common_e6500:
29262306a36Sopenharmony_ci	crmove	cr2*4+2,cr0*4+2		/* cr2.eq != 0 if kernel address */
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciBEGIN_FTR_SECTION		/* CPU_FTR_SMT */
29562306a36Sopenharmony_ci	/*
29662306a36Sopenharmony_ci	 * Search if we already have an indirect entry for that virtual
29762306a36Sopenharmony_ci	 * address, and if we do, bail out.
29862306a36Sopenharmony_ci	 *
29962306a36Sopenharmony_ci	 * MAS6:IND should be already set based on MAS4
30062306a36Sopenharmony_ci	 */
30162306a36Sopenharmony_ci	lhz	r10,PACAPACAINDEX(r13)
30262306a36Sopenharmony_ci	addi	r10,r10,1
30362306a36Sopenharmony_ci	crclr	cr1*4+eq	/* set cr1.eq = 0 for non-recursive */
30462306a36Sopenharmony_ci1:	lbarx	r15,0,r11
30562306a36Sopenharmony_ci	cmpdi	r15,0
30662306a36Sopenharmony_ci	bne	2f
30762306a36Sopenharmony_ci	stbcx.	r10,0,r11
30862306a36Sopenharmony_ci	bne	1b
30962306a36Sopenharmony_ci3:
31062306a36Sopenharmony_ci	.subsection 1
31162306a36Sopenharmony_ci2:	cmpd	cr1,r15,r10	/* recursive lock due to mcheck/crit/etc? */
31262306a36Sopenharmony_ci	beq	cr1,3b		/* unlock will happen if cr1.eq = 0 */
31362306a36Sopenharmony_ci10:	lbz	r15,0(r11)
31462306a36Sopenharmony_ci	cmpdi	r15,0
31562306a36Sopenharmony_ci	bne	10b
31662306a36Sopenharmony_ci	b	1b
31762306a36Sopenharmony_ci	.previous
31862306a36Sopenharmony_ciEND_FTR_SECTION_IFSET(CPU_FTR_SMT)
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	lbz	r7,TCD_ESEL_NEXT(r11)
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciBEGIN_FTR_SECTION		/* CPU_FTR_SMT */
32362306a36Sopenharmony_ci	/*
32462306a36Sopenharmony_ci	 * Erratum A-008139 says that we can't use tlbwe to change
32562306a36Sopenharmony_ci	 * an indirect entry in any way (including replacing or
32662306a36Sopenharmony_ci	 * invalidating) if the other thread could be in the process
32762306a36Sopenharmony_ci	 * of a lookup.  The workaround is to invalidate the entry
32862306a36Sopenharmony_ci	 * with tlbilx before overwriting.
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	rlwinm	r10,r7,16,0xff0000
33262306a36Sopenharmony_ci	oris	r10,r10,MAS0_TLBSEL(1)@h
33362306a36Sopenharmony_ci	mtspr	SPRN_MAS0,r10
33462306a36Sopenharmony_ci	isync
33562306a36Sopenharmony_ci	tlbre
33662306a36Sopenharmony_ci	mfspr	r15,SPRN_MAS1
33762306a36Sopenharmony_ci	andis.	r15,r15,MAS1_VALID@h
33862306a36Sopenharmony_ci	beq	5f
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ciBEGIN_FTR_SECTION_NESTED(532)
34162306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS8
34262306a36Sopenharmony_ci	rlwinm	r10,r10,0,0x80000fff  /* tgs,tlpid -> sgs,slpid */
34362306a36Sopenharmony_ci	mtspr	SPRN_MAS5,r10
34462306a36Sopenharmony_ciEND_FTR_SECTION_NESTED(CPU_FTR_EMB_HV,CPU_FTR_EMB_HV,532)
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
34762306a36Sopenharmony_ci	rlwinm	r15,r10,0,0x3fff0000  /* tid -> spid */
34862306a36Sopenharmony_ci	rlwimi	r15,r10,20,0x00000003 /* ind,ts -> sind,sas */
34962306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS6
35062306a36Sopenharmony_ci	mtspr	SPRN_MAS6,r15
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	mfspr	r15,SPRN_MAS2
35362306a36Sopenharmony_ci	isync
35462306a36Sopenharmony_ci	PPC_TLBILX_VA(0,R15)
35562306a36Sopenharmony_ci	isync
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	mtspr	SPRN_MAS6,r10
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci5:
36062306a36Sopenharmony_ciBEGIN_FTR_SECTION_NESTED(532)
36162306a36Sopenharmony_ci	li	r10,0
36262306a36Sopenharmony_ci	mtspr	SPRN_MAS8,r10
36362306a36Sopenharmony_ci	mtspr	SPRN_MAS5,r10
36462306a36Sopenharmony_ciEND_FTR_SECTION_NESTED(CPU_FTR_EMB_HV,CPU_FTR_EMB_HV,532)
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	tlbsx	0,r16
36762306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
36862306a36Sopenharmony_ci	andis.	r15,r10,MAS1_VALID@h
36962306a36Sopenharmony_ci	bne	tlb_miss_done_e6500
37062306a36Sopenharmony_ciFTR_SECTION_ELSE
37162306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
37262306a36Sopenharmony_ciALT_FTR_SECTION_END_IFSET(CPU_FTR_SMT)
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	oris	r10,r10,MAS1_VALID@h
37562306a36Sopenharmony_ci	beq	cr2,4f
37662306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1		/* Clear TID */
37762306a36Sopenharmony_ci4:	mtspr	SPRN_MAS1,r10
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Now, we need to walk the page tables. First check if we are in
38062306a36Sopenharmony_ci	 * range.
38162306a36Sopenharmony_ci	 */
38262306a36Sopenharmony_ci	rldicl.	r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
38362306a36Sopenharmony_ci	bne-	tlb_miss_fault_e6500
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	rldicl	r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3
38662306a36Sopenharmony_ci	cmpldi	cr0,r14,0
38762306a36Sopenharmony_ci	clrrdi	r15,r15,3
38862306a36Sopenharmony_ci	beq-	tlb_miss_fault_e6500 /* No PGDIR, bail */
38962306a36Sopenharmony_ci	ldx	r14,r14,r15		/* grab pgd entry */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	rldicl	r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
39262306a36Sopenharmony_ci	clrrdi	r15,r15,3
39362306a36Sopenharmony_ci	cmpdi	cr0,r14,0
39462306a36Sopenharmony_ci	bge	tlb_miss_huge_e6500	/* Bad pgd entry or hugepage; bail */
39562306a36Sopenharmony_ci	ldx	r14,r14,r15		/* grab pud entry */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rldicl	r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3
39862306a36Sopenharmony_ci	clrrdi	r15,r15,3
39962306a36Sopenharmony_ci	cmpdi	cr0,r14,0
40062306a36Sopenharmony_ci	bge	tlb_miss_huge_e6500
40162306a36Sopenharmony_ci	ldx	r14,r14,r15		/* Grab pmd entry */
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS0
40462306a36Sopenharmony_ci	cmpdi	cr0,r14,0
40562306a36Sopenharmony_ci	bge	tlb_miss_huge_e6500
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* Now we build the MAS for a 2M indirect page:
40862306a36Sopenharmony_ci	 *
40962306a36Sopenharmony_ci	 * MAS 0   :	ESEL needs to be filled by software round-robin
41062306a36Sopenharmony_ci	 * MAS 1   :	Fully set up
41162306a36Sopenharmony_ci	 *               - PID already updated by caller if necessary
41262306a36Sopenharmony_ci	 *               - TSIZE for now is base ind page size always
41362306a36Sopenharmony_ci	 *               - TID already cleared if necessary
41462306a36Sopenharmony_ci	 * MAS 2   :	Default not 2M-aligned, need to be redone
41562306a36Sopenharmony_ci	 * MAS 3+7 :	Needs to be done
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	ori	r14,r14,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
41962306a36Sopenharmony_ci	mtspr	SPRN_MAS7_MAS3,r14
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	clrrdi	r15,r16,21		/* make EA 2M-aligned */
42262306a36Sopenharmony_ci	mtspr	SPRN_MAS2,r15
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_citlb_miss_huge_done_e6500:
42562306a36Sopenharmony_ci	lbz	r16,TCD_ESEL_MAX(r11)
42662306a36Sopenharmony_ci	lbz	r14,TCD_ESEL_FIRST(r11)
42762306a36Sopenharmony_ci	rlwimi	r10,r7,16,0x00ff0000	/* insert esel_next into MAS0 */
42862306a36Sopenharmony_ci	addi	r7,r7,1			/* increment esel_next */
42962306a36Sopenharmony_ci	mtspr	SPRN_MAS0,r10
43062306a36Sopenharmony_ci	cmpw	r7,r16
43162306a36Sopenharmony_ci	iseleq	r7,r14,r7		/* if next == last use first */
43262306a36Sopenharmony_ci	stb	r7,TCD_ESEL_NEXT(r11)
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	tlbwe
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_citlb_miss_done_e6500:
43762306a36Sopenharmony_ci	.macro	tlb_unlock_e6500
43862306a36Sopenharmony_ciBEGIN_FTR_SECTION
43962306a36Sopenharmony_ci	beq	cr1,1f		/* no unlock if lock was recursively grabbed */
44062306a36Sopenharmony_ci	li	r15,0
44162306a36Sopenharmony_ci	isync
44262306a36Sopenharmony_ci	stb	r15,0(r11)
44362306a36Sopenharmony_ci1:
44462306a36Sopenharmony_ciEND_FTR_SECTION_IFSET(CPU_FTR_SMT)
44562306a36Sopenharmony_ci	.endm
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	tlb_unlock_e6500
44862306a36Sopenharmony_ci	tlb_epilog_bolted
44962306a36Sopenharmony_ci	rfi
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_citlb_miss_huge_e6500:
45262306a36Sopenharmony_ci	beq	tlb_miss_fault_e6500
45362306a36Sopenharmony_ci	li	r10,1
45462306a36Sopenharmony_ci	andi.	r15,r14,HUGEPD_SHIFT_MASK@l /* r15 = psize */
45562306a36Sopenharmony_ci	rldimi	r14,r10,63,0		/* Set PD_HUGE */
45662306a36Sopenharmony_ci	xor	r14,r14,r15		/* Clear size bits */
45762306a36Sopenharmony_ci	ldx	r14,0,r14
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/*
46062306a36Sopenharmony_ci	 * Now we build the MAS for a huge page.
46162306a36Sopenharmony_ci	 *
46262306a36Sopenharmony_ci	 * MAS 0   :	ESEL needs to be filled by software round-robin
46362306a36Sopenharmony_ci	 *		 - can be handled by indirect code
46462306a36Sopenharmony_ci	 * MAS 1   :	Need to clear IND and set TSIZE
46562306a36Sopenharmony_ci	 * MAS 2,3+7:	Needs to be redone similar to non-tablewalk handler
46662306a36Sopenharmony_ci	 */
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	subi	r15,r15,10		/* Convert psize to tsize */
46962306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
47062306a36Sopenharmony_ci	rlwinm	r10,r10,0,~MAS1_IND
47162306a36Sopenharmony_ci	rlwimi	r10,r15,MAS1_TSIZE_SHIFT,MAS1_TSIZE_MASK
47262306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	li	r10,-0x400
47562306a36Sopenharmony_ci	sld	r15,r10,r15		/* Generate mask based on size */
47662306a36Sopenharmony_ci	and	r10,r16,r15
47762306a36Sopenharmony_ci	rldicr	r15,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
47862306a36Sopenharmony_ci	rlwimi	r10,r14,32-19,27,31	/* Insert WIMGE */
47962306a36Sopenharmony_ci	clrldi	r15,r15,PAGE_SHIFT	/* Clear crap at the top */
48062306a36Sopenharmony_ci	rlwimi	r15,r14,32-8,22,25	/* Move in U bits */
48162306a36Sopenharmony_ci	mtspr	SPRN_MAS2,r10
48262306a36Sopenharmony_ci	andi.	r10,r14,_PAGE_DIRTY
48362306a36Sopenharmony_ci	rlwimi	r15,r14,32-2,26,31	/* Move in BAP bits */
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* Mask out SW and UW if !DIRTY (XXX optimize this !) */
48662306a36Sopenharmony_ci	bne	1f
48762306a36Sopenharmony_ci	li	r10,MAS3_SW|MAS3_UW
48862306a36Sopenharmony_ci	andc	r15,r15,r10
48962306a36Sopenharmony_ci1:
49062306a36Sopenharmony_ci	mtspr	SPRN_MAS7_MAS3,r15
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS0
49362306a36Sopenharmony_ci	b	tlb_miss_huge_done_e6500
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_citlb_miss_kernel_e6500:
49662306a36Sopenharmony_ci	ld	r14,PACA_KERNELPGD(r13)
49762306a36Sopenharmony_ci	srdi	r15,r16,44		/* get kernel region */
49862306a36Sopenharmony_ci	xoris	r15,r15,0xc		/* Check for vmalloc region */
49962306a36Sopenharmony_ci	cmplwi	cr1,r15,1
50062306a36Sopenharmony_ci	beq+	cr1,tlb_miss_common_e6500
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_citlb_miss_fault_e6500:
50362306a36Sopenharmony_ci	tlb_unlock_e6500
50462306a36Sopenharmony_ci	/* We need to check if it was an instruction miss */
50562306a36Sopenharmony_ci	andi.	r16,r16,1
50662306a36Sopenharmony_ci	bne	itlb_miss_fault_e6500
50762306a36Sopenharmony_cidtlb_miss_fault_e6500:
50862306a36Sopenharmony_ci	tlb_epilog_bolted
50962306a36Sopenharmony_ci	b	exc_data_storage_book3e
51062306a36Sopenharmony_ciitlb_miss_fault_e6500:
51162306a36Sopenharmony_ci	tlb_epilog_bolted
51262306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci/**********************************************************************
51562306a36Sopenharmony_ci *                                                                    *
51662306a36Sopenharmony_ci * TLB miss handling for Book3E with TLB reservation and HES support  *
51762306a36Sopenharmony_ci *                                                                    *
51862306a36Sopenharmony_ci **********************************************************************/
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci/* Data TLB miss */
52262306a36Sopenharmony_ci	START_EXCEPTION(data_tlb_miss)
52362306a36Sopenharmony_ci	TLB_MISS_PROLOG
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* Now we handle the fault proper. We only save DEAR in normal
52662306a36Sopenharmony_ci	 * fault case since that's the only interesting values here.
52762306a36Sopenharmony_ci	 * We could probably also optimize by not saving SRR0/1 in the
52862306a36Sopenharmony_ci	 * linear mapping case but I'll leave that for later
52962306a36Sopenharmony_ci	 */
53062306a36Sopenharmony_ci	mfspr	r14,SPRN_ESR
53162306a36Sopenharmony_ci	mfspr	r16,SPRN_DEAR		/* get faulting address */
53262306a36Sopenharmony_ci	srdi	r15,r16,44		/* get region */
53362306a36Sopenharmony_ci	xoris	r15,r15,0xc
53462306a36Sopenharmony_ci	cmpldi	cr0,r15,0		/* linear mapping ? */
53562306a36Sopenharmony_ci	beq	tlb_load_linear		/* yes -> go to linear map load */
53662306a36Sopenharmony_ci	cmpldi	cr1,r15,1		/* vmalloc mapping ? */
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* The page tables are mapped virtually linear. At this point, though,
53962306a36Sopenharmony_ci	 * we don't know whether we are trying to fault in a first level
54062306a36Sopenharmony_ci	 * virtual address or a virtual page table address. We can get that
54162306a36Sopenharmony_ci	 * from bit 0x1 of the region ID which we have set for a page table
54262306a36Sopenharmony_ci	 */
54362306a36Sopenharmony_ci	andis.	r10,r15,0x1
54462306a36Sopenharmony_ci	bne-	virt_page_table_tlb_miss
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	std	r14,EX_TLB_ESR(r12);	/* save ESR */
54762306a36Sopenharmony_ci	std	r16,EX_TLB_DEAR(r12);	/* save DEAR */
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	 /* We need _PAGE_PRESENT and  _PAGE_ACCESSED set */
55062306a36Sopenharmony_ci	li	r11,_PAGE_PRESENT
55162306a36Sopenharmony_ci	oris	r11,r11,_PAGE_ACCESSED@h
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	srdi.	r15,r16,60		/* Check for user region */
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* We pre-test some combination of permissions to avoid double
55862306a36Sopenharmony_ci	 * faults:
55962306a36Sopenharmony_ci	 *
56062306a36Sopenharmony_ci	 * We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE
56162306a36Sopenharmony_ci	 * ESR_ST   is 0x00800000
56262306a36Sopenharmony_ci	 * _PAGE_BAP_SW is 0x00000010
56362306a36Sopenharmony_ci	 * So the shift is >> 19. This tests for supervisor writeability.
56462306a36Sopenharmony_ci	 * If the page happens to be supervisor writeable and not user
56562306a36Sopenharmony_ci	 * writeable, we will take a new fault later, but that should be
56662306a36Sopenharmony_ci	 * a rare enough case.
56762306a36Sopenharmony_ci	 *
56862306a36Sopenharmony_ci	 * We also move ESR_ST in _PAGE_DIRTY position
56962306a36Sopenharmony_ci	 * _PAGE_DIRTY is 0x00001000 so the shift is >> 11
57062306a36Sopenharmony_ci	 *
57162306a36Sopenharmony_ci	 * MAS1 is preset for all we need except for TID that needs to
57262306a36Sopenharmony_ci	 * be cleared for kernel translations
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci	rlwimi	r11,r14,32-19,27,27
57562306a36Sopenharmony_ci	rlwimi	r11,r14,32-16,19,19
57662306a36Sopenharmony_ci	beq	normal_tlb_miss_user
57762306a36Sopenharmony_ci	/* XXX replace the RMW cycles with immediate loads + writes */
57862306a36Sopenharmony_ci1:	mfspr	r10,SPRN_MAS1
57962306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1		/* Clear TID */
58062306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
58162306a36Sopenharmony_ci	beq+	cr1,normal_tlb_miss
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/* We got a crappy address, just fault with whatever DEAR and ESR
58462306a36Sopenharmony_ci	 * are here
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
58762306a36Sopenharmony_ci	b	exc_data_storage_book3e
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci/* Instruction TLB miss */
59062306a36Sopenharmony_ci	START_EXCEPTION(instruction_tlb_miss)
59162306a36Sopenharmony_ci	TLB_MISS_PROLOG
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* If we take a recursive fault, the second level handler may need
59462306a36Sopenharmony_ci	 * to know whether we are handling a data or instruction fault in
59562306a36Sopenharmony_ci	 * order to get to the right store fault handler. We provide that
59662306a36Sopenharmony_ci	 * info by writing a crazy value in ESR in our exception frame
59762306a36Sopenharmony_ci	 */
59862306a36Sopenharmony_ci	li	r14,-1	/* store to exception frame is done later */
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/* Now we handle the fault proper. We only save DEAR in the non
60162306a36Sopenharmony_ci	 * linear mapping case since we know the linear mapping case will
60262306a36Sopenharmony_ci	 * not re-enter. We could indeed optimize and also not save SRR0/1
60362306a36Sopenharmony_ci	 * in the linear mapping case but I'll leave that for later
60462306a36Sopenharmony_ci	 *
60562306a36Sopenharmony_ci	 * Faulting address is SRR0 which is already in r16
60662306a36Sopenharmony_ci	 */
60762306a36Sopenharmony_ci	srdi	r15,r16,44		/* get region */
60862306a36Sopenharmony_ci	xoris	r15,r15,0xc
60962306a36Sopenharmony_ci	cmpldi	cr0,r15,0		/* linear mapping ? */
61062306a36Sopenharmony_ci	beq	tlb_load_linear		/* yes -> go to linear map load */
61162306a36Sopenharmony_ci	cmpldi	cr1,r15,1		/* vmalloc mapping ? */
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
61462306a36Sopenharmony_ci	 */
61562306a36Sopenharmony_ci	li	r11,_PAGE_PRESENT|_PAGE_BAP_UX	/* Base perm */
61662306a36Sopenharmony_ci	oris	r11,r11,_PAGE_ACCESSED@h
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	srdi.	r15,r16,60			/* Check for user region */
61962306a36Sopenharmony_ci	std	r14,EX_TLB_ESR(r12)		/* write crazy -1 to frame */
62062306a36Sopenharmony_ci	beq	normal_tlb_miss_user
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	li	r11,_PAGE_PRESENT|_PAGE_BAP_SX	/* Base perm */
62362306a36Sopenharmony_ci	oris	r11,r11,_PAGE_ACCESSED@h
62462306a36Sopenharmony_ci	/* XXX replace the RMW cycles with immediate loads + writes */
62562306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
62662306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1			/* Clear TID */
62762306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
62862306a36Sopenharmony_ci	beq+	cr1,normal_tlb_miss
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* We got a crappy address, just fault */
63162306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
63262306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/*
63562306a36Sopenharmony_ci * This is the guts of the first-level TLB miss handler for direct
63662306a36Sopenharmony_ci * misses. We are entered with:
63762306a36Sopenharmony_ci *
63862306a36Sopenharmony_ci * r16 = faulting address
63962306a36Sopenharmony_ci * r15 = region ID
64062306a36Sopenharmony_ci * r14 = crap (free to use)
64162306a36Sopenharmony_ci * r13 = PACA
64262306a36Sopenharmony_ci * r12 = TLB exception frame in PACA
64362306a36Sopenharmony_ci * r11 = PTE permission mask
64462306a36Sopenharmony_ci * r10 = crap (free to use)
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_cinormal_tlb_miss_user:
64762306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
64862306a36Sopenharmony_ci	mfspr	r14,SPRN_MAS1
64962306a36Sopenharmony_ci	rlwinm.	r14,r14,0,0x3fff0000
65062306a36Sopenharmony_ci	beq-	normal_tlb_miss_access_fault /* KUAP fault */
65162306a36Sopenharmony_ci#endif
65262306a36Sopenharmony_cinormal_tlb_miss:
65362306a36Sopenharmony_ci	/* So we first construct the page table address. We do that by
65462306a36Sopenharmony_ci	 * shifting the bottom of the address (not the region ID) by
65562306a36Sopenharmony_ci	 * PAGE_SHIFT-3, clearing the bottom 3 bits (get a PTE ptr) and
65662306a36Sopenharmony_ci	 * or'ing the fourth high bit.
65762306a36Sopenharmony_ci	 *
65862306a36Sopenharmony_ci	 * NOTE: For 64K pages, we do things slightly differently in
65962306a36Sopenharmony_ci	 * order to handle the weird page table format used by linux
66062306a36Sopenharmony_ci	 */
66162306a36Sopenharmony_ci	srdi	r15,r16,44
66262306a36Sopenharmony_ci	oris	r10,r15,0x1
66362306a36Sopenharmony_ci	rldicl	r14,r16,64-(PAGE_SHIFT-3),PAGE_SHIFT-3+4
66462306a36Sopenharmony_ci	sldi	r15,r10,44
66562306a36Sopenharmony_ci	clrrdi	r14,r14,19
66662306a36Sopenharmony_ci	or	r10,r15,r14
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	ld	r14,0(r10)
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cifinish_normal_tlb_miss:
67162306a36Sopenharmony_ci	/* Check if required permissions are met */
67262306a36Sopenharmony_ci	andc.	r15,r11,r14
67362306a36Sopenharmony_ci	bne-	normal_tlb_miss_access_fault
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Now we build the MAS:
67662306a36Sopenharmony_ci	 *
67762306a36Sopenharmony_ci	 * MAS 0   :	Fully setup with defaults in MAS4 and TLBnCFG
67862306a36Sopenharmony_ci	 * MAS 1   :	Almost fully setup
67962306a36Sopenharmony_ci	 *               - PID already updated by caller if necessary
68062306a36Sopenharmony_ci	 *               - TSIZE need change if !base page size, not
68162306a36Sopenharmony_ci	 *                 yet implemented for now
68262306a36Sopenharmony_ci	 * MAS 2   :	Defaults not useful, need to be redone
68362306a36Sopenharmony_ci	 * MAS 3+7 :	Needs to be done
68462306a36Sopenharmony_ci	 *
68562306a36Sopenharmony_ci	 * TODO: mix up code below for better scheduling
68662306a36Sopenharmony_ci	 */
68762306a36Sopenharmony_ci	clrrdi	r10,r16,12		/* Clear low crap in EA */
68862306a36Sopenharmony_ci	rlwimi	r10,r14,32-19,27,31	/* Insert WIMGE */
68962306a36Sopenharmony_ci	mtspr	SPRN_MAS2,r10
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* Check page size, if not standard, update MAS1 */
69262306a36Sopenharmony_ci	rldicl	r10,r14,64-8,64-8
69362306a36Sopenharmony_ci	cmpldi	cr0,r10,BOOK3E_PAGESZ_4K
69462306a36Sopenharmony_ci	beq-	1f
69562306a36Sopenharmony_ci	mfspr	r11,SPRN_MAS1
69662306a36Sopenharmony_ci	rlwimi	r11,r14,31,21,24
69762306a36Sopenharmony_ci	rlwinm	r11,r11,0,21,19
69862306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r11
69962306a36Sopenharmony_ci1:
70062306a36Sopenharmony_ci	/* Move RPN in position */
70162306a36Sopenharmony_ci	rldicr	r11,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
70262306a36Sopenharmony_ci	clrldi	r15,r11,12		/* Clear crap at the top */
70362306a36Sopenharmony_ci	rlwimi	r15,r14,32-8,22,25	/* Move in U bits */
70462306a36Sopenharmony_ci	rlwimi	r15,r14,32-2,26,31	/* Move in BAP bits */
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Mask out SW and UW if !DIRTY (XXX optimize this !) */
70762306a36Sopenharmony_ci	andi.	r11,r14,_PAGE_DIRTY
70862306a36Sopenharmony_ci	bne	1f
70962306a36Sopenharmony_ci	li	r11,MAS3_SW|MAS3_UW
71062306a36Sopenharmony_ci	andc	r15,r15,r11
71162306a36Sopenharmony_ci1:
71262306a36Sopenharmony_ci	srdi	r16,r15,32
71362306a36Sopenharmony_ci	mtspr	SPRN_MAS3,r15
71462306a36Sopenharmony_ci	mtspr	SPRN_MAS7,r16
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	tlbwe
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cinormal_tlb_miss_done:
71962306a36Sopenharmony_ci	/* We don't bother with restoring DEAR or ESR since we know we are
72062306a36Sopenharmony_ci	 * level 0 and just going back to userland. They are only needed
72162306a36Sopenharmony_ci	 * if you are going to take an access fault
72262306a36Sopenharmony_ci	 */
72362306a36Sopenharmony_ci	TLB_MISS_EPILOG_SUCCESS
72462306a36Sopenharmony_ci	rfi
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cinormal_tlb_miss_access_fault:
72762306a36Sopenharmony_ci	/* We need to check if it was an instruction miss */
72862306a36Sopenharmony_ci	andi.	r10,r11,_PAGE_BAP_UX
72962306a36Sopenharmony_ci	bne	1f
73062306a36Sopenharmony_ci	ld	r14,EX_TLB_DEAR(r12)
73162306a36Sopenharmony_ci	ld	r15,EX_TLB_ESR(r12)
73262306a36Sopenharmony_ci	mtspr	SPRN_DEAR,r14
73362306a36Sopenharmony_ci	mtspr	SPRN_ESR,r15
73462306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
73562306a36Sopenharmony_ci	b	exc_data_storage_book3e
73662306a36Sopenharmony_ci1:	TLB_MISS_EPILOG_ERROR
73762306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/*
74162306a36Sopenharmony_ci * This is the guts of the second-level TLB miss handler for direct
74262306a36Sopenharmony_ci * misses. We are entered with:
74362306a36Sopenharmony_ci *
74462306a36Sopenharmony_ci * r16 = virtual page table faulting address
74562306a36Sopenharmony_ci * r15 = region (top 4 bits of address)
74662306a36Sopenharmony_ci * r14 = crap (free to use)
74762306a36Sopenharmony_ci * r13 = PACA
74862306a36Sopenharmony_ci * r12 = TLB exception frame in PACA
74962306a36Sopenharmony_ci * r11 = crap (free to use)
75062306a36Sopenharmony_ci * r10 = crap (free to use)
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci * Note that this should only ever be called as a second level handler
75362306a36Sopenharmony_ci * with the current scheme when using SW load.
75462306a36Sopenharmony_ci * That means we can always get the original fault DEAR at
75562306a36Sopenharmony_ci * EX_TLB_DEAR-EX_TLB_SIZE(r12)
75662306a36Sopenharmony_ci *
75762306a36Sopenharmony_ci * It can be re-entered by the linear mapping miss handler. However, to
75862306a36Sopenharmony_ci * avoid too much complication, it will restart the whole fault at level
75962306a36Sopenharmony_ci * 0 so we don't care too much about clobbers
76062306a36Sopenharmony_ci *
76162306a36Sopenharmony_ci * XXX That code was written back when we couldn't clobber r14. We can now,
76262306a36Sopenharmony_ci * so we could probably optimize things a bit
76362306a36Sopenharmony_ci */
76462306a36Sopenharmony_civirt_page_table_tlb_miss:
76562306a36Sopenharmony_ci	/* Are we hitting a kernel page table ? */
76662306a36Sopenharmony_ci	srdi	r15,r16,60
76762306a36Sopenharmony_ci	andi.	r10,r15,0x8
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* The cool thing now is that r10 contains 0 for user and 8 for kernel,
77062306a36Sopenharmony_ci	 * and we happen to have the swapper_pg_dir at offset 8 from the user
77162306a36Sopenharmony_ci	 * pgdir in the PACA :-).
77262306a36Sopenharmony_ci	 */
77362306a36Sopenharmony_ci	add	r11,r10,r13
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* If kernel, we need to clear MAS1 TID */
77662306a36Sopenharmony_ci	beq	1f
77762306a36Sopenharmony_ci	/* XXX replace the RMW cycles with immediate loads + writes */
77862306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
77962306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1			/* Clear TID */
78062306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
78162306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
78262306a36Sopenharmony_ci	b	2f
78362306a36Sopenharmony_ci1:
78462306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
78562306a36Sopenharmony_ci	rlwinm.	r10,r10,0,0x3fff0000
78662306a36Sopenharmony_ci	beq-	virt_page_table_tlb_miss_fault /* KUAP fault */
78762306a36Sopenharmony_ci2:
78862306a36Sopenharmony_ci#else
78962306a36Sopenharmony_ci1:
79062306a36Sopenharmony_ci#endif
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* Now, we need to walk the page tables. First check if we are in
79362306a36Sopenharmony_ci	 * range.
79462306a36Sopenharmony_ci	 */
79562306a36Sopenharmony_ci	rldicl	r10,r16,64-(VPTE_INDEX_SIZE+3),VPTE_INDEX_SIZE+3+4
79662306a36Sopenharmony_ci	cmpldi	r10,0x80
79762306a36Sopenharmony_ci	bne-	virt_page_table_tlb_miss_fault
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	/* Get the PGD pointer */
80062306a36Sopenharmony_ci	ld	r15,PACAPGD(r11)
80162306a36Sopenharmony_ci	cmpldi	cr0,r15,0
80262306a36Sopenharmony_ci	beq-	virt_page_table_tlb_miss_fault
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	/* Get to PGD entry */
80562306a36Sopenharmony_ci	rldicl	r11,r16,64-VPTE_PGD_SHIFT,64-PGD_INDEX_SIZE-3
80662306a36Sopenharmony_ci	clrrdi	r10,r11,3
80762306a36Sopenharmony_ci	ldx	r15,r10,r15
80862306a36Sopenharmony_ci	cmpdi	cr0,r15,0
80962306a36Sopenharmony_ci	bge	virt_page_table_tlb_miss_fault
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	/* Get to PUD entry */
81262306a36Sopenharmony_ci	rldicl	r11,r16,64-VPTE_PUD_SHIFT,64-PUD_INDEX_SIZE-3
81362306a36Sopenharmony_ci	clrrdi	r10,r11,3
81462306a36Sopenharmony_ci	ldx	r15,r10,r15
81562306a36Sopenharmony_ci	cmpdi	cr0,r15,0
81662306a36Sopenharmony_ci	bge	virt_page_table_tlb_miss_fault
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/* Get to PMD entry */
81962306a36Sopenharmony_ci	rldicl	r11,r16,64-VPTE_PMD_SHIFT,64-PMD_INDEX_SIZE-3
82062306a36Sopenharmony_ci	clrrdi	r10,r11,3
82162306a36Sopenharmony_ci	ldx	r15,r10,r15
82262306a36Sopenharmony_ci	cmpdi	cr0,r15,0
82362306a36Sopenharmony_ci	bge	virt_page_table_tlb_miss_fault
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/* Ok, we're all right, we can now create a kernel translation for
82662306a36Sopenharmony_ci	 * a 4K or 64K page from r16 -> r15.
82762306a36Sopenharmony_ci	 */
82862306a36Sopenharmony_ci	/* Now we build the MAS:
82962306a36Sopenharmony_ci	 *
83062306a36Sopenharmony_ci	 * MAS 0   :	Fully setup with defaults in MAS4 and TLBnCFG
83162306a36Sopenharmony_ci	 * MAS 1   :	Almost fully setup
83262306a36Sopenharmony_ci	 *               - PID already updated by caller if necessary
83362306a36Sopenharmony_ci	 *               - TSIZE for now is base page size always
83462306a36Sopenharmony_ci	 * MAS 2   :	Use defaults
83562306a36Sopenharmony_ci	 * MAS 3+7 :	Needs to be done
83662306a36Sopenharmony_ci	 *
83762306a36Sopenharmony_ci	 * So we only do MAS 2 and 3 for now...
83862306a36Sopenharmony_ci	 */
83962306a36Sopenharmony_ci	clrldi	r11,r15,4		/* remove region ID from RPN */
84062306a36Sopenharmony_ci	ori	r10,r11,1		/* Or-in SR */
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	srdi	r16,r10,32
84362306a36Sopenharmony_ci	mtspr	SPRN_MAS3,r10
84462306a36Sopenharmony_ci	mtspr	SPRN_MAS7,r16
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	tlbwe
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* Return to caller, normal case */
84962306a36Sopenharmony_ci	TLB_MISS_EPILOG_SUCCESS
85062306a36Sopenharmony_ci	rfi
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_civirt_page_table_tlb_miss_fault:
85362306a36Sopenharmony_ci	/* If we fault here, things are a little bit tricky. We need to call
85462306a36Sopenharmony_ci	 * either data or instruction store fault, and we need to retrieve
85562306a36Sopenharmony_ci	 * the original fault address and ESR (for data).
85662306a36Sopenharmony_ci	 *
85762306a36Sopenharmony_ci	 * The thing is, we know that in normal circumstances, this is
85862306a36Sopenharmony_ci	 * always called as a second level tlb miss for SW load or as a first
85962306a36Sopenharmony_ci	 * level TLB miss for HW load, so we should be able to peek at the
86062306a36Sopenharmony_ci	 * relevant information in the first exception frame in the PACA.
86162306a36Sopenharmony_ci	 *
86262306a36Sopenharmony_ci	 * However, we do need to double check that, because we may just hit
86362306a36Sopenharmony_ci	 * a stray kernel pointer or a userland attack trying to hit those
86462306a36Sopenharmony_ci	 * areas. If that is the case, we do a data fault. (We can't get here
86562306a36Sopenharmony_ci	 * from an instruction tlb miss anyway).
86662306a36Sopenharmony_ci	 *
86762306a36Sopenharmony_ci	 * Note also that when going to a fault, we must unwind the previous
86862306a36Sopenharmony_ci	 * level as well. Since we are doing that, we don't need to clear or
86962306a36Sopenharmony_ci	 * restore the TLB reservation neither.
87062306a36Sopenharmony_ci	 */
87162306a36Sopenharmony_ci	subf	r10,r13,r12
87262306a36Sopenharmony_ci	cmpldi	cr0,r10,PACA_EXTLB+EX_TLB_SIZE
87362306a36Sopenharmony_ci	bne-	virt_page_table_tlb_miss_whacko_fault
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/* We dig the original DEAR and ESR from slot 0 */
87662306a36Sopenharmony_ci	ld	r15,EX_TLB_DEAR+PACA_EXTLB(r13)
87762306a36Sopenharmony_ci	ld	r16,EX_TLB_ESR+PACA_EXTLB(r13)
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* We check for the "special" ESR value for instruction faults */
88062306a36Sopenharmony_ci	cmpdi	cr0,r16,-1
88162306a36Sopenharmony_ci	beq	1f
88262306a36Sopenharmony_ci	mtspr	SPRN_DEAR,r15
88362306a36Sopenharmony_ci	mtspr	SPRN_ESR,r16
88462306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
88562306a36Sopenharmony_ci	b	exc_data_storage_book3e
88662306a36Sopenharmony_ci1:	TLB_MISS_EPILOG_ERROR
88762306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_civirt_page_table_tlb_miss_whacko_fault:
89062306a36Sopenharmony_ci	/* The linear fault will restart everything so ESR and DEAR will
89162306a36Sopenharmony_ci	 * not have been clobbered, let's just fault with what we have
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
89462306a36Sopenharmony_ci	b	exc_data_storage_book3e
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci/**************************************************************
89862306a36Sopenharmony_ci *                                                            *
89962306a36Sopenharmony_ci * TLB miss handling for Book3E with hw page table support    *
90062306a36Sopenharmony_ci *                                                            *
90162306a36Sopenharmony_ci **************************************************************/
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/* Data TLB miss */
90562306a36Sopenharmony_ci	START_EXCEPTION(data_tlb_miss_htw)
90662306a36Sopenharmony_ci	TLB_MISS_PROLOG
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* Now we handle the fault proper. We only save DEAR in normal
90962306a36Sopenharmony_ci	 * fault case since that's the only interesting values here.
91062306a36Sopenharmony_ci	 * We could probably also optimize by not saving SRR0/1 in the
91162306a36Sopenharmony_ci	 * linear mapping case but I'll leave that for later
91262306a36Sopenharmony_ci	 */
91362306a36Sopenharmony_ci	mfspr	r14,SPRN_ESR
91462306a36Sopenharmony_ci	mfspr	r16,SPRN_DEAR		/* get faulting address */
91562306a36Sopenharmony_ci	srdi	r11,r16,44		/* get region */
91662306a36Sopenharmony_ci	xoris	r11,r11,0xc
91762306a36Sopenharmony_ci	cmpldi	cr0,r11,0		/* linear mapping ? */
91862306a36Sopenharmony_ci	beq	tlb_load_linear		/* yes -> go to linear map load */
91962306a36Sopenharmony_ci	cmpldi	cr1,r11,1		/* vmalloc mapping ? */
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
92262306a36Sopenharmony_ci	 */
92362306a36Sopenharmony_ci	srdi.	r11,r16,60		/* Check for user region */
92462306a36Sopenharmony_ci	ld	r15,PACAPGD(r13)	/* Load user pgdir */
92562306a36Sopenharmony_ci	beq	htw_tlb_miss
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	/* XXX replace the RMW cycles with immediate loads + writes */
92862306a36Sopenharmony_ci1:	mfspr	r10,SPRN_MAS1
92962306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1		/* Clear TID */
93062306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
93162306a36Sopenharmony_ci	ld	r15,PACA_KERNELPGD(r13)	/* Load kernel pgdir */
93262306a36Sopenharmony_ci	beq+	cr1,htw_tlb_miss
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* We got a crappy address, just fault with whatever DEAR and ESR
93562306a36Sopenharmony_ci	 * are here
93662306a36Sopenharmony_ci	 */
93762306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
93862306a36Sopenharmony_ci	b	exc_data_storage_book3e
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/* Instruction TLB miss */
94162306a36Sopenharmony_ci	START_EXCEPTION(instruction_tlb_miss_htw)
94262306a36Sopenharmony_ci	TLB_MISS_PROLOG
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* If we take a recursive fault, the second level handler may need
94562306a36Sopenharmony_ci	 * to know whether we are handling a data or instruction fault in
94662306a36Sopenharmony_ci	 * order to get to the right store fault handler. We provide that
94762306a36Sopenharmony_ci	 * info by keeping a crazy value for ESR in r14
94862306a36Sopenharmony_ci	 */
94962306a36Sopenharmony_ci	li	r14,-1	/* store to exception frame is done later */
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* Now we handle the fault proper. We only save DEAR in the non
95262306a36Sopenharmony_ci	 * linear mapping case since we know the linear mapping case will
95362306a36Sopenharmony_ci	 * not re-enter. We could indeed optimize and also not save SRR0/1
95462306a36Sopenharmony_ci	 * in the linear mapping case but I'll leave that for later
95562306a36Sopenharmony_ci	 *
95662306a36Sopenharmony_ci	 * Faulting address is SRR0 which is already in r16
95762306a36Sopenharmony_ci	 */
95862306a36Sopenharmony_ci	srdi	r11,r16,44		/* get region */
95962306a36Sopenharmony_ci	xoris	r11,r11,0xc
96062306a36Sopenharmony_ci	cmpldi	cr0,r11,0		/* linear mapping ? */
96162306a36Sopenharmony_ci	beq	tlb_load_linear		/* yes -> go to linear map load */
96262306a36Sopenharmony_ci	cmpldi	cr1,r11,1		/* vmalloc mapping ? */
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	/* We do the user/kernel test for the PID here along with the RW test
96562306a36Sopenharmony_ci	 */
96662306a36Sopenharmony_ci	srdi.	r11,r16,60		/* Check for user region */
96762306a36Sopenharmony_ci	ld	r15,PACAPGD(r13)		/* Load user pgdir */
96862306a36Sopenharmony_ci	beq	htw_tlb_miss
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/* XXX replace the RMW cycles with immediate loads + writes */
97162306a36Sopenharmony_ci1:	mfspr	r10,SPRN_MAS1
97262306a36Sopenharmony_ci	rlwinm	r10,r10,0,16,1			/* Clear TID */
97362306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r10
97462306a36Sopenharmony_ci	ld	r15,PACA_KERNELPGD(r13)		/* Load kernel pgdir */
97562306a36Sopenharmony_ci	beq+	htw_tlb_miss
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* We got a crappy address, just fault */
97862306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
97962306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci/*
98362306a36Sopenharmony_ci * This is the guts of the second-level TLB miss handler for direct
98462306a36Sopenharmony_ci * misses. We are entered with:
98562306a36Sopenharmony_ci *
98662306a36Sopenharmony_ci * r16 = virtual page table faulting address
98762306a36Sopenharmony_ci * r15 = PGD pointer
98862306a36Sopenharmony_ci * r14 = ESR
98962306a36Sopenharmony_ci * r13 = PACA
99062306a36Sopenharmony_ci * r12 = TLB exception frame in PACA
99162306a36Sopenharmony_ci * r11 = crap (free to use)
99262306a36Sopenharmony_ci * r10 = crap (free to use)
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * It can be re-entered by the linear mapping miss handler. However, to
99562306a36Sopenharmony_ci * avoid too much complication, it will save/restore things for us
99662306a36Sopenharmony_ci */
99762306a36Sopenharmony_cihtw_tlb_miss:
99862306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
99962306a36Sopenharmony_ci	mfspr	r10,SPRN_MAS1
100062306a36Sopenharmony_ci	rlwinm.	r10,r10,0,0x3fff0000
100162306a36Sopenharmony_ci	beq-	htw_tlb_miss_fault /* KUAP fault */
100262306a36Sopenharmony_ci#endif
100362306a36Sopenharmony_ci	/* Search if we already have a TLB entry for that virtual address, and
100462306a36Sopenharmony_ci	 * if we do, bail out.
100562306a36Sopenharmony_ci	 *
100662306a36Sopenharmony_ci	 * MAS1:IND should be already set based on MAS4
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	PPC_TLBSRX_DOT(0,R16)
100962306a36Sopenharmony_ci	beq	htw_tlb_miss_done
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* Now, we need to walk the page tables. First check if we are in
101262306a36Sopenharmony_ci	 * range.
101362306a36Sopenharmony_ci	 */
101462306a36Sopenharmony_ci	rldicl.	r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
101562306a36Sopenharmony_ci	bne-	htw_tlb_miss_fault
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* Get the PGD pointer */
101862306a36Sopenharmony_ci	cmpldi	cr0,r15,0
101962306a36Sopenharmony_ci	beq-	htw_tlb_miss_fault
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/* Get to PGD entry */
102262306a36Sopenharmony_ci	rldicl	r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3
102362306a36Sopenharmony_ci	clrrdi	r10,r11,3
102462306a36Sopenharmony_ci	ldx	r15,r10,r15
102562306a36Sopenharmony_ci	cmpdi	cr0,r15,0
102662306a36Sopenharmony_ci	bge	htw_tlb_miss_fault
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* Get to PUD entry */
102962306a36Sopenharmony_ci	rldicl	r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3
103062306a36Sopenharmony_ci	clrrdi	r10,r11,3
103162306a36Sopenharmony_ci	ldx	r15,r10,r15
103262306a36Sopenharmony_ci	cmpdi	cr0,r15,0
103362306a36Sopenharmony_ci	bge	htw_tlb_miss_fault
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Get to PMD entry */
103662306a36Sopenharmony_ci	rldicl	r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3
103762306a36Sopenharmony_ci	clrrdi	r10,r11,3
103862306a36Sopenharmony_ci	ldx	r15,r10,r15
103962306a36Sopenharmony_ci	cmpdi	cr0,r15,0
104062306a36Sopenharmony_ci	bge	htw_tlb_miss_fault
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* Ok, we're all right, we can now create an indirect entry for
104362306a36Sopenharmony_ci	 * a 1M or 256M page.
104462306a36Sopenharmony_ci	 *
104562306a36Sopenharmony_ci	 * The last trick is now that because we use "half" pages for
104662306a36Sopenharmony_ci	 * the HTW (1M IND is 2K and 256M IND is 32K) we need to account
104762306a36Sopenharmony_ci	 * for an added LSB bit to the RPN. For 64K pages, there is no
104862306a36Sopenharmony_ci	 * problem as we already use 32K arrays (half PTE pages), but for
104962306a36Sopenharmony_ci	 * 4K page we need to extract a bit from the virtual address and
105062306a36Sopenharmony_ci	 * insert it into the "PA52" bit of the RPN.
105162306a36Sopenharmony_ci	 */
105262306a36Sopenharmony_ci	rlwimi	r15,r16,32-9,20,20
105362306a36Sopenharmony_ci	/* Now we build the MAS:
105462306a36Sopenharmony_ci	 *
105562306a36Sopenharmony_ci	 * MAS 0   :	Fully setup with defaults in MAS4 and TLBnCFG
105662306a36Sopenharmony_ci	 * MAS 1   :	Almost fully setup
105762306a36Sopenharmony_ci	 *               - PID already updated by caller if necessary
105862306a36Sopenharmony_ci	 *               - TSIZE for now is base ind page size always
105962306a36Sopenharmony_ci	 * MAS 2   :	Use defaults
106062306a36Sopenharmony_ci	 * MAS 3+7 :	Needs to be done
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	ori	r10,r15,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	srdi	r16,r10,32
106562306a36Sopenharmony_ci	mtspr	SPRN_MAS3,r10
106662306a36Sopenharmony_ci	mtspr	SPRN_MAS7,r16
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	tlbwe
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cihtw_tlb_miss_done:
107162306a36Sopenharmony_ci	/* We don't bother with restoring DEAR or ESR since we know we are
107262306a36Sopenharmony_ci	 * level 0 and just going back to userland. They are only needed
107362306a36Sopenharmony_ci	 * if you are going to take an access fault
107462306a36Sopenharmony_ci	 */
107562306a36Sopenharmony_ci	TLB_MISS_EPILOG_SUCCESS
107662306a36Sopenharmony_ci	rfi
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cihtw_tlb_miss_fault:
107962306a36Sopenharmony_ci	/* We need to check if it was an instruction miss. We know this
108062306a36Sopenharmony_ci	 * though because r14 would contain -1
108162306a36Sopenharmony_ci	 */
108262306a36Sopenharmony_ci	cmpdi	cr0,r14,-1
108362306a36Sopenharmony_ci	beq	1f
108462306a36Sopenharmony_ci	mtspr	SPRN_DEAR,r16
108562306a36Sopenharmony_ci	mtspr	SPRN_ESR,r14
108662306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
108762306a36Sopenharmony_ci	b	exc_data_storage_book3e
108862306a36Sopenharmony_ci1:	TLB_MISS_EPILOG_ERROR
108962306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci/*
109262306a36Sopenharmony_ci * This is the guts of "any" level TLB miss handler for kernel linear
109362306a36Sopenharmony_ci * mapping misses. We are entered with:
109462306a36Sopenharmony_ci *
109562306a36Sopenharmony_ci *
109662306a36Sopenharmony_ci * r16 = faulting address
109762306a36Sopenharmony_ci * r15 = crap (free to use)
109862306a36Sopenharmony_ci * r14 = ESR (data) or -1 (instruction)
109962306a36Sopenharmony_ci * r13 = PACA
110062306a36Sopenharmony_ci * r12 = TLB exception frame in PACA
110162306a36Sopenharmony_ci * r11 = crap (free to use)
110262306a36Sopenharmony_ci * r10 = crap (free to use)
110362306a36Sopenharmony_ci *
110462306a36Sopenharmony_ci * In addition we know that we will not re-enter, so in theory, we could
110562306a36Sopenharmony_ci * use a simpler epilog not restoring SRR0/1 etc.. but we'll do that later.
110662306a36Sopenharmony_ci *
110762306a36Sopenharmony_ci * We also need to be careful about MAS registers here & TLB reservation,
110862306a36Sopenharmony_ci * as we know we'll have clobbered them if we interrupt the main TLB miss
110962306a36Sopenharmony_ci * handlers in which case we probably want to do a full restart at level
111062306a36Sopenharmony_ci * 0 rather than saving / restoring the MAS.
111162306a36Sopenharmony_ci *
111262306a36Sopenharmony_ci * Note: If we care about performance of that core, we can easily shuffle
111362306a36Sopenharmony_ci *       a few things around
111462306a36Sopenharmony_ci */
111562306a36Sopenharmony_citlb_load_linear:
111662306a36Sopenharmony_ci	/* For now, we assume the linear mapping is contiguous and stops at
111762306a36Sopenharmony_ci	 * linear_map_top. We also assume the size is a multiple of 1G, thus
111862306a36Sopenharmony_ci	 * we only use 1G pages for now. That might have to be changed in a
111962306a36Sopenharmony_ci	 * final implementation, especially when dealing with hypervisors
112062306a36Sopenharmony_ci	 */
112162306a36Sopenharmony_ci	__LOAD_PACA_TOC(r11)
112262306a36Sopenharmony_ci	LOAD_REG_ADDR_ALTTOC(r11, r11, linear_map_top)
112362306a36Sopenharmony_ci	ld	r10,0(r11)
112462306a36Sopenharmony_ci	tovirt(10,10)
112562306a36Sopenharmony_ci	cmpld	cr0,r16,r10
112662306a36Sopenharmony_ci	bge	tlb_load_linear_fault
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	/* MAS1 need whole new setup. */
112962306a36Sopenharmony_ci	li	r15,(BOOK3E_PAGESZ_1GB<<MAS1_TSIZE_SHIFT)
113062306a36Sopenharmony_ci	oris	r15,r15,MAS1_VALID@h	/* MAS1 needs V and TSIZE */
113162306a36Sopenharmony_ci	mtspr	SPRN_MAS1,r15
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* Already somebody there ? */
113462306a36Sopenharmony_ci	PPC_TLBSRX_DOT(0,R16)
113562306a36Sopenharmony_ci	beq	tlb_load_linear_done
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	/* Now we build the remaining MAS. MAS0 and 2 should be fine
113862306a36Sopenharmony_ci	 * with their defaults, which leaves us with MAS 3 and 7. The
113962306a36Sopenharmony_ci	 * mapping is linear, so we just take the address, clear the
114062306a36Sopenharmony_ci	 * region bits, and or in the permission bits which are currently
114162306a36Sopenharmony_ci	 * hard wired
114262306a36Sopenharmony_ci	 */
114362306a36Sopenharmony_ci	clrrdi	r10,r16,30		/* 1G page index */
114462306a36Sopenharmony_ci	clrldi	r10,r10,4		/* clear region bits */
114562306a36Sopenharmony_ci	ori	r10,r10,MAS3_SR|MAS3_SW|MAS3_SX
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	srdi	r16,r10,32
114862306a36Sopenharmony_ci	mtspr	SPRN_MAS3,r10
114962306a36Sopenharmony_ci	mtspr	SPRN_MAS7,r16
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	tlbwe
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_citlb_load_linear_done:
115462306a36Sopenharmony_ci	/* We use the "error" epilog for success as we do want to
115562306a36Sopenharmony_ci	 * restore to the initial faulting context, whatever it was.
115662306a36Sopenharmony_ci	 * We do that because we can't resume a fault within a TLB
115762306a36Sopenharmony_ci	 * miss handler, due to MAS and TLB reservation being clobbered.
115862306a36Sopenharmony_ci	 */
115962306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR
116062306a36Sopenharmony_ci	rfi
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_citlb_load_linear_fault:
116362306a36Sopenharmony_ci	/* We keep the DEAR and ESR around, this shouldn't have happened */
116462306a36Sopenharmony_ci	cmpdi	cr0,r14,-1
116562306a36Sopenharmony_ci	beq	1f
116662306a36Sopenharmony_ci	TLB_MISS_EPILOG_ERROR_SPECIAL
116762306a36Sopenharmony_ci	b	exc_data_storage_book3e
116862306a36Sopenharmony_ci1:	TLB_MISS_EPILOG_ERROR_SPECIAL
116962306a36Sopenharmony_ci	b	exc_instruction_storage_book3e
1170