File Index
Files and directories
Sign in
FILE

rsi.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm64/kernel/rsi.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2023 ARM Ltd.
  4 */
  5
  6#include <linux/jump_label.h>
  7#include <linux/memblock.h>
  8#include <linux/psci.h>
  9#include <linux/swiotlb.h>
 10#include <linux/cc_platform.h>
 11#include <linux/platform_device.h>
 12
 13#include <asm/io.h>
 14#include <asm/mem_encrypt.h>
 15#include <asm/pgtable.h>
 16#include <asm/rsi.h>
 17
 18static struct realm_config config;
 19
 20unsigned long prot_ns_shared;
 21EXPORT_SYMBOL(prot_ns_shared);
 22
 23DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 24EXPORT_SYMBOL(rsi_present);
 25
 26bool cc_platform_has(enum cc_attr attr)
 27{
 28	switch (attr) {
 29	case CC_ATTR_MEM_ENCRYPT:
 30		return is_realm_world();
 31	default:
 32		return false;
 33	}
 34}
 35EXPORT_SYMBOL_GPL(cc_platform_has);
 36
 37static bool rsi_version_matches(void)
 38{
 39	unsigned long ver_lower, ver_higher;
 40	unsigned long ret = rsi_request_version(RSI_ABI_VERSION,
 41						&ver_lower,
 42						&ver_higher);
 43
 44	if (ret == SMCCC_RET_NOT_SUPPORTED)
 45		return false;
 46
 47	if (ret != RSI_SUCCESS) {
 48		pr_err("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
 49		       RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
 50		       RSI_ABI_VERSION_GET_MAJOR(ver_lower),
 51		       RSI_ABI_VERSION_GET_MINOR(ver_lower),
 52		       RSI_ABI_VERSION_GET_MAJOR(ver_higher),
 53		       RSI_ABI_VERSION_GET_MINOR(ver_higher));
 54		return false;
 55	}
 56
 57	pr_info("RME: Using RSI version %lu.%lu\n",
 58		RSI_ABI_VERSION_GET_MAJOR(ver_lower),
 59		RSI_ABI_VERSION_GET_MINOR(ver_lower));
 60
 61	return true;
 62}
 63
 64static void __init arm64_rsi_setup_memory(void)
 65{
 66	u64 i;
 67	phys_addr_t start, end;
 68
 69	/*
 70	 * Iterate over the available memory ranges and convert the state to
 71	 * protected memory. We should take extra care to ensure that we DO NOT
 72	 * permit any "DESTROYED" pages to be converted to "RAM".
 73	 *
 74	 * panic() is used because if the attempt to switch the memory to
 75	 * protected has failed here, then future accesses to the memory are
 76	 * simply going to be reflected as a SEA (Synchronous External Abort)
 77	 * which we can't handle.  Bailing out early prevents the guest limping
 78	 * on and dying later.
 79	 */
 80	for_each_mem_range(i, &start, &end) {
 81		if (rsi_set_memory_range_protected_safe(start, end)) {
 82			panic("Failed to set memory range to protected: %pa-%pa",
 83			      &start, &end);
 84		}
 85	}
 86}
 87
 88/*
 89 * Check if a given PA range is Trusted (e.g., Protected memory, a Trusted Device
 90 * mapping, or an MMIO emulated in the Realm world).
 91 *
 92 * We can rely on the RIPAS value of the region to detect if a given region is
 93 * protected.
 94 *
 95 *  RIPAS_DEV - A trusted device memory or a trusted emulated MMIO (in the Realm
 96 *		world
 97 *  RIPAS_RAM - Memory (RAM), protected by the RMM guarantees. (e.g., Firmware
 98 *		reserved regions for data sharing).
 99 *
100 *  RIPAS_DESTROYED is a special case of one of the above, where the host did
101 *  something without our permission and as such we can't do anything about it.
102 *
103 * The only case where something is emulated by the untrusted hypervisor or is
104 * backed by shared memory is indicated by RSI_RIPAS_EMPTY.
105 */
106bool arm64_rsi_is_protected(phys_addr_t base, size_t size)
107{
108	enum ripas ripas;
109	phys_addr_t end, top;
110
111	/* Overflow ? */
112	if (WARN_ON(base + size <= base))
113		return false;
114
115	end = ALIGN(base + size, RSI_GRANULE_SIZE);
116	base = ALIGN_DOWN(base, RSI_GRANULE_SIZE);
117
118	while (base < end) {
119		if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top)))
120			break;
121		if (WARN_ON(top <= base))
122			break;
123		if (ripas == RSI_RIPAS_EMPTY)
124			break;
125		base = top;
126	}
127
128	return base >= end;
129}
130EXPORT_SYMBOL(arm64_rsi_is_protected);
131
132static int realm_ioremap_hook(phys_addr_t phys, size_t size, pgprot_t *prot)
133{
134	if (arm64_rsi_is_protected(phys, size))
135		*prot = pgprot_encrypted(*prot);
136	else
137		*prot = pgprot_decrypted(*prot);
138
139	return 0;
140}
141
142void __init arm64_rsi_init(void)
143{
144	if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
145		return;
146	if (!rsi_version_matches())
147		return;
148	if (WARN_ON(rsi_get_realm_config(&config)))
149		return;
150	prot_ns_shared = __phys_to_pte_val(BIT(config.ipa_bits - 1));
151
152	if (arm64_ioremap_prot_hook_register(realm_ioremap_hook))
153		return;
154
155	if (realm_register_memory_enc_ops())
156		return;
157
158	arm64_rsi_setup_memory();
159
160	static_branch_enable(&rsi_present);
161}
162
163static struct platform_device rsi_dev = {
164	.name = RSI_PDEV_NAME,
165	.id = PLATFORM_DEVID_NONE
166};
167
168static int __init arm64_create_dummy_rsi_dev(void)
169{
170	if (is_realm_world() &&
171	    platform_device_register(&rsi_dev))
172		pr_err("failed to register rsi platform device\n");
173	return 0;
174}
175
176arch_initcall(arm64_create_dummy_rsi_dev)
~/ Read-only file preview.