xref: /openbsd/sys/arch/sparc64/sparc64/mdesc.c (revision 0b1ae31b)
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