arch/powerpc/mm/book3s32/mmu.c

Source file repositories/reference/linux-study-clean/arch/powerpc/mm/book3s32/mmu.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/mm/book3s32/mmu.c
Extension
.c
Size
12150 bytes
Lines
445
Domain
Architecture Layer
Bucket
arch/powerpc
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 ((top - base) > size) {
			size <<= 1;
			if (strict_kernel_rwx_enabled() && base + size > border)
				pr_warn("Some RW data is getting mapped X. "
					"Adjust CONFIG_DATA_SHIFT to avoid that.\n");
		}
		setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_X);
		base += size;
	}
	for (; i < nb; i++)
		clearibat(i);

	update_bats();

	for (i = ALIGN(TASK_SIZE, SZ_256M) >> 28; i < 16; i++) {
		/* Do not set NX on VM space for modules */
		if (is_module_segment(i << 28))
			continue;

		mtsr(mfsr(i << 28) | 0x10000000, i << 28);
	}
	return 0;
}

int mmu_mark_rodata_ro(void)
{
	int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
	int i;

	for (i = 0; i < nb; i++) {
		struct ppc_bat *bat = BATS[i];

		if (bat_addrs[i].start < (unsigned long)__end_rodata)
			bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
	}

	update_bats();

	return 0;
}

/*
 * Set up one of the D BAT (block address translation) register pairs.
 * The parameters are not checked; in particular size must be a power
 * of 2 between 128k and 256M.
 */
void __init setbat(int index, unsigned long virt, phys_addr_t phys,
		   unsigned int size, pgprot_t prot)
{
	unsigned int bl;
	int wimgxpp;
	struct ppc_bat *bat;
	unsigned long flags = pgprot_val(prot);

	if (index == -1)
		index = find_free_bat();
	if (index == -1) {
		pr_err("%s: no BAT available for mapping 0x%llx\n", __func__,
		       (unsigned long long)phys);
		return;
	}
	bat = BATS[index];

	if ((flags & _PAGE_NO_CACHE) ||
	    (cpu_has_feature(CPU_FTR_NEED_COHERENT) == 0))
		flags &= ~_PAGE_COHERENT;

	bl = (size >> 17) - 1;
	/* Do DBAT first */
	wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
			   | _PAGE_COHERENT | _PAGE_GUARDED);
	wimgxpp |= (flags & _PAGE_WRITE) ? BPP_RW : BPP_RX;
	bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
	bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
	if (!is_kernel_addr(virt))
		bat[1].batu |= 1; 	/* Vp = 1 */
	if (flags & _PAGE_GUARDED) {
		/* G bit must be zero in IBATs */
		flags &= ~_PAGE_EXEC;
	}

	bat_addrs[index].start = virt;
	bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
	bat_addrs[index].phys = phys;
}

/*
 * Preload a translation in the hash table
 */
static void hash_preload(struct mm_struct *mm, unsigned long ea)

Annotation

Implementation Notes