1 /* $OpenBSD: mdesc.c,v 1.9 2023/04/10 04:21:20 jsg Exp $ */
2 /*
3 * Copyright (c) 2009 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22
23 #include <uvm/uvm_extern.h>
24
25 #include <machine/autoconf.h>
26 #include <machine/hypervisor.h>
27 #include <machine/mdesc.h>
28 #include <machine/sparc64.h>
29
30 #define HSVC_GROUP_PARALLEL_BOOT 0x105
31
32 caddr_t mdesc;
33 paddr_t mdesc_pa;
34 size_t mdesc_len;
35
36 caddr_t pri;
37 paddr_t pri_pa;
38 size_t pri_len;
39
40 void pri_init(void);
41
42 void
mdesc_init(void)43 mdesc_init(void)
44 {
45 struct pglist mlist;
46 struct vm_page *m;
47 psize_t len = 0, size;
48 paddr_t pa;
49 vaddr_t va;
50 int err;
51
52 err = hv_mach_desc((paddr_t)NULL, &len);
53 KASSERT(err == H_EINVAL);
54 KASSERT(len != 0);
55
56 again:
57 size = round_page(len);
58
59 TAILQ_INIT(&mlist);
60 err = uvm_pglistalloc(len, 0, -1, PAGE_SIZE, 0, &mlist, 1,
61 UVM_PLA_NOWAIT);
62 if (err)
63 panic("%s: out of memory", __func__);
64
65 len = size;
66 pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist));
67 err = hv_mach_desc(pa, &len);
68 if (err != H_EOK)
69 goto fail;
70
71 va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait);
72 if (va == 0)
73 panic("%s: out of memory", __func__);
74
75 mdesc = (caddr_t)va;
76 mdesc_pa = pa;
77 mdesc_len = len;
78
79 m = TAILQ_FIRST(&mlist);
80 for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
81 pa = VM_PAGE_TO_PHYS(m);
82 pmap_enter(pmap_kernel(), va, pa,
83 PROT_READ | PROT_WRITE,
84 PROT_READ | PROT_WRITE | PMAP_WIRED);
85 va += PAGE_SIZE;
86 }
87 pmap_update(pmap_kernel());
88
89 pri_init();
90 return;
91
92 fail:
93 uvm_pglistfree(&mlist);
94
95 /*
96 * If the machine description was updated while we were trying
97 * to fetch it, the allocated buffer may have been too small.
98 * Try again in that case.
99 */
100 if (err == H_EINVAL && len > size)
101 goto again;
102
103 return;
104 }
105
106 void
pri_init(void)107 pri_init(void)
108 {
109 struct pglist mlist;
110 struct vm_page *m;
111 uint64_t minor;
112 psize_t len = 0, size;
113 paddr_t pa;
114 vaddr_t va;
115 int err;
116
117 /*
118 * We can only fetch the physical resource inventory this way
119 * if the firmware supports parallel boot.
120 */
121 if (prom_set_sun4v_api_version(HSVC_GROUP_PARALLEL_BOOT, 1, 0, &minor))
122 return;
123
124 err = hv_mach_pri((paddr_t)NULL, &len);
125 if (err != H_EINVAL)
126 return;
127
128 again:
129 size = round_page(len);
130
131 TAILQ_INIT(&mlist);
132 err = uvm_pglistalloc(len, 0, -1, PAGE_SIZE, 0, &mlist, 1,
133 UVM_PLA_NOWAIT);
134 if (err)
135 panic("%s: out of memory", __func__);
136
137 len = size;
138 pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist));
139 err = hv_mach_pri(pa, &len);
140 if (err != H_EOK)
141 goto fail;
142
143 va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait);
144 if (va == 0)
145 panic("%s: out of memory", __func__);
146
147 pri = (caddr_t)va;
148 pri_pa = pa;
149 pri_len = len;
150
151 m = TAILQ_FIRST(&mlist);
152 for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
153 pa = VM_PAGE_TO_PHYS(m);
154 pmap_enter(pmap_kernel(), va, pa,
155 PROT_READ | PROT_WRITE,
156 PROT_READ | PROT_WRITE | PMAP_WIRED);
157 va += PAGE_SIZE;
158 }
159 pmap_update(pmap_kernel());
160
161 return;
162
163 fail:
164 uvm_pglistfree(&mlist);
165
166 /*
167 * If the physical resource inventory was updated while we
168 * were trying to fetch it, the allocated buffer may have been
169 * too small. Try again in that case.
170 */
171 if (err == H_EINVAL && len > size)
172 goto again;
173
174 return;
175 }
176
177 uint64_t
mdesc_get_prop_val(int idx,const char * name)178 mdesc_get_prop_val(int idx, const char *name)
179 {
180 struct md_header *hdr;
181 struct md_element *elem;
182 const char *name_blk;
183 const char *str;
184
185 hdr = (struct md_header *)mdesc;
186 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
187 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
188
189 while (elem[idx].tag != 'E') {
190 str = name_blk + elem[idx].name_offset;
191 if (elem[idx].tag == 'v' && strcmp(str, name) == 0)
192 return (elem[idx].d.val);
193 idx++;
194 }
195
196 return (-1);
197 }
198
199 const char *
mdesc_get_prop_str(int idx,const char * name)200 mdesc_get_prop_str(int idx, const char *name)
201 {
202 struct md_header *hdr;
203 struct md_element *elem;
204 const char *name_blk;
205 const char *data_blk;
206 const char *str;
207
208 hdr = (struct md_header *)mdesc;
209 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
210 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
211 data_blk = name_blk + hdr->name_blk_sz;
212
213 while (elem[idx].tag != 'E') {
214 str = name_blk + elem[idx].name_offset;
215 if (elem[idx].tag == 's' && strcmp(str, name) == 0)
216 return (data_blk + elem[idx].d.y.data_offset);
217 idx++;
218 }
219
220 return (NULL);
221 }
222
223 const char *
mdesc_get_prop_data(int idx,const char * name,size_t * len)224 mdesc_get_prop_data(int idx, const char *name, size_t *len)
225 {
226 struct md_header *hdr;
227 struct md_element *elem;
228 const char *name_blk;
229 const char *data_blk;
230 const char *str;
231
232 hdr = (struct md_header *)mdesc;
233 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
234 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
235 data_blk = name_blk + hdr->name_blk_sz;
236
237 while (elem[idx].tag != 'E') {
238 str = name_blk + elem[idx].name_offset;
239 if (elem[idx].tag == 'd' && strcmp(str, name) == 0) {
240 *len = elem[idx].d.y.data_len;
241 return (data_blk + elem[idx].d.y.data_offset);
242 }
243 idx++;
244 }
245
246 return (NULL);
247 }
248
249 int
mdesc_find(const char * name,uint64_t cfg_handle)250 mdesc_find(const char *name, uint64_t cfg_handle)
251 {
252 struct md_header *hdr;
253 struct md_element *elem;
254 const char *str;
255 uint64_t val;
256 int idx;
257
258 hdr = (struct md_header *)mdesc;
259 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
260
261 for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) {
262 str = mdesc_get_prop_str(idx, "name");
263 val = mdesc_get_prop_val(idx, "cfg-handle");
264 if (str && strcmp(str, name) == 0 && val == cfg_handle)
265 return (idx);
266 }
267
268 return (-1);
269 }
270
271 int
mdesc_find_child(int idx,const char * name,uint64_t cfg_handle)272 mdesc_find_child(int idx, const char *name, uint64_t cfg_handle)
273 {
274 struct md_header *hdr;
275 struct md_element *elem;
276 const char *name_blk;
277 const char *str;
278 uint64_t val;
279 int arc;
280
281 hdr = (struct md_header *)mdesc;
282 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
283 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
284
285 for (; elem[idx].tag != 'E'; idx++) {
286 str = name_blk + elem[idx].name_offset;
287 if (elem[idx].tag != 'a' || strcmp(str, "fwd") != 0)
288 continue;
289
290 arc = elem[idx].d.val;
291 str = mdesc_get_prop_str(arc, "name");
292 val = mdesc_get_prop_val(arc, "cfg-handle");
293 if (str && strcmp(str, name) == 0 && val == cfg_handle)
294 return (arc);
295 }
296
297 return (-1);
298 }
299
300 int
mdesc_find_node(const char * name)301 mdesc_find_node(const char *name)
302 {
303 struct md_header *hdr;
304 struct md_element *elem;
305 const char *name_blk;
306 const char *str;
307 int idx;
308
309 hdr = (struct md_header *)mdesc;
310 elem = (struct md_element *)(mdesc + sizeof(struct md_header));
311 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
312
313 for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) {
314 str = name_blk + elem[idx].name_offset;
315 if (str && strcmp(str, name) == 0)
316 return (idx);
317 }
318
319 return (-1);
320 }
321