arch/arm/mm/fault-armv.c

Source file repositories/reference/linux-study-clean/arch/arm/mm/fault-armv.c

File Facts

System
Linux kernel
Corpus path
arch/arm/mm/fault-armv.c
Extension
.c
Size
7126 bytes
Lines
277
Domain
Architecture Layer
Bucket
arch/arm
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 (unlikely(!pmd_same(pmdval, pmdp_get_lockless(pmd)))) {
			pte_unmap_unlock(pte, ptl);
			goto again;
		}
	}

	ret = do_adjust_pte(vma, address, pfn, pte);

	if (need_lock)
		spin_unlock(ptl);
	pte_unmap(pte);

	return ret;
}

static void
make_coherent(struct address_space *mapping, struct vm_area_struct *vma,
	      unsigned long addr, pte_t *ptep, unsigned long pfn)
{
	const unsigned long pmd_start_addr = ALIGN_DOWN(addr, PMD_SIZE);
	const unsigned long pmd_end_addr = pmd_start_addr + PMD_SIZE;
	struct mm_struct *mm = vma->vm_mm;
	struct vm_area_struct *mpnt;
	unsigned long offset;
	pgoff_t pgoff;
	int aliases = 0;

	pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);

	/*
	 * If we have any shared mappings that are in the same mm
	 * space, then we need to handle them specially to maintain
	 * cache coherency.
	 */
	flush_dcache_mmap_lock(mapping);
	vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) {
		/*
		 * If we are using split PTE locks, then we need to take the pte
		 * lock. Otherwise we are using shared mm->page_table_lock which
		 * is already locked, thus cannot take it.
		 */
		bool need_lock = IS_ENABLED(CONFIG_SPLIT_PTE_PTLOCKS);
		unsigned long mpnt_addr;

		/*
		 * If this VMA is not in our MM, we can ignore it.
		 * Note that we intentionally mask out the VMA
		 * that we are fixing up.
		 */
		if (mpnt->vm_mm != mm || mpnt == vma)
			continue;
		if (!(mpnt->vm_flags & VM_MAYSHARE))
			continue;
		offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
		mpnt_addr = mpnt->vm_start + offset;

		/* Avoid deadlocks by not grabbing the same PTE lock again. */
		if (mpnt_addr >= pmd_start_addr && mpnt_addr < pmd_end_addr)
			need_lock = false;
		aliases += adjust_pte(mpnt, mpnt_addr, pfn, need_lock);
	}
	flush_dcache_mmap_unlock(mapping);
	if (aliases)
		do_adjust_pte(vma, addr, pfn, ptep);
}

/*
 * Take care of architecture specific things when placing a new PTE into
 * a page table, or changing an existing PTE.  Basically, there are two
 * things that we need to take care of:
 *
 *  1. If PG_dcache_clean is not set for the page, we need to ensure
 *     that any cache entries for the kernels virtual memory
 *     range are written back to the page.
 *  2. If we have multiple shared mappings of the same space in
 *     an object, we need to deal with the cache aliasing issues.
 *
 * Note that the pte lock will be held.
 */
void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma,
		unsigned long addr, pte_t *ptep, unsigned int nr)
{
	unsigned long pfn = pte_pfn(*ptep);
	struct address_space *mapping;
	struct folio *folio;

	if (!pfn_valid(pfn))
		return;

	/*

Annotation

Implementation Notes