xref: /linux/drivers/firmware/arm_rmm/rsi.c (revision 303bff3637d13f0ecbb280c7cb403470c440a2a6)
14cd84902SAneesh Kumar K.V (Arm) // SPDX-License-Identifier: GPL-2.0-only
24cd84902SAneesh Kumar K.V (Arm) /*
34cd84902SAneesh Kumar K.V (Arm)  * Copyright (C) 2023 ARM Ltd.
44cd84902SAneesh Kumar K.V (Arm)  */
54cd84902SAneesh Kumar K.V (Arm) 
64cd84902SAneesh Kumar K.V (Arm) #include <linux/jump_label.h>
74cd84902SAneesh Kumar K.V (Arm) #include <linux/memblock.h>
84cd84902SAneesh Kumar K.V (Arm) #include <linux/psci.h>
94cd84902SAneesh Kumar K.V (Arm) #include <linux/swiotlb.h>
104cd84902SAneesh Kumar K.V (Arm) #include <linux/arm-rsi-cmds.h>
11*d541df16SAneesh Kumar K.V (Arm) #include <linux/kobject.h>
12*d541df16SAneesh Kumar K.V (Arm) #include <linux/sysfs.h>
134cd84902SAneesh Kumar K.V (Arm) 
144cd84902SAneesh Kumar K.V (Arm) #include <asm/io.h>
154cd84902SAneesh Kumar K.V (Arm) #include <asm/mem_encrypt.h>
164cd84902SAneesh Kumar K.V (Arm) #include <asm/pgtable.h>
174cd84902SAneesh Kumar K.V (Arm) 
184cd84902SAneesh Kumar K.V (Arm) static struct realm_config config;
194cd84902SAneesh Kumar K.V (Arm) 
204cd84902SAneesh Kumar K.V (Arm) unsigned long prot_ns_shared;
214cd84902SAneesh Kumar K.V (Arm) EXPORT_SYMBOL(prot_ns_shared);
224cd84902SAneesh Kumar K.V (Arm) 
234cd84902SAneesh Kumar K.V (Arm) DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
244cd84902SAneesh Kumar K.V (Arm) EXPORT_SYMBOL(rsi_present);
254cd84902SAneesh Kumar K.V (Arm) 
rsi_version_matches(void)264cd84902SAneesh Kumar K.V (Arm) static bool rsi_version_matches(void)
274cd84902SAneesh Kumar K.V (Arm) {
284cd84902SAneesh Kumar K.V (Arm) 	unsigned long ver_lower, ver_higher;
294cd84902SAneesh Kumar K.V (Arm) 	unsigned long ret = rsi_request_version(RSI_ABI_VERSION,
304cd84902SAneesh Kumar K.V (Arm) 						&ver_lower,
314cd84902SAneesh Kumar K.V (Arm) 						&ver_higher);
324cd84902SAneesh Kumar K.V (Arm) 
334cd84902SAneesh Kumar K.V (Arm) 	if (ret == SMCCC_RET_NOT_SUPPORTED)
344cd84902SAneesh Kumar K.V (Arm) 		return false;
354cd84902SAneesh Kumar K.V (Arm) 
364cd84902SAneesh Kumar K.V (Arm) 	if (ret != RSI_SUCCESS) {
374cd84902SAneesh Kumar K.V (Arm) 		pr_err("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
384cd84902SAneesh Kumar K.V (Arm) 		       RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
394cd84902SAneesh Kumar K.V (Arm) 		       RSI_ABI_VERSION_GET_MAJOR(ver_lower),
404cd84902SAneesh Kumar K.V (Arm) 		       RSI_ABI_VERSION_GET_MINOR(ver_lower),
414cd84902SAneesh Kumar K.V (Arm) 		       RSI_ABI_VERSION_GET_MAJOR(ver_higher),
424cd84902SAneesh Kumar K.V (Arm) 		       RSI_ABI_VERSION_GET_MINOR(ver_higher));
434cd84902SAneesh Kumar K.V (Arm) 		return false;
444cd84902SAneesh Kumar K.V (Arm) 	}
454cd84902SAneesh Kumar K.V (Arm) 
464cd84902SAneesh Kumar K.V (Arm) 	pr_info("RME: Using RSI version %lu.%lu\n",
474cd84902SAneesh Kumar K.V (Arm) 		RSI_ABI_VERSION_GET_MAJOR(ver_lower),
484cd84902SAneesh Kumar K.V (Arm) 		RSI_ABI_VERSION_GET_MINOR(ver_lower));
494cd84902SAneesh Kumar K.V (Arm) 
504cd84902SAneesh Kumar K.V (Arm) 	return true;
514cd84902SAneesh Kumar K.V (Arm) }
524cd84902SAneesh Kumar K.V (Arm) 
arm64_rsi_setup_memory(void)534cd84902SAneesh Kumar K.V (Arm) static void __init arm64_rsi_setup_memory(void)
544cd84902SAneesh Kumar K.V (Arm) {
554cd84902SAneesh Kumar K.V (Arm) 	u64 i;
564cd84902SAneesh Kumar K.V (Arm) 	phys_addr_t start, end;
574cd84902SAneesh Kumar K.V (Arm) 
584cd84902SAneesh Kumar K.V (Arm) 	/*
594cd84902SAneesh Kumar K.V (Arm) 	 * Iterate over the available memory ranges and convert the state to
604cd84902SAneesh Kumar K.V (Arm) 	 * protected memory. We should take extra care to ensure that we DO NOT
614cd84902SAneesh Kumar K.V (Arm) 	 * permit any "DESTROYED" pages to be converted to "RAM".
624cd84902SAneesh Kumar K.V (Arm) 	 *
634cd84902SAneesh Kumar K.V (Arm) 	 * panic() is used because if the attempt to switch the memory to
644cd84902SAneesh Kumar K.V (Arm) 	 * protected has failed here, then future accesses to the memory are
654cd84902SAneesh Kumar K.V (Arm) 	 * simply going to be reflected as a SEA (Synchronous External Abort)
664cd84902SAneesh Kumar K.V (Arm) 	 * which we can't handle.  Bailing out early prevents the guest limping
674cd84902SAneesh Kumar K.V (Arm) 	 * on and dying later.
684cd84902SAneesh Kumar K.V (Arm) 	 */
694cd84902SAneesh Kumar K.V (Arm) 	for_each_mem_range(i, &start, &end) {
704cd84902SAneesh Kumar K.V (Arm) 		if (rsi_set_memory_range_protected_safe(start, end)) {
714cd84902SAneesh Kumar K.V (Arm) 			panic("Failed to set memory range to protected: %pa-%pa",
724cd84902SAneesh Kumar K.V (Arm) 			      &start, &end);
734cd84902SAneesh Kumar K.V (Arm) 		}
744cd84902SAneesh Kumar K.V (Arm) 	}
754cd84902SAneesh Kumar K.V (Arm) }
764cd84902SAneesh Kumar K.V (Arm) 
774cd84902SAneesh Kumar K.V (Arm) /*
784cd84902SAneesh Kumar K.V (Arm)  * Check if a given PA range is Trusted (e.g., Protected memory, a Trusted Device
794cd84902SAneesh Kumar K.V (Arm)  * mapping, or an MMIO emulated in the Realm world).
804cd84902SAneesh Kumar K.V (Arm)  *
814cd84902SAneesh Kumar K.V (Arm)  * We can rely on the RIPAS value of the region to detect if a given region is
824cd84902SAneesh Kumar K.V (Arm)  * protected.
834cd84902SAneesh Kumar K.V (Arm)  *
844cd84902SAneesh Kumar K.V (Arm)  *  RIPAS_DEV - A trusted device memory or a trusted emulated MMIO (in the Realm
854cd84902SAneesh Kumar K.V (Arm)  *		world
864cd84902SAneesh Kumar K.V (Arm)  *  RIPAS_RAM - Memory (RAM), protected by the RMM guarantees. (e.g., Firmware
874cd84902SAneesh Kumar K.V (Arm)  *		reserved regions for data sharing).
884cd84902SAneesh Kumar K.V (Arm)  *
894cd84902SAneesh Kumar K.V (Arm)  *  RIPAS_DESTROYED is a special case of one of the above, where the host did
904cd84902SAneesh Kumar K.V (Arm)  *  something without our permission and as such we can't do anything about it.
914cd84902SAneesh Kumar K.V (Arm)  *
924cd84902SAneesh Kumar K.V (Arm)  * The only case where something is emulated by the untrusted hypervisor or is
934cd84902SAneesh Kumar K.V (Arm)  * backed by shared memory is indicated by RSI_RIPAS_EMPTY.
944cd84902SAneesh Kumar K.V (Arm)  */
arm64_rsi_is_protected(phys_addr_t base,size_t size)954cd84902SAneesh Kumar K.V (Arm) bool arm64_rsi_is_protected(phys_addr_t base, size_t size)
964cd84902SAneesh Kumar K.V (Arm) {
974cd84902SAneesh Kumar K.V (Arm) 	enum ripas ripas;
984cd84902SAneesh Kumar K.V (Arm) 	phys_addr_t end, top;
994cd84902SAneesh Kumar K.V (Arm) 
1004cd84902SAneesh Kumar K.V (Arm) 	/* Overflow ? */
1014cd84902SAneesh Kumar K.V (Arm) 	if (WARN_ON(base + size <= base))
1024cd84902SAneesh Kumar K.V (Arm) 		return false;
1034cd84902SAneesh Kumar K.V (Arm) 
1044cd84902SAneesh Kumar K.V (Arm) 	end = ALIGN(base + size, RSI_GRANULE_SIZE);
1054cd84902SAneesh Kumar K.V (Arm) 	base = ALIGN_DOWN(base, RSI_GRANULE_SIZE);
1064cd84902SAneesh Kumar K.V (Arm) 
1074cd84902SAneesh Kumar K.V (Arm) 	while (base < end) {
1084cd84902SAneesh Kumar K.V (Arm) 		if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top)))
1094cd84902SAneesh Kumar K.V (Arm) 			break;
1104cd84902SAneesh Kumar K.V (Arm) 		if (WARN_ON(top <= base))
1114cd84902SAneesh Kumar K.V (Arm) 			break;
1124cd84902SAneesh Kumar K.V (Arm) 		if (ripas == RSI_RIPAS_EMPTY)
1134cd84902SAneesh Kumar K.V (Arm) 			break;
1144cd84902SAneesh Kumar K.V (Arm) 		base = top;
1154cd84902SAneesh Kumar K.V (Arm) 	}
1164cd84902SAneesh Kumar K.V (Arm) 
1174cd84902SAneesh Kumar K.V (Arm) 	return base >= end;
1184cd84902SAneesh Kumar K.V (Arm) }
1194cd84902SAneesh Kumar K.V (Arm) EXPORT_SYMBOL(arm64_rsi_is_protected);
1204cd84902SAneesh Kumar K.V (Arm) 
realm_ioremap_hook(phys_addr_t phys,size_t size,pgprot_t * prot)1214cd84902SAneesh Kumar K.V (Arm) static int realm_ioremap_hook(phys_addr_t phys, size_t size, pgprot_t *prot)
1224cd84902SAneesh Kumar K.V (Arm) {
1234cd84902SAneesh Kumar K.V (Arm) 	if (arm64_rsi_is_protected(phys, size))
1244cd84902SAneesh Kumar K.V (Arm) 		*prot = pgprot_encrypted(*prot);
1254cd84902SAneesh Kumar K.V (Arm) 	else
1264cd84902SAneesh Kumar K.V (Arm) 		*prot = pgprot_decrypted(*prot);
1274cd84902SAneesh Kumar K.V (Arm) 
1284cd84902SAneesh Kumar K.V (Arm) 	return 0;
1294cd84902SAneesh Kumar K.V (Arm) }
1304cd84902SAneesh Kumar K.V (Arm) 
realm_set_memory_encrypted(unsigned long addr,int numpages)131714153dcSAneesh Kumar K.V (Arm) static int realm_set_memory_encrypted(unsigned long addr, int numpages)
132714153dcSAneesh Kumar K.V (Arm) {
133714153dcSAneesh Kumar K.V (Arm) 	int ret = __set_memory_enc_dec(addr, numpages, true);
134714153dcSAneesh Kumar K.V (Arm) 
135714153dcSAneesh Kumar K.V (Arm) 	/*
136714153dcSAneesh Kumar K.V (Arm) 	 * If the request to change state fails, then the only sensible cause
137714153dcSAneesh Kumar K.V (Arm) 	 * of action for the caller is to leak the memory
138714153dcSAneesh Kumar K.V (Arm) 	 */
139714153dcSAneesh Kumar K.V (Arm) 	WARN(ret, "Failed to encrypt memory, %d pages will be leaked",
140714153dcSAneesh Kumar K.V (Arm) 	     numpages);
141714153dcSAneesh Kumar K.V (Arm) 
142714153dcSAneesh Kumar K.V (Arm) 	return ret;
143714153dcSAneesh Kumar K.V (Arm) }
144714153dcSAneesh Kumar K.V (Arm) 
realm_set_memory_decrypted(unsigned long addr,int numpages)145714153dcSAneesh Kumar K.V (Arm) static int realm_set_memory_decrypted(unsigned long addr, int numpages)
146714153dcSAneesh Kumar K.V (Arm) {
147714153dcSAneesh Kumar K.V (Arm) 	int ret = __set_memory_enc_dec(addr, numpages, false);
148714153dcSAneesh Kumar K.V (Arm) 
149714153dcSAneesh Kumar K.V (Arm) 	WARN(ret, "Failed to decrypt memory, %d pages will be leaked",
150714153dcSAneesh Kumar K.V (Arm) 	     numpages);
151714153dcSAneesh Kumar K.V (Arm) 
152714153dcSAneesh Kumar K.V (Arm) 	return ret;
153714153dcSAneesh Kumar K.V (Arm) }
154714153dcSAneesh Kumar K.V (Arm) 
155714153dcSAneesh Kumar K.V (Arm) static const struct arm64_mem_crypt_ops realm_crypt_ops = {
156714153dcSAneesh Kumar K.V (Arm) 	.encrypt = realm_set_memory_encrypted,
157714153dcSAneesh Kumar K.V (Arm) 	.decrypt = realm_set_memory_decrypted,
158714153dcSAneesh Kumar K.V (Arm) };
159714153dcSAneesh Kumar K.V (Arm) 
realm_register_memory_enc_ops(void)160714153dcSAneesh Kumar K.V (Arm) static int realm_register_memory_enc_ops(void)
161714153dcSAneesh Kumar K.V (Arm) {
162714153dcSAneesh Kumar K.V (Arm) 	return arm64_mem_crypt_ops_register(&realm_crypt_ops);
163714153dcSAneesh Kumar K.V (Arm) }
164714153dcSAneesh Kumar K.V (Arm) 
arm64_rsi_init(void)1654cd84902SAneesh Kumar K.V (Arm) void __init arm64_rsi_init(void)
1664cd84902SAneesh Kumar K.V (Arm) {
1674cd84902SAneesh Kumar K.V (Arm) 	if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
1684cd84902SAneesh Kumar K.V (Arm) 		return;
1694cd84902SAneesh Kumar K.V (Arm) 	if (!rsi_version_matches())
1704cd84902SAneesh Kumar K.V (Arm) 		return;
1714cd84902SAneesh Kumar K.V (Arm) 	if (WARN_ON(rsi_get_realm_config(lm_alias(&config))))
1724cd84902SAneesh Kumar K.V (Arm) 		return;
1734cd84902SAneesh Kumar K.V (Arm) 	prot_ns_shared = __phys_to_pte_val(BIT(config.ipa_bits - 1));
1744cd84902SAneesh Kumar K.V (Arm) 
1754cd84902SAneesh Kumar K.V (Arm) 	if (arm64_ioremap_prot_hook_register(realm_ioremap_hook))
1764cd84902SAneesh Kumar K.V (Arm) 		return;
1774cd84902SAneesh Kumar K.V (Arm) 
1784cd84902SAneesh Kumar K.V (Arm) 	if (realm_register_memory_enc_ops())
1794cd84902SAneesh Kumar K.V (Arm) 		return;
1804cd84902SAneesh Kumar K.V (Arm) 
1814cd84902SAneesh Kumar K.V (Arm) 	arm64_rsi_setup_memory();
1824cd84902SAneesh Kumar K.V (Arm) 
1834cd84902SAneesh Kumar K.V (Arm) 	static_branch_enable(&rsi_present);
1844cd84902SAneesh Kumar K.V (Arm) }
1854cd84902SAneesh Kumar K.V (Arm) 
realm_guest_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)186*d541df16SAneesh Kumar K.V (Arm) static ssize_t realm_guest_show(struct kobject *kobj,
187*d541df16SAneesh Kumar K.V (Arm) 		struct kobj_attribute *attr, char *buf)
188*d541df16SAneesh Kumar K.V (Arm) {
189*d541df16SAneesh Kumar K.V (Arm) 	return sysfs_emit(buf, "1\n");
190*d541df16SAneesh Kumar K.V (Arm) }
191*d541df16SAneesh Kumar K.V (Arm) 
192*d541df16SAneesh Kumar K.V (Arm) static struct kobj_attribute cca_realm_guest = __ATTR_RO(realm_guest);
193*d541df16SAneesh Kumar K.V (Arm) static const struct attribute *cca_realm_attrs[] = {
194*d541df16SAneesh Kumar K.V (Arm) 	&cca_realm_guest.attr,
195*d541df16SAneesh Kumar K.V (Arm) 	NULL
196*d541df16SAneesh Kumar K.V (Arm) };
197*d541df16SAneesh Kumar K.V (Arm) 
realm_sysfs_init(void)198*d541df16SAneesh Kumar K.V (Arm) static int __init realm_sysfs_init(void)
199*d541df16SAneesh Kumar K.V (Arm) {
200*d541df16SAneesh Kumar K.V (Arm) 	int ret;
201*d541df16SAneesh Kumar K.V (Arm) 	struct kobject *cca_kobj;
202*d541df16SAneesh Kumar K.V (Arm) 
203*d541df16SAneesh Kumar K.V (Arm) 	if (!is_realm_world())
204*d541df16SAneesh Kumar K.V (Arm) 		return 0;
205*d541df16SAneesh Kumar K.V (Arm) 
206*d541df16SAneesh Kumar K.V (Arm) 	cca_kobj = kobject_create_and_add("cca", firmware_kobj);
207*d541df16SAneesh Kumar K.V (Arm) 	if (!cca_kobj)
208*d541df16SAneesh Kumar K.V (Arm) 		return -ENOMEM;
209*d541df16SAneesh Kumar K.V (Arm) 
210*d541df16SAneesh Kumar K.V (Arm) 	ret = sysfs_create_files(cca_kobj, cca_realm_attrs);
211*d541df16SAneesh Kumar K.V (Arm) 	if (!ret)
212*d541df16SAneesh Kumar K.V (Arm) 		return 0;
213*d541df16SAneesh Kumar K.V (Arm) 
214*d541df16SAneesh Kumar K.V (Arm) 	kobject_put(cca_kobj);
215*d541df16SAneesh Kumar K.V (Arm) 	return ret;
216*d541df16SAneesh Kumar K.V (Arm) }
217*d541df16SAneesh Kumar K.V (Arm) device_initcall(realm_sysfs_init);
218