arch/arm/mm/pgd.c

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

File Facts

System
Linux kernel
Corpus path
arch/arm/mm/pgd.c
Extension
.c
Size
4550 bytes
Lines
210
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/arch/arm/mm/pgd.c
 *
 *  Copyright (C) 1998-2005 Russell King
 */
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/highmem.h>
#include <linux/slab.h>

#include <asm/cp15.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
#include <asm/tlbflush.h>

#include "mm.h"

#ifdef CONFIG_ARM_LPAE
#define _pgd_alloc(mm)		kmalloc_objs(pgd_t, PTRS_PER_PGD, GFP_KERNEL | __GFP_ZERO)
#define _pgd_free(mm, pgd)	kfree(pgd)
#else
#define _pgd_alloc(mm)		__pgd_alloc(mm, 2)
#define _pgd_free(mm, pgd)	__pgd_free(mm, pgd)
#endif

/*
 * need to get a 16k page for level 1
 */
pgd_t *pgd_alloc(struct mm_struct *mm)
{
	pgd_t *new_pgd, *init_pgd;
	p4d_t *new_p4d, *init_p4d;
	pud_t *new_pud, *init_pud;
	pmd_t *new_pmd, *init_pmd;
	pte_t *new_pte, *init_pte;

	new_pgd = _pgd_alloc(mm);
	if (!new_pgd)
		goto no_pgd;

	/*
	 * Copy over the kernel and IO PGD entries
	 */
	init_pgd = pgd_offset_k(0);
	memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));

	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));

#ifdef CONFIG_ARM_LPAE
	/*
	 * Allocate PMD table for modules and pkmap mappings.
	 */
	new_p4d = p4d_alloc(mm, new_pgd + pgd_index(MODULES_VADDR),
			    MODULES_VADDR);
	if (!new_p4d)
		goto no_p4d;

	new_pud = pud_alloc(mm, new_p4d, MODULES_VADDR);
	if (!new_pud)
		goto no_pud;

	new_pmd = pmd_alloc(mm, new_pud, 0);
	if (!new_pmd)
		goto no_pmd;
#ifdef CONFIG_KASAN
	/*
	 * Copy PMD table for KASAN shadow mappings.
	 */
	init_pgd = pgd_offset_k(TASK_SIZE);
	init_p4d = p4d_offset(init_pgd, TASK_SIZE);
	init_pud = pud_offset(init_p4d, TASK_SIZE);
	init_pmd = pmd_offset(init_pud, TASK_SIZE);
	new_pmd = pmd_offset(new_pud, TASK_SIZE);
	memcpy(new_pmd, init_pmd,
	       (pmd_index(MODULES_VADDR) - pmd_index(TASK_SIZE))
	       * sizeof(pmd_t));
	clean_dcache_area(new_pmd, PTRS_PER_PMD * sizeof(pmd_t));
#endif /* CONFIG_KASAN */
#endif /* CONFIG_LPAE */

	if (!vectors_high()) {
		/*
		 * On ARM, first page must always be allocated since it
		 * contains the machine vectors. The vectors are always high
		 * with LPAE.
		 */
		new_p4d = p4d_alloc(mm, new_pgd, 0);
		if (!new_p4d)

Annotation

Implementation Notes