mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-17 11:21:05 -05:00
For ioremap(), so far we only checked if it was a device (RIPAS_DEV) to choose an encrypted vs decrypted mapping. However, we may have firmware reserved memory regions exposed to the OS (e.g., EFI Coco Secret Securityfs, ACPI CCEL). We need to make sure that anything that is RIPAS_RAM (i.e., Guest protected memory with RMM guarantees) are also mapped as encrypted. Rephrasing the above, anything that is not RIPAS_EMPTY is guaranteed to be protected by the RMM. Thus we choose encrypted mapping for anything that is not RIPAS_EMPTY. While at it, rename the helper function __arm64_is_protected_mmio => arm64_rsi_is_protected to clearly indicate that this not an arm64 generic helper, but something to do with Realms. Cc: Sami Mujawar <sami.mujawar@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org> Cc: Steven Price <steven.price@arm.com> Reviewed-by: Gavin Shan <gshan@redhat.com> Reviewed-by: Steven Price <steven.price@arm.com> Tested-by: Sami Mujawar <sami.mujawar@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will@kernel.org>
176 lines
4.4 KiB
C
176 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/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(&config)))
|
|
return;
|
|
prot_ns_shared = 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)
|