1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
|
2005-06-06 Marcus Brinkmann <marcus@gnu.org>
* include/mach/mach4.defs: Add memory_object_create_proxy
interface.
* Makefile.in (vm-cfiles): Add memory_object_proxy.c.
* i386/include/mach/i386/vm_types.h (vm_offset_array_t): New type.
* include/mach/memory_object.h (memory_object_array_t): New type.
* vm/memory_object_proxy.c: New file.
* kern/ipc_kobject.h: New macro IKOT_PAGER_PROXY. Bump up macros
IKOT_UNKNOWN and IKOT_MAX_TYPE.
* kern/ipc_kobject.c (ipc_kobject_notify): Call
memory_object_proxy_notify for IKOT_PAGER_PROXY.
* vm/vm_init.c (vm_mem_init): Call memory_object_proxy_init.
* vm/vm_user.c (vm_map): Implement support for proxy memory
objects.
Index: b/i386/include/mach/i386/vm_types.h
===================================================================
--- a/i386/include/mach/i386/vm_types.h
+++ b/i386/include/mach/i386/vm_types.h
@@ -74,6 +74,7 @@ typedef unsigned int uint32;
* e.g. an offset into a virtual memory space.
*/
typedef natural_t vm_offset_t;
+typedef vm_offset_t * vm_offset_array_t;
/*
* A vm_size_t is the proper type for e.g.
Index: b/include/mach/mach4.defs
===================================================================
--- a/include/mach/mach4.defs
+++ b/include/mach/mach4.defs
@@ -79,4 +79,34 @@ skip /* pc_sampling reserved 1*/;
skip /* pc_sampling reserved 2*/;
skip /* pc_sampling reserved 3*/;
skip /* pc_sampling reserved 4*/;
+
+#else
+
+skip; /* task_enable_pc_sampling */
+skip; /* task_disable_pc_sampling */
+skip; /* task_get_sampled_pcs */
+skip; /* thread_enable_pc_sampling */
+skip; /* thread_disable_pc_sampling */
+skip; /* thread_get_sampled_pcs */
+
+skip /* pc_sampling reserved 1*/;
+skip /* pc_sampling reserved 2*/;
+skip /* pc_sampling reserved 3*/;
+skip /* pc_sampling reserved 4*/;
+
#endif
+
+
+/* Create a new proxy memory object from [START;START+LEN) in the
+ given OBJECT at OFFSET in the new object with the maximum
+ protection MAX_PROTECTION and return it in *PORT. */
+type vm_offset_array_t = array[*:1024] of vm_offset_t;
+routine memory_object_create_proxy(
+ task : ipc_space_t;
+ max_protection : vm_prot_t;
+ object : memory_object_array_t =
+ array[*:1024] of memory_object_t;
+ offset : vm_offset_array_t;
+ start : vm_offset_array_t;
+ len : vm_offset_array_t;
+ out proxy : mach_port_t);
Index: b/include/mach/memory_object.h
===================================================================
--- a/include/mach/memory_object.h
+++ b/include/mach/memory_object.h
@@ -46,6 +46,9 @@ typedef mach_port_t memory_object_t;
/* the object to map; used by the */
/* kernel to retrieve or store data */
+typedef mach_port_t * memory_object_array_t;
+ /* should be memory_object_t * */
+
typedef mach_port_t memory_object_control_t;
/* Provided to a memory manager; ... */
/* used to control a memory object */
Index: b/kern/ipc_kobject.c
===================================================================
--- a/kern/ipc_kobject.c
+++ b/kern/ipc_kobject.c
@@ -353,6 +353,9 @@ ipc_kobject_notify(request_header, reply
case IKOT_DEVICE:
return ds_notify(request_header);
+ case IKOT_PAGER_PROXY:
+ return memory_object_proxy_notify(request_header);
+
default:
return FALSE;
}
Index: b/kern/ipc_kobject.h
===================================================================
--- a/kern/ipc_kobject.h
+++ b/kern/ipc_kobject.h
@@ -77,9 +77,10 @@ typedef unsigned int ipc_kobject_type_t;
#define IKOT_LOCK_SET 24
#define IKOT_CLOCK 25
#define IKOT_CLOCK_CTRL 26
+#define IKOT_PAGER_PROXY 27
/* << new entries here */
-#define IKOT_UNKNOWN 27 /* magic catchall */
-#define IKOT_MAX_TYPE 28 /* # of IKOT_ types */
+#define IKOT_UNKNOWN 28 /* magic catchall */
+#define IKOT_MAX_TYPE 29 /* # of IKOT_ types */
/* Please keep ipc/ipc_object.c:ikot_print_array up to date */
#define is_ipc_kobject(ikot) (ikot != IKOT_NONE)
Index: b/vm/memory_object_proxy.c
===================================================================
--- /dev/null
+++ b/vm/memory_object_proxy.c
@@ -0,0 +1,200 @@
+/* memory_object_proxy.c - Proxy memory objects for Mach.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Mach is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* A proxy memory object is a kernel port that can be used like a real
+ memory object in a vm_map call, except that the current and maximum
+ protection are restricted to the proxy object's maximum protection
+ at the time the mapping is established. The kernel port will hold
+ a reference to the real memory object for the life time of the
+ proxy object.
+
+ Note that we don't need to do any reference counting on the proxy
+ object. Our caller will hold a reference to the proxy object when
+ looking it up, and is expected to acquire its own reference to the
+ real memory object if needed before releasing the reference to the
+ proxy object.
+
+ The user provided real memory object and the maximum protection are
+ not checked for validity. The maximum protection is only used as a
+ mask, and the memory object is validated at the time the mapping is
+ established. */
+
+#include <mach/port.h>
+#include <mach/kern_return.h>
+#include <mach/notify.h>
+#include <mach/vm_prot.h>
+#include <kern/zalloc.h>
+#include <kern/mach_param.h>
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_space.h>
+
+/* The zone which holds our proxy memory objects. */
+static zone_t memory_object_proxy_zone;
+
+struct memory_object_proxy
+{
+ struct ipc_port *port;
+
+ ipc_port_t object;
+ vm_prot_t max_protection;
+};
+typedef struct memory_object_proxy *memory_object_proxy_t;
+
+
+void
+memory_object_proxy_init (void)
+{
+ /* For limit, see PORT_MAX. */
+ memory_object_proxy_zone = zinit (sizeof (struct memory_object_proxy), 0,
+ (TASK_MAX * 3 + THREAD_MAX)
+ * sizeof (struct memory_object_proxy),
+ 256 * sizeof (struct memory_object_proxy),
+ ZONE_EXHAUSTIBLE,
+ "proxy memory object zone");
+}
+
+/* Lookup a proxy memory object by its port. */
+static memory_object_proxy_t
+memory_object_proxy_port_lookup (ipc_port_t port)
+{
+ memory_object_proxy_t proxy;
+
+ if (!IP_VALID(port))
+ return 0;
+
+ ip_lock (port);
+ if (ip_active (port) && (ip_kotype (port) == IKOT_PAGER_PROXY))
+ proxy = (memory_object_proxy_t) port->ip_kobject;
+ else
+ proxy = 0;
+ ip_unlock (port);
+ return proxy;
+}
+
+
+/* Process a no-sender notification for the proxy memory object
+ port. */
+boolean_t
+memory_object_proxy_notify (mach_msg_header_t *msg)
+{
+ if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS)
+ {
+ memory_object_proxy_t proxy;
+ mach_no_senders_notification_t *ns;
+
+ ns = (mach_no_senders_notification_t *) msg;
+ proxy = memory_object_proxy_port_lookup
+ ((ipc_port_t) ns->not_header.msgh_remote_port);
+ assert (proxy);
+
+ ipc_port_release_send (proxy->object);
+ return TRUE;
+ }
+
+ printf ("memory_object_proxy_notify: strange notification %d\n",
+ msg->msgh_id);
+ return FALSE;
+}
+
+
+/* Create a new proxy memory object from [START;START+LEN) in the
+ given OBJECT at OFFSET in the new object with the maximum
+ protection MAX_PROTECTION and return it in *PORT. */
+kern_return_t
+memory_object_create_proxy (ipc_space_t space, vm_prot_t max_protection,
+ ipc_port_t *object, natural_t object_count,
+ vm_offset_t *offset, natural_t offset_count,
+ vm_offset_t *start, natural_t start_count,
+ vm_offset_t *len, natural_t len_count,
+ ipc_port_t *port)
+{
+ kern_return_t kr;
+ memory_object_proxy_t proxy;
+ ipc_port_t notify;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (offset_count != object_count || start_count != object_count
+ || len_count != object_count)
+ return KERN_INVALID_ARGUMENT;
+
+ /* FIXME: Support more than one memory object. */
+ if (object_count != 1)
+ return KERN_INVALID_ARGUMENT;
+
+ if (!IP_VALID(object[0]))
+ return KERN_INVALID_NAME;
+
+ /* FIXME: Support a different offset from 0. */
+ if (offset[0] != 0)
+ return KERN_INVALID_ARGUMENT;
+
+ /* FIXME: Support a different range from total. */
+ if (start[0] != 0 || len[0] != (vm_offset_t) ~0)
+ return KERN_INVALID_ARGUMENT;
+
+ proxy = (memory_object_proxy_t) zalloc (memory_object_proxy_zone);
+
+ /* Allocate port, keeping a reference for it. */
+ proxy->port = ipc_port_alloc_kernel ();
+ if (proxy->port == IP_NULL)
+ {
+ zfree (memory_object_proxy_zone, (vm_offset_t) proxy);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+ /* Associate the port with the proxy memory object. */
+ ipc_kobject_set (proxy->port, (ipc_kobject_t) proxy, IKOT_PAGER_PROXY);
+
+ /* Request no-senders notifications on the port. */
+ notify = ipc_port_make_sonce (proxy->port);
+ ip_lock (proxy->port);
+ ipc_port_nsrequest (proxy->port, 1, notify, ¬ify);
+ assert (notify == IP_NULL);
+
+ proxy->object = ipc_port_copy_send (object[0]);
+ proxy->max_protection = max_protection;
+
+ *port = ipc_port_make_send (proxy->port);
+ return KERN_SUCCESS;
+}
+
+
+/* Lookup the real memory object and maximum protection for the proxy
+ memory object port PORT, for which the caller holds a reference.
+ *OBJECT is only guaranteed to be valid as long as the caller holds
+ the reference to PORT (unless the caller acquires its own reference
+ to it). If PORT is not a proxy memory object, return
+ KERN_INVALID_ARGUMENT. */
+kern_return_t
+memory_object_proxy_lookup (ipc_port_t port, ipc_port_t *object,
+ vm_prot_t *max_protection)
+{
+ memory_object_proxy_t proxy;
+
+ proxy = memory_object_proxy_port_lookup (port);
+ if (!proxy)
+ return KERN_INVALID_ARGUMENT;
+
+ *object = proxy->object;
+ *max_protection = proxy->max_protection;
+
+ return KERN_SUCCESS;
+}
Index: b/vm/vm_init.c
===================================================================
--- a/vm/vm_init.c
+++ b/vm/vm_init.c
@@ -81,4 +81,5 @@ void vm_mem_bootstrap()
void vm_mem_init()
{
vm_object_init();
+ memory_object_proxy_init();
}
Index: b/vm/vm_user.c
===================================================================
--- a/vm/vm_user.c
+++ b/vm/vm_user.c
@@ -275,6 +275,12 @@ kern_return_t vm_copy(map, source_addres
return KERN_SUCCESS;
}
+
+/* XXX From memory_object_proxy.c */
+kern_return_t
+memory_object_proxy_lookup (ipc_port_t proxy_object, ipc_port_t *object,
+ vm_prot_t *max_protection);
+
/*
* Routine: vm_map
*/
@@ -324,7 +330,22 @@ kern_return_t vm_map(
copy = FALSE;
} else if ((object = vm_object_enter(memory_object, size, FALSE))
== VM_OBJECT_NULL)
- return(KERN_INVALID_ARGUMENT);
+ {
+ ipc_port_t real_memobj;
+ vm_prot_t prot;
+ result = memory_object_proxy_lookup (memory_object, &real_memobj,
+ &prot);
+ if (result != KERN_SUCCESS)
+ return result;
+
+ /* Reduce the allowed access to the memory object. */
+ max_protection &= prot;
+ cur_protection &= prot;
+
+ if ((object = vm_object_enter(real_memobj, size, FALSE))
+ == VM_OBJECT_NULL)
+ return KERN_INVALID_ARGUMENT;
+ }
/*
* Perform the copy if requested
Index: b/Makefrag.am
===================================================================
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -214,6 +214,7 @@ libkernel_a_SOURCES += \
#
libkernel_a_SOURCES += \
+ vm/memory_object_proxy.c \
vm/memory_object.c \
vm/memory_object.h \
vm/pmap.h \
|