mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Pull arm64 updates from Catalin Marinas:
"The biggest changes are MPAM enablement in drivers/resctrl and new PMU
support under drivers/perf.
On the core side, FEAT_LSUI lets futex atomic operations with EL0
permissions, avoiding PAN toggling.
The rest is mostly TLB invalidation refactoring, further generic entry
work, sysreg updates and a few fixes.
Core features:
- Add support for FEAT_LSUI, allowing futex atomic operations without
toggling Privileged Access Never (PAN)
- Further refactor the arm64 exception handling code towards the
generic entry infrastructure
- Optimise __READ_ONCE() with CONFIG_LTO=y and allow alias analysis
through it
Memory management:
- Refactor the arm64 TLB invalidation API and implementation for
better control over barrier placement and level-hinted invalidation
- Enable batched TLB flushes during memory hot-unplug
- Fix rodata=full block mapping support for realm guests (when
BBML2_NOABORT is available)
Perf and PMU:
- Add support for a whole bunch of system PMUs featured in NVIDIA's
Tegra410 SoC (cspmu extensions for the fabric and PCIe, new drivers
for CPU/C2C memory latency PMUs)
- Clean up iomem resource handling in the Arm CMN driver
- Fix signedness handling of AA64DFR0.{PMUVer,PerfMon}
MPAM (Memory Partitioning And Monitoring):
- Add architecture context-switch and hiding of the feature from KVM
- Add interface to allow MPAM to be exposed to user-space using
resctrl
- Add errata workaround for some existing platforms
- Add documentation for using MPAM and what shape of platforms can
use resctrl
Miscellaneous:
- Check DAIF (and PMR, where relevant) at task-switch time
- Skip TFSR_EL1 checks and barriers in synchronous MTE tag check mode
(only relevant to asynchronous or asymmetric tag check modes)
- Remove a duplicate allocation in the kexec code
- Remove redundant save/restore of SCS SP on entry to/from EL0
- Generate the KERNEL_HWCAP_ definitions from the arm64 hwcap
descriptions
- Add kselftest coverage for cmpbr_sigill()
- Update sysreg definitions"
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (109 commits)
arm64: rsi: use linear-map alias for realm config buffer
arm64: Kconfig: fix duplicate word in CMDLINE help text
arm64: mte: Skip TFSR_EL1 checks and barriers in synchronous tag check mode
arm64/sysreg: Update ID_AA64SMFR0_EL1 description to DDI0601 2025-12
arm64/sysreg: Update ID_AA64ZFR0_EL1 description to DDI0601 2025-12
arm64/sysreg: Update ID_AA64FPFR0_EL1 description to DDI0601 2025-12
arm64/sysreg: Update ID_AA64ISAR2_EL1 description to DDI0601 2025-12
arm64/sysreg: Update ID_AA64ISAR0_EL1 description to DDI0601 2025-12
arm64/hwcap: Generate the KERNEL_HWCAP_ definitions for the hwcaps
arm64: kexec: Remove duplicate allocation for trans_pgd
ACPI: AGDI: fix missing newline in error message
arm64: Check DAIF (and PMR) at task-switch time
arm64: entry: Use split preemption logic
arm64: entry: Use irqentry_{enter_from,exit_to}_kernel_mode()
arm64: entry: Consistently prefix arm64-specific wrappers
arm64: entry: Don't preempt with SError or Debug masked
entry: Split preemption from irqentry_exit_to_kernel_mode()
entry: Split kernel mode logic from irqentry_{enter,exit}()
entry: Move irqentry_enter() prototype later
entry: Remove local_irq_{enable,disable}_exit_to_user()
...
177 lines
4.4 KiB
C
177 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2023 ARM Ltd.
|
|
*/
|
|
|
|
#include <linux/jump_label.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/psci.h>
|
|
#include <linux/swiotlb.h>
|
|
#include <linux/cc_platform.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/mem_encrypt.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/rsi.h>
|
|
|
|
static struct realm_config config;
|
|
|
|
unsigned long prot_ns_shared;
|
|
EXPORT_SYMBOL(prot_ns_shared);
|
|
|
|
DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
|
|
EXPORT_SYMBOL(rsi_present);
|
|
|
|
bool cc_platform_has(enum cc_attr attr)
|
|
{
|
|
switch (attr) {
|
|
case CC_ATTR_MEM_ENCRYPT:
|
|
return is_realm_world();
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(cc_platform_has);
|
|
|
|
static bool rsi_version_matches(void)
|
|
{
|
|
unsigned long ver_lower, ver_higher;
|
|
unsigned long ret = rsi_request_version(RSI_ABI_VERSION,
|
|
&ver_lower,
|
|
&ver_higher);
|
|
|
|
if (ret == SMCCC_RET_NOT_SUPPORTED)
|
|
return false;
|
|
|
|
if (ret != RSI_SUCCESS) {
|
|
pr_err("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
|
|
RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
|
|
RSI_ABI_VERSION_GET_MAJOR(ver_lower),
|
|
RSI_ABI_VERSION_GET_MINOR(ver_lower),
|
|
RSI_ABI_VERSION_GET_MAJOR(ver_higher),
|
|
RSI_ABI_VERSION_GET_MINOR(ver_higher));
|
|
return false;
|
|
}
|
|
|
|
pr_info("RME: Using RSI version %lu.%lu\n",
|
|
RSI_ABI_VERSION_GET_MAJOR(ver_lower),
|
|
RSI_ABI_VERSION_GET_MINOR(ver_lower));
|
|
|
|
return true;
|
|
}
|
|
|
|
static void __init arm64_rsi_setup_memory(void)
|
|
{
|
|
u64 i;
|
|
phys_addr_t start, end;
|
|
|
|
/*
|
|
* Iterate over the available memory ranges and convert the state to
|
|
* protected memory. We should take extra care to ensure that we DO NOT
|
|
* permit any "DESTROYED" pages to be converted to "RAM".
|
|
*
|
|
* panic() is used because if the attempt to switch the memory to
|
|
* protected has failed here, then future accesses to the memory are
|
|
* simply going to be reflected as a SEA (Synchronous External Abort)
|
|
* which we can't handle. Bailing out early prevents the guest limping
|
|
* on and dying later.
|
|
*/
|
|
for_each_mem_range(i, &start, &end) {
|
|
if (rsi_set_memory_range_protected_safe(start, end)) {
|
|
panic("Failed to set memory range to protected: %pa-%pa",
|
|
&start, &end);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if a given PA range is Trusted (e.g., Protected memory, a Trusted Device
|
|
* mapping, or an MMIO emulated in the Realm world).
|
|
*
|
|
* We can rely on the RIPAS value of the region to detect if a given region is
|
|
* protected.
|
|
*
|
|
* RIPAS_DEV - A trusted device memory or a trusted emulated MMIO (in the Realm
|
|
* world
|
|
* RIPAS_RAM - Memory (RAM), protected by the RMM guarantees. (e.g., Firmware
|
|
* reserved regions for data sharing).
|
|
*
|
|
* RIPAS_DESTROYED is a special case of one of the above, where the host did
|
|
* something without our permission and as such we can't do anything about it.
|
|
*
|
|
* The only case where something is emulated by the untrusted hypervisor or is
|
|
* backed by shared memory is indicated by RSI_RIPAS_EMPTY.
|
|
*/
|
|
bool arm64_rsi_is_protected(phys_addr_t base, size_t size)
|
|
{
|
|
enum ripas ripas;
|
|
phys_addr_t end, top;
|
|
|
|
/* Overflow ? */
|
|
if (WARN_ON(base + size <= base))
|
|
return false;
|
|
|
|
end = ALIGN(base + size, RSI_GRANULE_SIZE);
|
|
base = ALIGN_DOWN(base, RSI_GRANULE_SIZE);
|
|
|
|
while (base < end) {
|
|
if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top)))
|
|
break;
|
|
if (WARN_ON(top <= base))
|
|
break;
|
|
if (ripas == RSI_RIPAS_EMPTY)
|
|
break;
|
|
base = top;
|
|
}
|
|
|
|
return base >= end;
|
|
}
|
|
EXPORT_SYMBOL(arm64_rsi_is_protected);
|
|
|
|
static int realm_ioremap_hook(phys_addr_t phys, size_t size, pgprot_t *prot)
|
|
{
|
|
if (arm64_rsi_is_protected(phys, size))
|
|
*prot = pgprot_encrypted(*prot);
|
|
else
|
|
*prot = pgprot_decrypted(*prot);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init arm64_rsi_init(void)
|
|
{
|
|
if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
|
|
return;
|
|
if (!rsi_version_matches())
|
|
return;
|
|
if (WARN_ON(rsi_get_realm_config(lm_alias(&config))))
|
|
return;
|
|
prot_ns_shared = __phys_to_pte_val(BIT(config.ipa_bits - 1));
|
|
|
|
if (arm64_ioremap_prot_hook_register(realm_ioremap_hook))
|
|
return;
|
|
|
|
if (realm_register_memory_enc_ops())
|
|
return;
|
|
|
|
arm64_rsi_setup_memory();
|
|
|
|
static_branch_enable(&rsi_present);
|
|
}
|
|
|
|
static struct platform_device rsi_dev = {
|
|
.name = RSI_PDEV_NAME,
|
|
.id = PLATFORM_DEVID_NONE
|
|
};
|
|
|
|
static int __init arm64_create_dummy_rsi_dev(void)
|
|
{
|
|
if (is_realm_world() &&
|
|
platform_device_register(&rsi_dev))
|
|
pr_err("failed to register rsi platform device\n");
|
|
return 0;
|
|
}
|
|
|
|
arch_initcall(arm64_create_dummy_rsi_dev)
|