xref: /freebsd/sys/arm64/arm64/rsi.c (revision b8606c3406eab69637be616260c977c9a8f14ff3)
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 <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/physmem.h>
31 #include <sys/rwlock.h>
32 
33 #include <vm/vm.h>
34 #include <vm/pmap.h>
35 
36 #include <machine/rsi.h>
37 #include <machine/vmparam.h>
38 
39 #include <dev/psci/psci.h>
40 #include <dev/psci/smccc.h>
41 
42 static struct realm_config config;
43 static bool rsi_present = false;
44 
45 #define	PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1))
46 
47 static vm_paddr_t physmap[PHYSMAP_SIZE];
48 
49 static unsigned long
rsi_request_version(unsigned long req,unsigned long * out_lower,unsigned long * out_higher)50 rsi_request_version(unsigned long req, unsigned long *out_lower,
51     unsigned long *out_higher)
52 {
53 	struct arm_smccc_res res;
54 
55 	arm_smccc_invoke_smc(SMC_RSI_ABI_VERSION, req, &res);
56 
57 	if (out_lower != NULL)
58 		*out_lower = res.a1;
59 	if (out_higher != NULL)
60 		*out_higher = res.a2;
61 
62 	return (res.a0);
63 }
64 
65 static inline unsigned long
rsi_get_realm_config(struct realm_config * cfg)66 rsi_get_realm_config(struct realm_config *cfg)
67 {
68 	struct arm_smccc_res res;
69 
70 	arm_smccc_invoke_smc(SMC_RSI_REALM_CONFIG, vtophys(cfg), &res);
71 	return (res.a0);
72 }
73 
74 static bool
rsi_version_matches(void)75 rsi_version_matches(void)
76 {
77 	unsigned long ver_lower, ver_higher;
78 	unsigned long ret;
79 
80 	ret = rsi_request_version(RSI_ABI_VERSION, &ver_lower, &ver_higher);
81 
82 	if (ret == SMCCC_RET_NOT_SUPPORTED)
83 		return (false);
84 
85 	if (ret != RSI_SUCCESS) {
86 		printf("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
87 		    RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
88 		    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
89 		    RSI_ABI_VERSION_GET_MINOR(ver_lower),
90 		    RSI_ABI_VERSION_GET_MAJOR(ver_higher),
91 		    RSI_ABI_VERSION_GET_MINOR(ver_higher));
92 		return (false);
93 	}
94 
95 	printf("RME: Using RSI version %lu.%lu\n",
96 	    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
97 	    RSI_ABI_VERSION_GET_MINOR(ver_lower));
98 
99 	return (true);
100 }
101 
102 
103 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)104 rsi_set_addr_range_state(vm_paddr_t start, vm_paddr_t end, enum ripas state,
105     unsigned long flags, vm_paddr_t *top)
106 {
107 	struct arm_smccc_res res;
108 
109 	arm_smccc_smc(SMC_RSI_IPA_STATE_SET, start, end, state, flags, 0, 0, 0,
110 	    &res);
111 
112 	if (top)
113 		*top = res.a1;
114 
115 	return (res.a0);
116 }
117 
118 static int
rsi_set_memory_range(vm_paddr_t start,vm_paddr_t end,enum ripas state,unsigned long flags)119 rsi_set_memory_range(vm_paddr_t start, vm_paddr_t end, enum ripas state,
120     unsigned long flags)
121 {
122 	unsigned long ret;
123 	vm_paddr_t top;
124 
125 	while (start != end) {
126 		ret = rsi_set_addr_range_state(start, end, state, flags, &top);
127 		if (ret || top < start || top > end)
128 			return (-EINVAL);
129 		start = top;
130 	}
131 
132 	return (0);
133 }
134 
135 /*
136  * Convert the specified range to RAM. Do not convert any pages that may have
137  * been DESTROYED, without our permission.
138  */
139 static int
rsi_set_memory_range_protected_safe(vm_paddr_t start,vm_paddr_t end)140 rsi_set_memory_range_protected_safe(vm_paddr_t start, vm_paddr_t end)
141 {
142 	return (rsi_set_memory_range(start, end, RSI_RIPAS_RAM,
143 	    RSI_NO_CHANGE_DESTROYED));
144 }
145 
146 void
arm64_rsi_setup_memory(void)147 arm64_rsi_setup_memory(void)
148 {
149 	int physmap_idx;
150 	int i;
151 
152 	if (!psci_conduit_is_smc())
153 		return;
154 	if (!rsi_version_matches())
155 		return;
156 	if (rsi_get_realm_config(&config))
157 		return;
158 
159 	prot_ns_shared_pa = 1ul << (config.ipa_bits - 1);
160 	if (bootverbose)
161 		printf("arm64_rsi_setup_memory: rsi_present, ipa_bits=%lu prot_ns_shared_pa=%lx\n",
162 		    config.ipa_bits, prot_ns_shared_pa);
163 	rsi_present = true;
164 
165 	physmap_idx = physmem_all(physmap, nitems(physmap));
166 
167 	if (bootverbose)
168 		printf("physmap:\n");
169 
170 	for (i = 0; i < physmap_idx; i += 2) {
171 		if (bootverbose)
172 			printf("  %lx %lx\n", physmap[i], physmap[i + 1]);
173 
174 		if (rsi_set_memory_range_protected_safe(physmap[i],
175 		    physmap[i + 1]))
176 			panic("rsi_set_memory_range_protected_safe failed");
177 	}
178 }
179 
180 bool
in_realm(void)181 in_realm(void)
182 {
183 	return (rsi_present);
184 }
185