1 /* $OpenBSD: mdesc.c,v 1.3 2009/05/10 12:37:01 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.h> 24 25 #include <machine/autoconf.h> 26 #include <machine/hypervisor.h> 27 #include <machine/mdesc.h> 28 29 caddr_t mdesc; 30 paddr_t mdesc_pa; 31 size_t mdesc_len; 32 33 void 34 mdesc_init(void) 35 { 36 struct pglist mlist; 37 struct vm_page *m; 38 psize_t len, size; 39 paddr_t pa; 40 vaddr_t va; 41 int err; 42 43 hv_mach_desc((paddr_t)NULL, &len); 44 KASSERT(len != 0); 45 46 again: 47 size = round_page(len); 48 49 TAILQ_INIT(&mlist); 50 err = uvm_pglistalloc(len, 0, -1, PAGE_SIZE, 0, &mlist, 1, 51 UVM_PLA_NOWAIT); 52 if (err) 53 panic("%s: out of memory", __func__); 54 55 len = size; 56 pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); 57 err = hv_mach_desc(pa, &len); 58 if (err != H_EOK) 59 goto fail; 60 61 va = uvm_km_valloc(kernel_map, len); 62 if (va == 0) 63 panic("%s: out of memory", __func__); 64 65 mdesc = (caddr_t)va; 66 mdesc_pa = pa; 67 mdesc_len = len; 68 69 m = TAILQ_FIRST(&mlist); 70 for (; m != NULL; m = TAILQ_NEXT(m,pageq)) { 71 pa = VM_PAGE_TO_PHYS(m); 72 pmap_enter(pmap_kernel(), va, pa, VM_PROT_READ|VM_PROT_WRITE, 73 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); 74 va += PAGE_SIZE; 75 } 76 pmap_update(pmap_kernel()); 77 78 return; 79 80 fail: 81 uvm_pglistfree(&mlist); 82 83 /* 84 * If the machine description was updated while we were trying 85 * to fetch it, the allocated buffer may have been to small. 86 * Try again in that case. 87 */ 88 if (err == H_EINVAL && len > size) 89 goto again; 90 91 return; 92 } 93 94 uint64_t 95 mdesc_get_prop_val(int idx, const char *name) 96 { 97 struct md_header *hdr; 98 struct md_element *elem; 99 const char *name_blk; 100 const char *str; 101 102 hdr = (struct md_header *)mdesc; 103 elem = (struct md_element *)(mdesc + sizeof(struct md_header)); 104 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz; 105 106 while (elem[idx].tag != 'E') { 107 str = name_blk + elem[idx].name_offset; 108 if (elem[idx].tag == 'v' && strcmp(str, name) == 0) 109 return (elem[idx].d.val); 110 idx++; 111 } 112 113 return (-1); 114 } 115 116 const char * 117 mdesc_get_prop_str(int idx, const char *name) 118 { 119 struct md_header *hdr; 120 struct md_element *elem; 121 const char *name_blk; 122 const char *data_blk; 123 const char *str; 124 125 hdr = (struct md_header *)mdesc; 126 elem = (struct md_element *)(mdesc + sizeof(struct md_header)); 127 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz; 128 data_blk = name_blk + hdr->name_blk_sz; 129 130 while (elem[idx].tag != 'E') { 131 str = name_blk + elem[idx].name_offset; 132 if (elem[idx].tag == 's' && strcmp(str, name) == 0) 133 return (data_blk + elem[idx].d.y.data_offset); 134 idx++; 135 } 136 137 return (NULL); 138 } 139 140 int 141 mdesc_find(const char *name, uint64_t cfg_handle) 142 { 143 struct md_header *hdr; 144 struct md_element *elem; 145 const char *str; 146 uint64_t val; 147 int idx; 148 149 hdr = (struct md_header *)mdesc; 150 elem = (struct md_element *)(mdesc + sizeof(struct md_header)); 151 152 for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) { 153 str = mdesc_get_prop_str(idx, "name"); 154 val = mdesc_get_prop_val(idx, "cfg-handle"); 155 if (str && strcmp(str, name) == 0 && val == cfg_handle) 156 return (idx); 157 } 158 159 return (-1); 160 } 161 162 int 163 mdesc_find_child(int idx, const char *name, uint64_t cfg_handle) 164 { 165 struct md_header *hdr; 166 struct md_element *elem; 167 const char *name_blk; 168 const char *str; 169 uint64_t val; 170 int arc; 171 172 hdr = (struct md_header *)mdesc; 173 elem = (struct md_element *)(mdesc + sizeof(struct md_header)); 174 name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz; 175 176 for (; elem[idx].tag != 'E'; idx++) { 177 str = name_blk + elem[idx].name_offset; 178 if (elem[idx].tag != 'a' || strcmp(str, "fwd") != 0) 179 continue; 180 181 arc = elem[idx].d.val; 182 str = mdesc_get_prop_str(arc, "name"); 183 val = mdesc_get_prop_val(arc, "cfg-handle"); 184 if (str && strcmp(str, name) == 0 && val == cfg_handle) 185 return (arc); 186 } 187 188 return (-1); 189 } 190