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