1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_special.c,v $
29 * Revision 2.4 92/03/10 16:28:17 jsb
30 * Merged in norma branch changes as of NORMA_MK7.
31 * [92/03/09 12:50:20 jsb]
32 *
33 * Revision 2.3.2.4 92/02/18 19:16:34 jeffreyh
34 * Use IP_NORMA_IS_PROXY macro instead of checking for norma_uid
35 * in norma_port_location_hint. The latter gives the wrong
36 * answer if the port has been exported and we're not node 0.
37 * [92/02/14 dlb]
38 *
39 * Revision 2.3.2.3 92/01/21 21:52:33 jsb
40 * More de-linting.
41 * [92/01/17 11:41:55 jsb]
42 *
43 * De-linted.
44 * [92/01/16 22:14:38 jsb]
45 *
46 * Revision 2.3.2.2 92/01/09 18:45:51 jsb
47 * Removed placeholder logic.
48 * Added remote_{special,device,host,host_priv} routines.
49 * [92/01/04 18:35:52 jsb]
50 *
51 * Revision 2.3.2.1 92/01/03 16:37:58 jsb
52 * Corrected log. Removed norma_token_startup call. Fixed type clash.
53 * [91/12/24 14:26:15 jsb]
54 *
55 * Revision 2.2 91/11/14 16:48:12 rpd
56 * Moved from norma/ipc_xxx.c.
57 *
58 * Revision 2.5 91/08/28 11:16:15 jsb
59 * Renamed clport things to norma things.
60 * Eliminated NORMA_ETHER special case node/lid uid division.
61 * [91/08/15 09:14:06 jsb]
62 *
63 * Renamed ipc_clport_foo things to norma_ipc_foo.
64 * Added host_port_at_node().
65 * [91/08/14 19:21:16 jsb]
66 *
67 * Revision 2.4 91/08/03 18:19:34 jsb
68 * Conditionalized printfs.
69 * [91/08/01 22:55:17 jsb]
70 *
71 * Eliminated dynamically allocated clport structures; this information
72 * is now stored in ports directly. This simplifies issues of allocation
73 * at interrupt time.
74 *
75 * Added definitions for IP_CLPORT_{NODE,LID} appropriate for using the
76 * low two bytes of an internet address as a node number.
77 *
78 * Revised norma_special_port mechanism to better handle port death
79 * and port replacement. Eliminated redundant special port calls.
80 * Cleaned up associated startup code.
81 * [91/07/25 19:09:16 jsb]
82 *
83 * Revision 2.3 91/07/01 08:25:52 jsb
84 * Some locking changes.
85 * [91/06/29 15:10:46 jsb]
86 *
87 * Revision 2.2 91/06/17 15:48:05 jsb
88 * Moved here from ipc/ipc_clport.c.
89 * [91/06/17 11:07:25 jsb]
90 *
91 * Revision 2.7 91/06/06 17:05:35 jsb
92 * Added norma_get_special_port, norma_set_special_port.
93 * [91/05/25 10:28:14 jsb]
94 *
95 * Much code moved to other norma/ files.
96 * [91/05/13 17:16:24 jsb]
97 *
98 */
99 /*
100 * File: norma/ipc_special.c
101 * Author: Joseph S. Barrera III
102 * Date: 1990
103 *
104 * Functions to support norma special ports.
105 */
106
107 #include <norma_vm.h>
108 #include <norma_ether.h>
109
110 #include <vm/vm_kern.h>
111 #include <mach/vm_param.h>
112 #include <mach/port.h>
113 #include <mach/message.h>
114 #include <mach/norma_special_ports.h>
115 #include <kern/assert.h>
116 #include <kern/host.h>
117 #include <kern/sched_prim.h>
118 #include <kern/ipc_sched.h>
119 #include <kern/ipc_kobject.h>
120 #include <kern/zalloc.h>
121 #include <device/device_port.h>
122 #include <ipc/ipc_mqueue.h>
123 #include <ipc/ipc_thread.h>
124 #include <ipc/ipc_kmsg.h>
125 #include <ipc/ipc_port.h>
126 #include <ipc/ipc_pset.h>
127 #include <ipc/ipc_space.h>
128 #include <ipc/ipc_marequest.h>
129 #include <norma/ipc_node.h>
130
131 extern void netipc_thread();
132 extern ipc_port_t norma_port_lookup();
133 extern void netipc_thread_lock();
134 extern void netipc_thread_unlock();
135 extern void norma_port_insert();
136
137 ipc_port_t host_special_port_array[MAX_SPECIAL_ID];
138 #define host_special_port(id) (host_special_port_array[id])
139
140 /*
141 * The first three special ports are kernel owned.
142 * They are DEVICE, HOST, and HOST_PRIV.
143 * The kernel has receive rights to these ports.
144 * Users are not allowed to change these ports.
145 * No-more senders notifications are not requested for these ports.
146 */
147
148 norma_ipc_init()
149 {
150 /*
151 * Register master device, host, and host_priv ports.
152 */
153 assert(master_device_port != IP_NULL);
154 master_device_port->ip_norma_is_special = TRUE;
155 host_special_port(NORMA_DEVICE_PORT) = master_device_port;
156
157 assert(realhost.host_self != IP_NULL);
158 realhost.host_self->ip_norma_is_special = TRUE;
159 host_special_port(NORMA_HOST_PORT) = realhost.host_self;
160
161 assert(realhost.host_priv_self != IP_NULL);
162 realhost.host_priv_self->ip_norma_is_special = TRUE;
163 host_special_port(NORMA_HOST_PRIV_PORT) = realhost.host_priv_self;
164
165 /*
166 * Initialize network subsystem
167 */
168 netipc_init();
169
170 /*
171 * Start up netipc thread, kserver module, and token module.
172 * XXX netipc_init should do the former...
173 */
174 (void) kernel_thread(kernel_task, netipc_thread, (char *) 0);
175 norma_kserver_startup();
176 }
177
178 /*
179 * XXX should probably eliminate this -- it's a hack used by the xmm system
180 */
181 ipc_port_node(port)
182 ipc_port_t port;
183 {
184 if (!port) return node_self();
185 if (!port->ip_norma_uid) return node_self();
186 return IP_NORMA_NODE(port->ip_norma_uid);
187 }
188
189 kern_return_t
190 norma_port_location_hint(task, port, node)
191 task_t task;
192 ipc_port_t port;
193 int *node;
194 {
195 if (port == IP_NULL) {
196 return KERN_INVALID_ARGUMENT;
197 }
198 if (IP_NORMA_IS_PROXY(port)) {
199 *node = port->ip_norma_dest_node;
200 } else {
201 *node = node_self();
202 }
203 return KERN_SUCCESS;
204 }
205
206 kern_return_t
207 norma_set_special_port(host, id, port)
208 host_t host;
209 unsigned long id;
210 ipc_port_t port;
211 {
212 ipc_port_t old;
213
214 if (host == HOST_NULL) {
215 return KERN_INVALID_HOST;
216 }
217 if (id <= 0 || id > MAX_SPECIAL_ID) {
218 return KERN_INVALID_VALUE;
219 }
220 if (id <= MAX_SPECIAL_KERNEL_ID) {
221 /* these never change */
222 return KERN_INVALID_VALUE;
223 }
224 netipc_thread_lock();
225 old = host_special_port(id);
226 host_special_port(id) = port;
227 port->ip_norma_is_special = TRUE;
228 if (IP_VALID(old)) {
229 fret("special id #%d replaced\n", id);
230 ipc_port_release_send(old);
231 }
232 netipc_thread_unlock();
233 return KERN_SUCCESS;
234 }
235
236 /*
237 * Internally called when port is being destroyed.
238 * XXX
239 * Is it also called when proxy is destroyed???
240 */
241 norma_unset_special_port(port)
242 ipc_port_t port;
243 {
244 unsigned long id;
245
246 for (id = 1; id <= MAX_SPECIAL_ID; id++) {
247 if (host_special_port(id) == port) {
248 assert(id >= MAX_SPECIAL_KERNEL_ID);
249 fret("special id #%d died\n", id);
250 host_special_port(id) = IP_NULL;
251 ipc_port_release_send(port);
252 }
253 }
254 port->ip_norma_is_special = FALSE;
255 }
256
257 ipc_port_t
258 local_special(id)
259 unsigned long id;
260 {
261 assert(IP_NORMA_SPECIAL(id));
262 assert(id > 0 && id <= MAX_SPECIAL_KERNEL_ID);
263 return ipc_port_make_send(host_special_port(id));
264 }
265
266 ipc_port_t
267 remote_special(node, id)
268 unsigned long node;
269 unsigned long id;
270 {
271 ipc_port_t port;
272 unsigned long uid = IP_NORMA_UID(node, id);
273
274 assert(node != node_self());
275 assert(id > 0 && id <= MAX_SPECIAL_KERNEL_ID);
276 port = norma_port_lookup(uid);
277 if (port == IP_NULL) {
278 port = ipc_port_alloc_special(ipc_space_remote);
279 if (port == IP_NULL) {
280 panic("remote_special: ipc_port_alloc_special");
281 }
282 port->ip_nsrequest = ip_nsproxym(port);
283 port->ip_srights = 1;
284 port->ip_norma_uid = uid;
285 port->ip_norma_dest_node = node;
286 port->ip_norma_is_proxy = TRUE;
287 norma_port_insert(port);
288 } else {
289 port->ip_srights++;
290 }
291 port->ip_norma_stransit = -0x70000000; /* XXX */
292 return port;
293 }
294
295 ipc_port_t
296 remote_device(node)
297 unsigned long node;
298 {
299 return remote_special(node, (unsigned long) NORMA_DEVICE_PORT);
300 }
301
302 ipc_port_t
303 remote_host(node)
304 unsigned long node;
305 {
306 return remote_special(node, (unsigned long) NORMA_HOST_PORT);
307 }
308
309 ipc_port_t
310 remote_host_priv(node)
311 unsigned long node;
312 {
313 return remote_special(node, (unsigned long) NORMA_HOST_PRIV_PORT);
314 }
315
316 /*
317 * XXX
318 * The blocking behavior of this call is now somewhat funny.
319 * A remote call will block until the remote node comes up.
320 * However, in either local or remote case, a null port may be returned;
321 * that is, we do not block for a valid port to show up.
322 */
323 kern_return_t
324 norma_get_special_port(host, node, id, portp)
325 host_t host;
326 unsigned long node;
327 unsigned long id;
328 ipc_port_t *portp;
329 {
330 if (host == HOST_NULL) {
331 return KERN_INVALID_HOST;
332 }
333 if (id <= 0 || id > MAX_SPECIAL_ID) {
334 return KERN_INVALID_ARGUMENT;
335 }
336 if (id <= MAX_SPECIAL_KERNEL_ID) {
337 if (node == node_self()) {
338 *portp = local_special(id);
339 } else {
340 *portp = remote_special(node, id);
341 }
342 } else {
343 if (node == node_self()) {
344 *portp = ipc_port_copy_send(host_special_port(id));
345 } else {
346 return r_norma_get_special_port(remote_host_priv(node),
347 node, id, portp);
348 }
349 }
350 return KERN_SUCCESS;
351 }
Cache object: 3ee8183ba218521b47da2bbbf53fbb1c
|