cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

book3e_hugetlbpage.c (4422B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PPC Huge TLB Page Support for Book3E MMU
      4 *
      5 * Copyright (C) 2009 David Gibson, IBM Corporation.
      6 * Copyright (C) 2011 Becky Bruce, Freescale Semiconductor
      7 *
      8 */
      9#include <linux/mm.h>
     10#include <linux/hugetlb.h>
     11
     12#include <asm/mmu.h>
     13
     14#ifdef CONFIG_PPC64
     15#include <asm/paca.h>
     16
     17static inline int tlb1_next(void)
     18{
     19	struct paca_struct *paca = get_paca();
     20	struct tlb_core_data *tcd;
     21	int this, next;
     22
     23	tcd = paca->tcd_ptr;
     24	this = tcd->esel_next;
     25
     26	next = this + 1;
     27	if (next >= tcd->esel_max)
     28		next = tcd->esel_first;
     29
     30	tcd->esel_next = next;
     31	return this;
     32}
     33
     34static inline void book3e_tlb_lock(void)
     35{
     36	struct paca_struct *paca = get_paca();
     37	unsigned long tmp;
     38	int token = smp_processor_id() + 1;
     39
     40	/*
     41	 * Besides being unnecessary in the absence of SMT, this
     42	 * check prevents trying to do lbarx/stbcx. on e5500 which
     43	 * doesn't implement either feature.
     44	 */
     45	if (!cpu_has_feature(CPU_FTR_SMT))
     46		return;
     47
     48	asm volatile("1: lbarx %0, 0, %1;"
     49		     "cmpwi %0, 0;"
     50		     "bne 2f;"
     51		     "stbcx. %2, 0, %1;"
     52		     "bne 1b;"
     53		     "b 3f;"
     54		     "2: lbzx %0, 0, %1;"
     55		     "cmpwi %0, 0;"
     56		     "bne 2b;"
     57		     "b 1b;"
     58		     "3:"
     59		     : "=&r" (tmp)
     60		     : "r" (&paca->tcd_ptr->lock), "r" (token)
     61		     : "memory");
     62}
     63
     64static inline void book3e_tlb_unlock(void)
     65{
     66	struct paca_struct *paca = get_paca();
     67
     68	if (!cpu_has_feature(CPU_FTR_SMT))
     69		return;
     70
     71	isync();
     72	paca->tcd_ptr->lock = 0;
     73}
     74#else
     75static inline int tlb1_next(void)
     76{
     77	int index, ncams;
     78
     79	ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
     80
     81	index = this_cpu_read(next_tlbcam_idx);
     82
     83	/* Just round-robin the entries and wrap when we hit the end */
     84	if (unlikely(index == ncams - 1))
     85		__this_cpu_write(next_tlbcam_idx, tlbcam_index);
     86	else
     87		__this_cpu_inc(next_tlbcam_idx);
     88
     89	return index;
     90}
     91
     92static inline void book3e_tlb_lock(void)
     93{
     94}
     95
     96static inline void book3e_tlb_unlock(void)
     97{
     98}
     99#endif
    100
    101static inline int book3e_tlb_exists(unsigned long ea, unsigned long pid)
    102{
    103	int found = 0;
    104
    105	mtspr(SPRN_MAS6, pid << 16);
    106	if (mmu_has_feature(MMU_FTR_USE_TLBRSRV)) {
    107		asm volatile(
    108			"li	%0,0\n"
    109			"tlbsx.	0,%1\n"
    110			"bne	1f\n"
    111			"li	%0,1\n"
    112			"1:\n"
    113			: "=&r"(found) : "r"(ea));
    114	} else {
    115		asm volatile(
    116			"tlbsx	0,%1\n"
    117			"mfspr	%0,0x271\n"
    118			"srwi	%0,%0,31\n"
    119			: "=&r"(found) : "r"(ea));
    120	}
    121
    122	return found;
    123}
    124
    125static void
    126book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, pte_t pte)
    127{
    128	unsigned long mas1, mas2;
    129	u64 mas7_3;
    130	unsigned long psize, tsize, shift;
    131	unsigned long flags;
    132	struct mm_struct *mm;
    133	int index;
    134
    135	if (unlikely(is_kernel_addr(ea)))
    136		return;
    137
    138	mm = vma->vm_mm;
    139
    140	psize = vma_mmu_pagesize(vma);
    141	shift = __ilog2(psize);
    142	tsize = shift - 10;
    143	/*
    144	 * We can't be interrupted while we're setting up the MAS
    145	 * registers or after we've confirmed that no tlb exists.
    146	 */
    147	local_irq_save(flags);
    148
    149	book3e_tlb_lock();
    150
    151	if (unlikely(book3e_tlb_exists(ea, mm->context.id))) {
    152		book3e_tlb_unlock();
    153		local_irq_restore(flags);
    154		return;
    155	}
    156
    157	/* We have to use the CAM(TLB1) on FSL parts for hugepages */
    158	index = tlb1_next();
    159	mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1));
    160
    161	mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize);
    162	mas2 = ea & ~((1UL << shift) - 1);
    163	mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK;
    164	mas7_3 = (u64)pte_pfn(pte) << PAGE_SHIFT;
    165	mas7_3 |= (pte_val(pte) >> PTE_BAP_SHIFT) & MAS3_BAP_MASK;
    166	if (!pte_dirty(pte))
    167		mas7_3 &= ~(MAS3_SW|MAS3_UW);
    168
    169	mtspr(SPRN_MAS1, mas1);
    170	mtspr(SPRN_MAS2, mas2);
    171
    172	if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) {
    173		mtspr(SPRN_MAS7_MAS3, mas7_3);
    174	} else {
    175		if (mmu_has_feature(MMU_FTR_BIG_PHYS))
    176			mtspr(SPRN_MAS7, upper_32_bits(mas7_3));
    177		mtspr(SPRN_MAS3, lower_32_bits(mas7_3));
    178	}
    179
    180	asm volatile ("tlbwe");
    181
    182	book3e_tlb_unlock();
    183	local_irq_restore(flags);
    184}
    185
    186/*
    187 * This is called at the end of handling a user page fault, when the
    188 * fault has been handled by updating a PTE in the linux page tables.
    189 *
    190 * This must always be called with the pte lock held.
    191 */
    192void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
    193{
    194	if (is_vm_hugetlb_page(vma))
    195		book3e_hugetlb_preload(vma, address, *ptep);
    196}
    197
    198void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
    199{
    200	struct hstate *hstate = hstate_file(vma->vm_file);
    201	unsigned long tsize = huge_page_shift(hstate) - 10;
    202
    203	__flush_tlb_page(vma->vm_mm, vmaddr, tsize, 0);
    204}