mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-23 16:24:15 +00:00
In system_supports_bti() we use cpus_have_const_cap() to check for ARM64_HAS_BTI, but this is not necessary and alternative_has_cap_*() or cpus_have_final_*cap() would be preferable. For historical reasons, cpus_have_const_cap() is more complicated than it needs to be. Before cpucaps are finalized, it will perform a bitmap test of the system_cpucaps bitmap, and once cpucaps are finalized it will use an alternative branch. This used to be necessary to handle some race conditions in the window between cpucap detection and the subsequent patching of alternatives and static branches, where different branches could be out-of-sync with one another (or w.r.t. alternative sequences). Now that we use alternative branches instead of static branches, these are all patched atomically w.r.t. one another, and there are only a handful of cases that need special care in the window between cpucap detection and alternative patching. Due to the above, it would be nice to remove cpus_have_const_cap(), and migrate callers over to alternative_has_cap_*(), cpus_have_final_cap(), or cpus_have_cap() depending on when their requirements. This will remove redundant instructions and improve code generation, and will make it easier to determine how each callsite will behave before, during, and after alternative patching. When CONFIG_ARM64_BTI_KERNEL=y, the ARM64_HAS_BTI cpucap is a strict boot cpu feature which is detected and patched early on the boot cpu. All uses guarded by CONFIG_ARM64_BTI_KERNEL happen after the boot CPU has detected ARM64_HAS_BTI and patched boot alternatives, and hence can safely use alternative_has_cap_*() or cpus_have_final_boot_cap(). Regardless of CONFIG_ARM64_BTI_KERNEL, all other uses of ARM64_HAS_BTI happen after system capabilities have been finalized and alternatives have been patched. Hence these can safely use alternative_has_cap_*) or cpus_have_final_cap(). This patch splits system_supports_bti() into system_supports_bti() and system_supports_bti_kernel(), with the former handling where the cpucap affects userspace functionality, and ther latter handling where the cpucap affects kernel functionality. The use of cpus_have_const_cap() is replaced by cpus_have_final_cap() in cpus_have_const_cap, and cpus_have_final_boot_cap() in system_supports_bti_kernel(). This will avoid generating code to test the system_cpucaps bitmap and should be better for all subsequent calls at runtime. The use of cpus_have_final_cap() and cpus_have_final_boot_cap() will make it easier to spot if code is chaanged such that these run before the ARM64_HAS_BTI cpucap is guaranteed to have been finalized. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Mark Brown <broonie@kernel.org> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Suzuki K Poulose <suzuki.poulose@arm.com> Cc: Will Deacon <will@kernel.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
157 lines
6.8 KiB
C
157 lines
6.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (C) 2016 ARM Ltd.
|
|
*/
|
|
#ifndef __ASM_PGTABLE_PROT_H
|
|
#define __ASM_PGTABLE_PROT_H
|
|
|
|
#include <asm/memory.h>
|
|
#include <asm/pgtable-hwdef.h>
|
|
|
|
#include <linux/const.h>
|
|
|
|
/*
|
|
* Software defined PTE bits definition.
|
|
*/
|
|
#define PTE_WRITE (PTE_DBM) /* same as DBM (51) */
|
|
#define PTE_SWP_EXCLUSIVE (_AT(pteval_t, 1) << 2) /* only for swp ptes */
|
|
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
|
|
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
|
|
#define PTE_DEVMAP (_AT(pteval_t, 1) << 57)
|
|
#define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
|
|
|
|
/*
|
|
* This bit indicates that the entry is present i.e. pmd_page()
|
|
* still points to a valid huge page in memory even if the pmd
|
|
* has been invalidated.
|
|
*/
|
|
#define PMD_PRESENT_INVALID (_AT(pteval_t, 1) << 59) /* only when !PMD_SECT_VALID */
|
|
|
|
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
|
|
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
|
|
|
|
#define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG)
|
|
#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
|
|
|
|
#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
|
|
#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
|
|
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
|
|
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
|
|
#define PROT_NORMAL_TAGGED (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_TAGGED))
|
|
|
|
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
|
|
#define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PTE_WRITE | PMD_ATTRINDX(MT_NORMAL))
|
|
#define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
|
|
|
|
#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
|
|
|
|
#define _PAGE_KERNEL (PROT_NORMAL)
|
|
#define _PAGE_KERNEL_RO ((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
|
|
#define _PAGE_KERNEL_ROX ((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
|
|
#define _PAGE_KERNEL_EXEC (PROT_NORMAL & ~PTE_PXN)
|
|
#define _PAGE_KERNEL_EXEC_CONT ((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
|
|
|
|
#define _PAGE_SHARED (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
|
|
#define _PAGE_SHARED_EXEC (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
|
|
#define _PAGE_READONLY (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
|
|
#define _PAGE_READONLY_EXEC (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN)
|
|
#define _PAGE_EXECONLY (_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN)
|
|
|
|
#ifdef __ASSEMBLY__
|
|
#define PTE_MAYBE_NG 0
|
|
#endif
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <asm/cpufeature.h>
|
|
#include <asm/pgtable-types.h>
|
|
|
|
extern bool arm64_use_ng_mappings;
|
|
|
|
#define PTE_MAYBE_NG (arm64_use_ng_mappings ? PTE_NG : 0)
|
|
#define PMD_MAYBE_NG (arm64_use_ng_mappings ? PMD_SECT_NG : 0)
|
|
|
|
/*
|
|
* If we have userspace only BTI we don't want to mark kernel pages
|
|
* guarded even if the system does support BTI.
|
|
*/
|
|
#define PTE_MAYBE_GP (system_supports_bti_kernel() ? PTE_GP : 0)
|
|
|
|
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
|
|
#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
|
|
#define PAGE_KERNEL_ROX __pgprot(_PAGE_KERNEL_ROX)
|
|
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)
|
|
#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_KERNEL_EXEC_CONT)
|
|
|
|
#define PAGE_S2_MEMATTR(attr, has_fwb) \
|
|
({ \
|
|
u64 __val; \
|
|
if (has_fwb) \
|
|
__val = PTE_S2_MEMATTR(MT_S2_FWB_ ## attr); \
|
|
else \
|
|
__val = PTE_S2_MEMATTR(MT_S2_ ## attr); \
|
|
__val; \
|
|
})
|
|
|
|
#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
|
|
/* shared+writable pages are clean by default, hence PTE_RDONLY|PTE_WRITE */
|
|
#define PAGE_SHARED __pgprot(_PAGE_SHARED)
|
|
#define PAGE_SHARED_EXEC __pgprot(_PAGE_SHARED_EXEC)
|
|
#define PAGE_READONLY __pgprot(_PAGE_READONLY)
|
|
#define PAGE_READONLY_EXEC __pgprot(_PAGE_READONLY_EXEC)
|
|
#define PAGE_EXECONLY __pgprot(_PAGE_EXECONLY)
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#define pte_pi_index(pte) ( \
|
|
((pte & BIT(PTE_PI_IDX_3)) >> (PTE_PI_IDX_3 - 3)) | \
|
|
((pte & BIT(PTE_PI_IDX_2)) >> (PTE_PI_IDX_2 - 2)) | \
|
|
((pte & BIT(PTE_PI_IDX_1)) >> (PTE_PI_IDX_1 - 1)) | \
|
|
((pte & BIT(PTE_PI_IDX_0)) >> (PTE_PI_IDX_0 - 0)))
|
|
|
|
/*
|
|
* Page types used via Permission Indirection Extension (PIE). PIE uses
|
|
* the USER, DBM, PXN and UXN bits to to generate an index which is used
|
|
* to look up the actual permission in PIR_ELx and PIRE0_EL1. We define
|
|
* combinations we use on non-PIE systems with the same encoding, for
|
|
* convenience these are listed here as comments as are the unallocated
|
|
* encodings.
|
|
*/
|
|
|
|
/* 0: PAGE_DEFAULT */
|
|
/* 1: PTE_USER */
|
|
/* 2: PTE_WRITE */
|
|
/* 3: PTE_WRITE | PTE_USER */
|
|
/* 4: PAGE_EXECONLY PTE_PXN */
|
|
/* 5: PAGE_READONLY_EXEC PTE_PXN | PTE_USER */
|
|
/* 6: PTE_PXN | PTE_WRITE */
|
|
/* 7: PAGE_SHARED_EXEC PTE_PXN | PTE_WRITE | PTE_USER */
|
|
/* 8: PAGE_KERNEL_ROX PTE_UXN */
|
|
/* 9: PTE_UXN | PTE_USER */
|
|
/* a: PAGE_KERNEL_EXEC PTE_UXN | PTE_WRITE */
|
|
/* b: PTE_UXN | PTE_WRITE | PTE_USER */
|
|
/* c: PAGE_KERNEL_RO PTE_UXN | PTE_PXN */
|
|
/* d: PAGE_READONLY PTE_UXN | PTE_PXN | PTE_USER */
|
|
/* e: PAGE_KERNEL PTE_UXN | PTE_PXN | PTE_WRITE */
|
|
/* f: PAGE_SHARED PTE_UXN | PTE_PXN | PTE_WRITE | PTE_USER */
|
|
|
|
#define PIE_E0 ( \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_X_O) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RWX) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY), PIE_R) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED), PIE_RW))
|
|
|
|
#define PIE_E1 ( \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_NONE_O) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RW) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY), PIE_R) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED), PIE_RW) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_ROX), PIE_RX) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_EXEC), PIE_RWX) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL_RO), PIE_R) | \
|
|
PIRx_ELx_PERM(pte_pi_index(_PAGE_KERNEL), PIE_RW))
|
|
|
|
#endif /* __ASM_PGTABLE_PROT_H */
|