15 |
along with this program; if not, write to the Free Software |
along with this program; if not, write to the Free Software |
16 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
17 |
|
|
18 |
|
#include <rtmk/vm-types.h> |
19 |
|
#include <rtmk/vm-param.h> |
20 |
|
#include <rtmk/ipc-types.h> |
21 |
|
#include <rtmk/ipc-port.h> |
22 |
|
#include <rtmk/ipc-return.h> |
23 |
|
#include <stdarg.h> |
24 |
|
|
25 |
#include "tm.h" |
#include "tm.h" |
26 |
#include "trace.h" |
#include "trace.h" |
27 |
|
#include "vm-slab.h" |
28 |
|
#include "vm-kmem.h" |
29 |
|
#include "task.h" |
30 |
|
|
31 |
#include "ipc-kmsg.h" |
#include "ipc-kmsg.h" |
32 |
|
|
33 |
|
#define KERNEL_MSG_SIZE (256-4) |
34 |
|
|
35 |
|
static struct kmem_cache *atomic_cache; |
36 |
|
static struct kmem_cache *kmsg_cache; |
37 |
|
|
38 |
|
/* Copy a message into a kernel buffer must be done in a "atomic" |
39 |
|
manner. If we fail somewhere along the road the task state must |
40 |
|
be unchanged. |
41 |
|
|
42 |
|
To do this we have hold a list of atomic elements that will be |
43 |
|
executed when we have checked all rights and permissions. */ |
44 |
|
|
45 |
|
enum ipc_atomic_type |
46 |
|
{ |
47 |
|
IPC_ATOMIC_PORT_REMOVE, /* Remove port from task. */ |
48 |
|
IPC_ATOMIC_PORT_REF /* ??? */ |
49 |
|
}; |
50 |
|
|
51 |
|
struct ipc_atomic |
52 |
|
{ |
53 |
|
enum ipc_atomic_type type; |
54 |
|
|
55 |
|
union { |
56 |
|
rtmk_port_t name; |
57 |
|
struct ipc_port *port; |
58 |
|
} params; |
59 |
|
}; |
60 |
|
|
61 |
|
/* Add a new element to array of atomic operations. */ |
62 |
|
|
63 |
|
static void atomic_add (struct ipc_atomic ***atomics, int *n_atomics, |
64 |
|
int *n_max_atomics, enum ipc_atomic_type type, ...); |
65 |
|
|
66 |
|
/* Execute atomic operations specified in ATOMICS. */ |
67 |
|
|
68 |
|
static void atomic_execute (struct task *task, struct ipc_atomic **atomics, |
69 |
|
int n_atomics); |
70 |
|
|
71 |
|
|
72 |
|
/* Initialize kernel messages. */ |
73 |
|
|
74 |
|
void |
75 |
|
ipc_kmsg_init (void) |
76 |
|
{ |
77 |
|
kmsg_cache = kmem_cache_create ("ipc kmsg cache", KERNEL_MSG_SIZE, 0); |
78 |
|
atomic_cache = kmem_cache_create ("ipc atomic cache", |
79 |
|
sizeof (struct ipc_atomic), 0); |
80 |
|
assert (kmsg_cache && atomic_cache); |
81 |
|
} |
82 |
|
|
83 |
|
/* Allocate a new kernel message with SIZE bytes payload. |
84 |
|
SIZE includes the size of the header. */ |
85 |
|
|
86 |
|
struct ipc_kmsg * |
87 |
|
ipc_kmsg_alloc (vm_size_t size) |
88 |
|
{ |
89 |
|
struct ipc_kmsg *kmsg; |
90 |
|
|
91 |
|
/* Check if we can use memory from the "common size" cache. */ |
92 |
|
|
93 |
|
if ((size - sizeof (struct rtmk_msg_header)) |
94 |
|
<= (KERNEL_MSG_SIZE - sizeof (struct ipc_kmsg))) |
95 |
|
{ |
96 |
|
kmsg = (struct ipc_kmsg *) kmem_cache_alloc (kmsg_cache); |
97 |
|
} |
98 |
|
|
99 |
|
/* We have to allocate more than usual memory for message. */ |
100 |
|
else |
101 |
|
{ |
102 |
|
vm_size_t total_size; |
103 |
|
|
104 |
|
/* ??? should we not use kmem_malloc? */ |
105 |
|
|
106 |
|
total_size = vm_round_page (size + sizeof (struct ipc_kmsg) |
107 |
|
- sizeof (struct rtmk_msg_header)); |
108 |
|
kmsg = (struct ipc_kmsg *) kmem_alloc_wired (VM_MAP_KERNEL (), |
109 |
|
total_size); |
110 |
|
} |
111 |
|
|
112 |
|
if (kmsg) |
113 |
|
kmsg->length = size; |
114 |
|
return kmsg; |
115 |
|
} |
116 |
|
|
117 |
|
/* Free a kernel message allocated with ipc_kmsg_alloc. */ |
118 |
|
|
119 |
void |
void |
120 |
ipc_kmsg_free (struct ipc_kmsg *kmsg) |
ipc_kmsg_free (struct ipc_kmsg *kmsg) |
121 |
{ |
{ |
122 |
|
if ((kmsg->length - sizeof (struct rtmk_msg_header)) |
123 |
|
<= (KERNEL_MSG_SIZE - sizeof (struct ipc_kmsg))) |
124 |
|
{ |
125 |
|
kmem_cache_free (kmsg_cache, kmsg); |
126 |
|
} |
127 |
|
else |
128 |
|
kmem_free (VM_MAP_KERNEL (), (vm_offset_t) kmsg); |
129 |
|
} |
130 |
|
|
131 |
|
|
132 |
|
/* Copy in a kernel message from kernel address/ipc space into a |
133 |
|
kernel message buffer. TASK must be kernel task. |
134 |
|
|
135 |
|
There's one destinction from user and kernel messages; the kernel |
136 |
|
have rights to all ports so it do not operate on rights (or capabilites), |
137 |
|
instead it uses points to the IPC port structure. |
138 |
|
|
139 |
|
??? currently OOL memory can not be sent from kernel. */ |
140 |
|
|
141 |
|
kern_return_t |
142 |
|
ipc_kmsg_copyin_kernel (struct task *task, struct ipc_kmsg *kmsg) |
143 |
|
{ |
144 |
|
struct rtmk_msg_header *msgh = &kmsg->header; |
145 |
|
|
146 |
|
/* First we fill the kmsg structure with some information. */ |
147 |
|
|
148 |
|
kmsg->remote_port = (struct ipc_port *) msgh->msgh_remote_port; |
149 |
|
kmsg->local_port = (struct ipc_port *) msgh->msgh_local_port; |
150 |
|
|
151 |
|
/* Kernel never sends simple messages and it never sends to itself. */ |
152 |
|
|
153 |
|
kmsg->complex_p = true; |
154 |
|
kmsg->intratask_p = false; |
155 |
|
|
156 |
|
/* Length field of kmsg is already set by the alloc function. */ |
157 |
|
|
158 |
|
/* ??? since we do not support OOL memory from kernel yet, |
159 |
|
we can just return here since we are done. */ |
160 |
|
return KERN_SUCCESS; |
161 |
|
} |
162 |
|
|
163 |
|
|
164 |
|
/* ??? convenience function for expanding an atomic element array. */ |
165 |
|
|
166 |
|
static inline void expand_atomic_array (struct ipc_atomic ***atomics, |
167 |
|
int *n_atomics, int *n_max_atomics) |
168 |
|
{ |
169 |
|
if (*atomics == 0) |
170 |
|
{ |
171 |
|
*n_max_atomics = 16; |
172 |
|
*n_atomics = 0; |
173 |
|
*atomics = |
174 |
|
(struct ipc_atomic **) kmem_zalloc (*n_max_atomics |
175 |
|
* sizeof (struct ipc_atomic *)); |
176 |
|
} |
177 |
|
|
178 |
|
if (*n_atomics == *n_max_atomics) |
179 |
|
{ |
180 |
|
struct ipc_atomic **new_atomics; |
181 |
|
|
182 |
|
*n_max_atomics <<= 1; |
183 |
|
|
184 |
|
new_atomics = |
185 |
|
(struct ipc_atomic **) kmem_zalloc (*n_max_atomics |
186 |
|
* sizeof (struct ipc_atomic *)); |
187 |
|
memcpy (*atomics, new_atomics, |
188 |
|
*n_atomics * sizeof (struct ipc_atomic *)); |
189 |
|
|
190 |
|
kmem_mfree (*atomics); |
191 |
|
*atomics = new_atomics; |
192 |
|
} |
193 |
|
} |
194 |
|
|
195 |
|
|
196 |
|
/* Add an atomic element to list of elements (ATOMIC). */ |
197 |
|
|
198 |
|
static void |
199 |
|
atomic_add (struct ipc_atomic ***atomics, int *n_atomics, |
200 |
|
int *n_max_atomics, enum ipc_atomic_type type, ...) |
201 |
|
{ |
202 |
|
struct ipc_atomic *atomic; |
203 |
|
va_list ap; |
204 |
|
|
205 |
|
expand_atomic_array (atomics, n_atomics, n_max_atomics); |
206 |
|
|
207 |
|
va_start (ap, type); |
208 |
|
|
209 |
|
atomic = kmem_cache_alloc (atomic_cache); |
210 |
|
atomic->type = type; |
211 |
|
|
212 |
|
switch (type) |
213 |
|
{ |
214 |
|
case IPC_ATOMIC_PORT_REMOVE: |
215 |
|
{ |
216 |
|
rtmk_port_t name = va_arg (ap, rtmk_port_t); |
217 |
|
atomic->params.name = name; |
218 |
|
break; |
219 |
|
} |
220 |
|
|
221 |
|
case IPC_ATOMIC_PORT_REF: |
222 |
|
{ |
223 |
|
break; |
224 |
|
} |
225 |
|
} |
226 |
|
|
227 |
|
*atomics[*n_atomics++] = atomic; |
228 |
|
va_end (ap); |
229 |
} |
} |
230 |
|
|
231 |
|
/* Execute an array of atomic elements. This also releases all |
232 |
|
memory allocated by "atomic_add". */ |
233 |
|
|
234 |
|
static void |
235 |
|
atomic_execute (struct task *task, struct ipc_atomic **atomics, |
236 |
|
int n_atomics) |
237 |
|
{ |
238 |
|
struct ipc_atomic *atomic; |
239 |
|
|
240 |
|
int i; |
241 |
|
|
242 |
|
for (i = 0; i < n_atomics; i++) |
243 |
|
{ |
244 |
|
atomic = atomics [i]; |
245 |
|
|
246 |
|
switch (atomic->type) |
247 |
|
{ |
248 |
|
case IPC_ATOMIC_PORT_REMOVE: |
249 |
|
break; |
250 |
|
case IPC_ATOMIC_PORT_REF: |
251 |
|
break; |
252 |
|
} |
253 |
|
kmem_cache_free (atomic_cache, atomic); |
254 |
|
} |
255 |
|
kmem_mfree (atomics); |
256 |
|
} |