arch/powerpc/mm/book3s64/pkeys.c

Source file repositories/reference/linux-study-clean/arch/powerpc/mm/book3s64/pkeys.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/mm/book3s64/pkeys.c
Extension
.c
Size
12253 bytes
Lines
471
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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 (!firmware_has_feature(FW_FEATURE_LPAR)) {
			unsigned long pvr = mfspr(SPRN_PVR);

			if (PVR_VER(pvr) == PVR_POWER8 || PVR_VER(pvr) == PVR_POWER8E ||
			    PVR_VER(pvr) == PVR_POWER8NVL || PVR_VER(pvr) == PVR_POWER9 ||
			    PVR_VER(pvr) == PVR_HX_C2000)
				pkeys_total = 32;
		}
	}

#ifdef CONFIG_PPC_MEM_KEYS
	/*
	 * Adjust the upper limit, based on the number of bits supported by
	 * arch-neutral code.
	 */
	pkeys_total = min_t(int, pkeys_total,
			    ((ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT) + 1));
#endif
	return pkeys_total;
}

void __init pkey_early_init_devtree(void)
{
	int pkeys_total, i;

#ifdef CONFIG_PPC_MEM_KEYS
	/*
	 * We define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
	 * Ensure that the bits a distinct.
	 */
	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));

	/*
	 * pkey_to_vmflag_bits() assumes that the pkey bits are contiguous
	 * in the vmaflag. Make sure that is really the case.
	 */
	BUILD_BUG_ON(__builtin_clzl(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT) +
		     __builtin_popcountl(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT)
				!= (sizeof(u64) * BITS_PER_BYTE));
#endif
	/*
	 * Only P7 and above supports SPRN_AMR update with MSR[PR] = 1
	 */
	if (!early_cpu_has_feature(CPU_FTR_ARCH_206))
		return;

	/* scan the device tree for pkey feature */
	pkeys_total = scan_pkey_feature();
	if (!pkeys_total)
		goto out;

	/* Allow all keys to be modified by default */
	default_uamor = ~0x0UL;

	cur_cpu_spec->mmu_features |= MMU_FTR_PKEY;

	/*
	 * The device tree cannot be relied to indicate support for
	 * execute_disable support. Instead we use a PVR check.
	 */
	if (pvr_version_is(PVR_POWER7) || pvr_version_is(PVR_POWER7p))
		pkey_execute_disable_supported = false;
	else
		pkey_execute_disable_supported = true;

#ifdef CONFIG_PPC_4K_PAGES
	/*
	 * The OS can manage only 8 pkeys due to its inability to represent them
	 * in the Linux 4K PTE. Mark all other keys reserved.
	 */
	num_pkey = min(8, pkeys_total);
#else
	num_pkey = pkeys_total;
#endif

	if (unlikely(num_pkey <= execute_only_key) || !pkey_execute_disable_supported) {
		/*
		 * Insufficient number of keys to support
		 * execute only key. Mark it unavailable.
		 */
		execute_only_key = -1;
	} else {
		/*
		 * Mark the execute_only_pkey as not available for
		 * user allocation via pkey_alloc.
		 */
		reserved_allocation_mask |= (0x1 << execute_only_key);

Annotation

Implementation Notes