xref: /titanic_44/usr/src/lib/efcode/engine/mcookie.c (revision c06fe975984a85c8ca4faa9dc8b176203f45e04b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 
33 #include <fcode/private.h>
34 #include <fcode/log.h>
35 
36 #include <fcdriver/fcdriver.h>
37 
38 #define	MAX_MAPS	256
39 
40 #define	MAP_IS_VALID		0x01
41 
42 struct map_table {
43 	int map_flags;
44 	uint64_t map_add;
45 	size_t map_size;
46 	uint64_t adj_virt;
47 	size_t adj_length;
48 } map_table[MAX_MAPS];
49 
50 /*
51  * Originally, this code translated kernel supplied virtual addresses into
52  * "memory cookies", which was a 32-bit number with ascii-M in the upper 8
53  * bits, a 4-bit index and a 20-bit offset.  However, this caused two
54  * problems:  1) the 20-bit offset was too small for some devices, esp. some
55  * with frame-buffers;  2) if the fcode used the cookie to program the
56  * hardware, there was no easy way for the software to detect that a
57  * translation needed to be done.
58  *
59  * For that reason, "memory cookies" are now just the kernel-supplied
60  * virtual address, and we now check each memory access to see if it's
61  * attempting to access kernel-supplied memory.  The only important thing
62  * now is that "is_mcookie" returns 1 (or true) if the tested mcookie
63  * is a kernel virtual address.
64  *
65  * There is a potential bug if the kernel virtual address happens to
66  * conflict with a user virtual address.  However, the current implementation
67  * of Solaris avoids this conflict.
68  */
69 
70 fstack_t
71 mapping_to_mcookie(uint64_t req_add, size_t req_size, uint64_t adj_virt,
72     size_t adj_length)
73 {
74 	int i;
75 	struct map_table *mp;
76 
77 	for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++)
78 		if ((mp->map_flags & MAP_IS_VALID) == 0)
79 			break;
80 	if (i == MAX_MAPS) {
81 		log_message(MSG_WARN, "Warning: too many mappings\n");
82 		return (0);
83 	}
84 	debug_msg(DEBUG_REG_ACCESS, "Allocating mapping: %d add: 0x%llx"
85 	    " size: 0x%x\n", i, req_add, req_size);
86 	mp->map_flags |= MAP_IS_VALID;
87 	mp->map_add = req_add;
88 	mp->map_size = req_size;
89 	mp->adj_virt = adj_virt;
90 	mp->adj_length = adj_length;
91 	if (mp->adj_length != 0)
92 		return (adj_virt);
93 	else
94 		return (req_add);
95 }
96 
97 void
98 delete_mapping(fstack_t mcookie)
99 {
100 	int i;
101 	struct map_table *mp;
102 
103 	for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) {
104 		if ((mp->map_flags & MAP_IS_VALID) &&
105 		    mcookie >= mp->map_add &&
106 		    mcookie < mp->map_add + mp->map_size) {
107 			debug_msg(DEBUG_REG_ACCESS, "Deallocating mapping: %d"
108 			    " add: 0x%llx size: 0x%x\n", i, mp->map_add,
109 			    mp->map_size);
110 			mp->map_flags &= ~MAP_IS_VALID;
111 			mp->map_add = 0;
112 			mp->map_size = 0;
113 			mp->adj_virt = 0;
114 			mp->adj_length = 0;
115 			return;
116 		}
117 	}
118 	log_message(MSG_WARN, "Warning: delete_mapping: invalid"
119 		" mcookie: %llx\n", (uint64_t)mcookie);
120 }
121 
122 int
123 is_mcookie(fstack_t mcookie)
124 {
125 	struct map_table *mp;
126 	int i;
127 
128 	for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++)
129 		if ((mp->map_flags & MAP_IS_VALID) &&
130 		    mcookie >= mp->map_add &&
131 		    mcookie < mp->map_add + mp->map_size)
132 			return (1);
133 	return (0);
134 }
135 
136 uint64_t
137 mcookie_to_addr(fstack_t mcookie)
138 {
139 	return (mcookie);
140 }
141 
142 fstack_t
143 mcookie_to_rlen(fstack_t mcookie)
144 {
145 	int i;
146 	struct map_table *mp;
147 
148 	for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) {
149 		if ((mp->map_flags & MAP_IS_VALID) &&
150 		    mcookie >= mp->map_add &&
151 		    mcookie < mp->map_add + mp->map_size) {
152 			return (mp->map_size);
153 		}
154 	}
155 	log_message(MSG_WARN, "Warning: mcookie_to_rlen: invalid"
156 	    " mcookie: %llx\n", (uint64_t)mcookie);
157 
158 	return (0);
159 }
160 
161 fstack_t
162 mcookie_to_rvirt(fstack_t mcookie)
163 {
164 	int i;
165 	struct map_table *mp;
166 
167 	for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) {
168 		if ((mp->map_flags & MAP_IS_VALID) &&
169 		    mcookie >= mp->map_add &&
170 		    mcookie < mp->map_add + mp->map_size) {
171 			return (mp->map_add);
172 		}
173 	}
174 	log_message(MSG_WARN, "Warning: mcookie_to_rvirt: invalid"
175 	    " mcookie: %llx\n", (uint64_t)mcookie);
176 
177 	return (0);
178 }
179 
180 static void
181 dot_maps(fcode_env_t *env)
182 {
183 	int i;
184 
185 	log_message(MSG_DEBUG, "idx     base-addr        size\n");
186 	for (i = 0; i < MAX_MAPS; i++) {
187 		if (map_table[i].map_flags & MAP_IS_VALID)
188 			log_message(MSG_DEBUG, "%3d %016llx %8x\n", i,
189 			    map_table[i].map_add, map_table[i].map_size);
190 	}
191 }
192 
193 static void
194 map_qmark(fcode_env_t *env)
195 {
196 	fstack_t d = POP(DS);
197 
198 	if (!is_mcookie(d))
199 		log_message(MSG_INFO, "%llx: not mcookie\n", (uint64_t)d);
200 	else
201 		log_message(MSG_INFO, "%llx -> %llx\n", (uint64_t)d,
202 		    mcookie_to_addr(d));
203 }
204 
205 static void
206 add_map(fcode_env_t *env)
207 {
208 	fstack_t size, addr;
209 
210 	size = POP(DS);
211 	addr = POP(DS);
212 	addr = mapping_to_mcookie(addr, size, NULL, NULL);
213 	PUSH(DS, addr);
214 }
215 
216 static void
217 del_map(fcode_env_t *env)
218 {
219 	fstack_t addr;
220 
221 	addr = POP(DS);
222 	delete_mapping(addr);
223 }
224 
225 
226 #pragma init(_init)
227 
228 static void
229 _init(void)
230 {
231 	fcode_env_t *env = initial_env;
232 
233 	ASSERT(env);
234 	NOTICE;
235 
236 	FORTH(0,	".maps",		dot_maps);
237 	FORTH(0,	"map?",			map_qmark);
238 	FORTH(0,	"add-map",		add_map);
239 	FORTH(0,	"del-map",		del_map);
240 }
241