2 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU Lesser General Public License 2.1.
7 * Please see the COPYING-LGPL-2.1 file for details.
9 #include <l4/shmc/shmc.h>
11 #include <l4/sys/err.h>
12 #include <l4/sys/factory.h>
13 #include <l4/sys/task.h>
14 #include <l4/re/env.h>
15 #include <l4/re/c/util/cap_alloc.h>
16 #include <l4/re/c/rm.h>
17 #include <l4/re/c/mem_alloc.h>
18 #include <l4/re/c/namespace.h>
19 #include <l4/sys/debugger.h>
21 #include <l4/util/util.h>
22 #include <l4/util/atomic.h>
27 /* Head of a shared memory data memory, which has a size of multiple pages
28 * No task local data must be in here (pointers, caps)
31 l4_umword_t lock; // lock for handling chunks
32 l4_addr_t _first_chunk; // offset to first chunk
36 SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
40 MAX_SIZE = (~0UL) >> 1,
43 static inline l4shmc_chunk_desc_t *
44 chunk_get(l4_addr_t o, void *shm_local_addr)
46 return (l4shmc_chunk_desc_t *)(o + (l4_addr_t)shm_local_addr);
50 l4shmc_create(const char *shm_name, l4_umword_t shm_size)
53 l4re_ds_t shm_ds = L4_INVALID_CAP;
54 l4re_namespace_t shm_cap;
57 if (shm_size > MAX_SIZE)
60 shm_cap = l4re_env_get_cap(shm_name);
61 if (l4_is_invalid_cap(shm_cap))
64 if (l4_is_invalid_cap(shm_ds = l4re_util_cap_alloc()))
67 if ((r = l4re_ma_alloc(shm_size, shm_ds, 0)))
68 goto out_shm_free_cap;
70 if ((r = l4re_rm_attach((void **)&s, shm_size, L4RE_RM_SEARCH_ADDR, shm_ds,
72 goto out_shm_free_mem;
75 s->lock = SHMAREA_LOCK_FREE;
77 if ((r = l4re_ns_register_obj_srv(shm_cap, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
78 goto out_shm_free_mem;
80 l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
87 l4re_util_cap_free(shm_ds);
93 l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
94 l4shmc_area_t *shmarea)
97 l4re_namespace_t nssrv;
99 strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
100 shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
101 shmarea->_local_addr = 0;
103 if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
106 nssrv = l4re_env_get_cap(shm_name);
107 if (l4_is_invalid_cap(nssrv))
109 printf("shm: did not find '%s' namespace\n", shm_name);
113 if ((r = l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms)))
115 printf("shm: did not find shm-ds 'shm' (%ld)\n", r);
119 r = l4shmc_area_size(shmarea);
127 if ((r = l4re_rm_attach(&shmarea->_local_addr, shmarea->_size,
128 L4RE_RM_SEARCH_ADDR, shmarea->_shm_ds,
135 l4re_util_cap_free(shmarea->_shm_ds);
140 l4shmc_area_overhead(void)
142 return sizeof(shared_mem_t);
146 l4shmc_chunk_overhead(void)
148 return sizeof(l4shmc_chunk_desc_t);
151 static long next_chunk(l4shmc_area_t *shmarea, l4_addr_t offs)
153 shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
154 volatile l4shmc_chunk_desc_t *p;
159 next = shm_addr->_first_chunk;
163 p = chunk_get(offs, shmarea->_local_addr);
168 if (next >= shmarea->_size || next + sizeof(*p) >= shmarea->_size || next <= offs)
170 if (next % sizeof(l4_addr_t) != 0)
172 p = chunk_get(next, shmarea->_local_addr);
173 if (p->_magic != L4SHMC_CHUNK_MAGIC)
179 l4shmc_iterate_chunk(l4shmc_area_t *shmarea, const char **chunk_name, long offs)
183 offs = next_chunk(shmarea, offs);
186 l4shmc_chunk_desc_t *p = chunk_get(offs, shmarea->_local_addr);
187 *chunk_name = p->_name;
193 l4shmc_add_chunk(l4shmc_area_t *shmarea,
194 const char *chunk_name,
195 l4_umword_t chunk_capacity,
196 l4shmc_chunk_t *chunk)
198 shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
200 l4shmc_chunk_desc_t *p = NULL;
201 l4shmc_chunk_desc_t *prev = NULL;
205 if (chunk_capacity >> (sizeof(chunk_capacity) * 8 - 1))
208 while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
211 asm volatile ("" : : : "memory");
212 while ((ret = next_chunk(shmarea, offs)) > 0)
214 p = chunk_get(ret, shmarea->_local_addr);
215 if (strcmp(p->_name, chunk_name) == 0)
225 offs = sizeof(shared_mem_t);
228 l4_addr_t n = p->_offset + p->_capacity + sizeof(*p);
229 if (n <= offs || n >= shmarea->_size)
238 if (offs + chunk_capacity + sizeof(*p) > (unsigned long)shmarea->_size)
241 goto out_free_lock; // no more free memory in this shm
243 p = chunk_get(offs, shmarea->_local_addr);
246 p->_capacity = chunk_capacity;
248 p->_status = L4SHMC_CHUNK_CLEAR;
249 p->_magic = L4SHMC_CHUNK_MAGIC;
250 strncpy(p->_name, chunk_name, sizeof(p->_name));
251 p->_name[sizeof(p->_name) - 1] = 0;
252 // Ensure that other CPUs have correct data before inserting chunk
253 __sync_synchronize();
258 shm_addr->_first_chunk = offs;
260 __sync_synchronize();
261 shm_addr->lock = SHMAREA_LOCK_FREE;
264 chunk->_shm = shmarea;
266 chunk->_capacity = chunk_capacity;
270 shm_addr->lock = SHMAREA_LOCK_FREE;
275 l4shmc_area_size_free(l4shmc_area_t *shmarea)
279 while ((ret = next_chunk(shmarea, offs)) > 0)
283 ret = shmarea->_size - offs;
284 return ret > 0 ? ret : 0;
288 l4shmc_add_signal(l4shmc_area_t *shmarea,
289 const char *signal_name,
290 l4shmc_signal_t *signal)
292 /* Now that the chunk is allocated in the shm, lets get the UIRQ
295 l4re_namespace_t tmp;
296 char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
298 tmp = l4re_env_get_cap(shmarea->_name);
299 if (l4_is_invalid_cap(tmp))
302 signal->_sigcap = l4re_util_cap_alloc();
303 if (l4_is_invalid_cap(signal->_sigcap))
306 if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
310 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
311 b[sizeof(b) - 1] = 0;
313 r = l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0);
320 l4_task_unmap(L4_BASE_TASK_CAP,
321 l4_obj_fpage(signal->_sigcap, 0, L4_FPAGE_RWX),
324 l4re_util_cap_free(signal->_sigcap);
329 l4shmc_get_chunk_to(l4shmc_area_t *shmarea,
330 const char *chunk_name,
331 l4_umword_t timeout_ms,
332 l4shmc_chunk_t *chunk)
334 l4_kernel_clock_t try_until = l4re_kip()->clock + (timeout_ms * 1000);
340 while ((ret = next_chunk(shmarea, offs)) > 0)
342 l4shmc_chunk_desc_t *p;
344 p = chunk_get(offs, shmarea->_local_addr);
345 if (!strcmp(p->_name, chunk_name))
347 chunk->_shm = shmarea;
350 chunk->_capacity = p->_capacity;
351 if (chunk->_capacity > shmarea->_size ||
352 chunk->_capacity + offs > shmarea->_size)
365 while (l4re_kip()->clock < try_until);
371 l4shmc_attach_signal_to(l4shmc_area_t *shmarea,
372 const char *signal_name,
374 l4_umword_t timeout_ms,
375 l4shmc_signal_t *signal)
379 r = l4shmc_get_signal_to(shmarea, signal_name, timeout_ms, signal);
383 if ((r = l4_error(l4_irq_attach(signal->_sigcap,
384 (l4_umword_t)signal, thread))))
386 printf("Error on irq_attach(): %ld (sigcap %lx, sig_id %lx, thread %lx\n",
387 r, signal->_sigcap, l4_debugger_global_id(signal->_sigcap),
389 l4re_util_cap_free(signal->_sigcap);
397 l4shmc_get_signal_to(l4shmc_area_t *shmarea,
398 const char *signal_name,
399 l4_umword_t timeout_ms,
400 l4shmc_signal_t *signal)
402 char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
404 l4_cpu_time_t timeout;
406 ns = l4re_env_get_cap(shmarea->_name);
407 if (l4_is_invalid_cap(ns))
410 signal->_sigcap = l4re_util_cap_alloc();
411 if (l4_is_invalid_cap(signal->_sigcap))
414 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
415 b[sizeof(b) - 1] = 0;
417 timeout = l4re_kip()->clock + timeout_ms * 1000;
420 int e = l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms);
424 l4re_util_cap_free(signal->_sigcap);
427 if (l4re_kip()->clock < timeout)
439 l4shmc_connect_chunk_signal(l4shmc_chunk_t *chunk,
440 l4shmc_signal_t *signal)
442 chunk->_sig = signal;
447 l4shmc_enable_signal(l4shmc_signal_t *s)
449 return l4_error(l4_irq_unmask(s->_sigcap));
453 l4shmc_enable_chunk(l4shmc_chunk_t *p)
455 return l4shmc_enable_signal(p->_sig);
459 l4shmc_wait_any_to(l4_timeout_t timeout, l4shmc_signal_t **p)
464 if ((r = l4_ipc_error(l4_ipc_wait(l4_utcb(), &l, timeout), l4_utcb())))
467 *p = (l4shmc_signal_t *)l;
473 l4shmc_wait_signal_to(l4shmc_signal_t *s, l4_timeout_t timeout)
477 if ((r = l4_ipc_error(l4_irq_receive(s->_sigcap, timeout), l4_utcb())))
484 l4shmc_wait_chunk_to(l4shmc_chunk_t *p, l4_timeout_t to)
486 return l4shmc_wait_signal_to(p->_sig, to);