1 /* $OpenBSD: mdesc.c,v 1.8 2019/10/20 16:27:19 kettenis 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 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 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 parellel 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 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 * 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 * 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 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 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 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