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