xref: /freebsd/sys/arm64/arm64/rsi.c (revision 76a2904c352b497b32fc902523e3e485f7b06ffd)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2026 Arm Ltd
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "opt_platform.h"
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/physmem.h>
33 #include <sys/rwlock.h>
34 
35 #include <vm/vm_page.h>
36 
37 #include <machine/rsi.h>
38 #include <machine/vmparam.h>
39 
40 #include <dev/psci/psci.h>
41 #include <dev/psci/smccc.h>
42 
43 static struct realm_config config;
44 static bool rsi_present = false;
45 
46 #define	PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1))
47 
48 static vm_paddr_t physmap[PHYSMAP_SIZE];
49 
50 static unsigned long
rsi_request_version(unsigned long req,unsigned long * out_lower,unsigned long * out_higher)51 rsi_request_version(unsigned long req, unsigned long *out_lower,
52     unsigned long *out_higher)
53 {
54 	struct arm_smccc_res res;
55 
56 	arm_smccc_invoke_smc(SMC_RSI_ABI_VERSION, req, &res);
57 
58 	if (out_lower != NULL)
59 		*out_lower = res.a1;
60 	if (out_higher != NULL)
61 		*out_higher = res.a2;
62 
63 	return (res.a0);
64 }
65 
66 static inline unsigned long
rsi_get_realm_config(struct realm_config * cfg)67 rsi_get_realm_config(struct realm_config *cfg)
68 {
69 	struct arm_smccc_res res;
70 
71 	arm_smccc_invoke_smc(SMC_RSI_REALM_CONFIG, vtophys(cfg), &res);
72 	return (res.a0);
73 }
74 
75 static bool
rsi_version_matches(void)76 rsi_version_matches(void)
77 {
78 	unsigned long ver_lower, ver_higher;
79 	unsigned long ret;
80 
81 	ret = rsi_request_version(RSI_ABI_VERSION, &ver_lower, &ver_higher);
82 
83 	if (ret == SMCCC_RET_NOT_SUPPORTED)
84 		return (false);
85 
86 	if (ret != RSI_SUCCESS) {
87 		printf("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
88 		    RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
89 		    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
90 		    RSI_ABI_VERSION_GET_MINOR(ver_lower),
91 		    RSI_ABI_VERSION_GET_MAJOR(ver_higher),
92 		    RSI_ABI_VERSION_GET_MINOR(ver_higher));
93 		return (false);
94 	}
95 
96 	printf("RME: Using RSI version %lu.%lu\n",
97 	    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
98 	    RSI_ABI_VERSION_GET_MINOR(ver_lower));
99 
100 	return (true);
101 }
102 
103 
104 unsigned long
rsi_set_addr_range_state(vm_paddr_t start,vm_paddr_t end,enum ripas state,unsigned long flags,vm_paddr_t * top)105 rsi_set_addr_range_state(vm_paddr_t start, vm_paddr_t end, enum ripas state,
106     unsigned long flags, vm_paddr_t *top)
107 {
108 	struct arm_smccc_res res;
109 
110 	arm_smccc_smc(SMC_RSI_IPA_STATE_SET, start, end, state, flags, 0, 0, 0,
111 	    &res);
112 
113 	if (top)
114 		*top = res.a1;
115 
116 	return (res.a0);
117 }
118 
119 static int
rsi_set_memory_range(vm_paddr_t start,vm_paddr_t end,enum ripas state,unsigned long flags)120 rsi_set_memory_range(vm_paddr_t start, vm_paddr_t end, enum ripas state,
121     unsigned long flags)
122 {
123 	unsigned long ret;
124 	vm_paddr_t top;
125 
126 	while (start != end) {
127 		ret = rsi_set_addr_range_state(start, end, state, flags, &top);
128 		if (ret || top < start || top > end)
129 			return (-EINVAL);
130 		start = top;
131 	}
132 
133 	return (0);
134 }
135 
136 /*
137  * Convert the specified range to RAM. Do not convert any pages that may have
138  * been DESTROYED, without our permission.
139  */
140 static int
rsi_set_memory_range_protected_safe(vm_paddr_t start,vm_paddr_t end)141 rsi_set_memory_range_protected_safe(vm_paddr_t start, vm_paddr_t end)
142 {
143 	return (rsi_set_memory_range(start, end, RSI_RIPAS_RAM,
144 	    RSI_NO_CHANGE_DESTROYED));
145 }
146 
147 void
arm64_rsi_setup_memory(void)148 arm64_rsi_setup_memory(void)
149 {
150 	int physmap_idx;
151 	int i;
152 
153 	if (!psci_conduit_is_smc())
154 		return;
155 	if (!rsi_version_matches())
156 		return;
157 	if (rsi_get_realm_config(&config))
158 		return;
159 
160 	prot_ns_shared_pa = 1ul << (config.ipa_bits - 1);
161 	if (bootverbose)
162 		printf("arm64_rsi_setup_memory: rsi_present, ipa_bits=%lu prot_ns_shared_pa=%lx\n",
163 		    config.ipa_bits, prot_ns_shared_pa);
164 	rsi_present = true;
165 
166 	physmap_idx = physmem_all(physmap, nitems(physmap));
167 
168 	if (bootverbose)
169 		printf("physmap:\n");
170 
171 	for (i = 0; i < physmap_idx; i += 2) {
172 		if (bootverbose)
173 			printf("  %lx %lx\n", physmap[i], physmap[i + 1]);
174 
175 		if (rsi_set_memory_range_protected_safe(physmap[i],
176 		    physmap[i + 1]))
177 			panic("rsi_set_memory_range_protected_safe failed");
178 	}
179 }
180 
181 bool
in_realm(void)182 in_realm(void)
183 {
184 	return (rsi_present);
185 }
186