arch/x86/boot/startup/sme.c

Source file repositories/reference/linux-study-clean/arch/x86/boot/startup/sme.c

File Facts

System
Linux kernel
Corpus path
arch/x86/boot/startup/sme.c
Extension
.c
Size
17290 bytes
Lines
578
Domain
Architecture Layer
Bucket
arch/x86
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

struct sme_populate_pgd_data {
	void    *pgtable_area;
	pgd_t   *pgd;

	pmdval_t pmd_flags;
	pteval_t pte_flags;
	unsigned long paddr;

	unsigned long vaddr;
	unsigned long vaddr_end;
};

/*
 * This work area lives in the .init.scratch section, which lives outside of
 * the kernel proper. It is sized to hold the intermediate copy buffer and
 * more than enough pagetable pages.
 *
 * By using this section, the kernel can be encrypted in place and it
 * avoids any possibility of boot parameters or initramfs images being
 * placed such that the in-place encryption logic overwrites them.  This
 * section is 2MB aligned to allow for simple pagetable setup using only
 * PMD entries (see vmlinux.lds.S).
 */
static char sme_workarea[2 * PMD_SIZE] __section(".init.scratch");

static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
{
	unsigned long pgd_start, pgd_end, pgd_size;
	pgd_t *pgd_p;

	pgd_start = ppd->vaddr & PGDIR_MASK;
	pgd_end = ppd->vaddr_end & PGDIR_MASK;

	pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);

	pgd_p = ppd->pgd + pgd_index(ppd->vaddr);

	memset(pgd_p, 0, pgd_size);
}

static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
{
	pgd_t *pgd;
	p4d_t *p4d;
	pud_t *pud;
	pmd_t *pmd;

	pgd = ppd->pgd + pgd_index(ppd->vaddr);
	if (pgd_none(*pgd)) {
		p4d = ppd->pgtable_area;
		memset(p4d, 0, sizeof(*p4d) * PTRS_PER_P4D);
		ppd->pgtable_area += sizeof(*p4d) * PTRS_PER_P4D;
		set_pgd(pgd, __pgd(PGD_FLAGS | __pa(p4d)));
	}

	p4d = p4d_offset(pgd, ppd->vaddr);
	if (p4d_none(*p4d)) {
		pud = ppd->pgtable_area;
		memset(pud, 0, sizeof(*pud) * PTRS_PER_PUD);
		ppd->pgtable_area += sizeof(*pud) * PTRS_PER_PUD;
		set_p4d(p4d, __p4d(P4D_FLAGS | __pa(pud)));
	}

	pud = pud_offset(p4d, ppd->vaddr);
	if (pud_none(*pud)) {
		pmd = ppd->pgtable_area;
		memset(pmd, 0, sizeof(*pmd) * PTRS_PER_PMD);
		ppd->pgtable_area += sizeof(*pmd) * PTRS_PER_PMD;
		set_pud(pud, __pud(PUD_FLAGS | __pa(pmd)));
	}

	if (pud_leaf(*pud))
		return NULL;

	return pud;
}

static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
{
	pud_t *pud;
	pmd_t *pmd;

	pud = sme_prepare_pgd(ppd);
	if (!pud)
		return;

	pmd = pmd_offset(pud, ppd->vaddr);
	if (pmd_leaf(*pmd))
		return;

Annotation

Implementation Notes