L4Re - L4 Runtime Environment
factory
Go to the documentation of this file.
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /**
3  * \file
4  * Common factory related definitions.
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  * Alexander Warg <warg@os.inf.tu-dresden.de>
9  * economic rights: Technische Universit├Ąt Dresden (Germany)
10  *
11  * This file is part of TUD:OS and distributed under the terms of the
12  * GNU General Public License 2.
13  * Please see the COPYING-GPL-2 file for details.
14  *
15  * As a special exception, you may use this file as part of a free software
16  * library without restriction. Specifically, if other files instantiate
17  * templates or use macros or inline functions from this file, or you compile
18  * this file and link it with other files to produce an executable, this
19  * file does not by itself cause the resulting executable to be covered by
20  * the GNU General Public License. This exception does not however
21  * invalidate any other reasons why the executable file might be covered by
22  * the GNU General Public License.
23  */
24 
25 #pragma once
26 
27 #include <l4/sys/factory.h>
28 #include <l4/sys/capability>
29 #include <l4/sys/cxx/ipc_iface>
30 #include <l4/sys/cxx/ipc_varg>
31 
32 namespace L4 {
33 
34 /**
35  * C++ Factory interface to create kernel objects.
36  *
37  * A factory is used to create all kinds of kernel objects:
38  * - L4::Task
39  * - L4::Thread
40  * - L4::Factory
41  * - L4::Ipc_gate
42  * - L4::Irq
43  * - L4::Vm
44  *
45  * The factory is equipped with a limit that limits the amount of kernel
46  * memory available to that factory.
47  *
48  * \note The limit does not give any guarantee for the amount of available
49  * kernel memory.
50  *
51  * \includefile{l4/sys/factory}
52  *
53  * For the C interface refer to \ref l4_factory_api.
54  */
55 class Factory : public Kobject_t<Factory, Kobject, L4_PROTO_FACTORY>
56 {
57 public:
58 
59  typedef l4_mword_t Proto;
60 
61  /**
62  * Special type to add a void argument into the factory create stream.
63  */
64  struct Nil {};
65 
66  /**
67  * Special type to add a pascal string into the factory create stream.
68  *
69  * This encapsulates a string that has an explicit length.
70  */
71  struct Lstr
72  {
73  /**
74  * The character buffer.
75  */
76  char const *s;
77 
78  /**
79  * The number of characters in the buffer.
80  */
81  int len;
82 
83  /**
84  * \param s Pointer to the c-style string.
85  * \param len Length in number of characters of the string s.
86  */
87  Lstr(char const *s, int len) : s(s), len(len) {}
88  };
89 
90  /**
91  * Stream class for the create() argument stream.
92  *
93  * This stream allows a variable number of arguments to be
94  * added to a create() call.
95  */
96  class S
97  {
98  private:
99  l4_utcb_t *u;
100  l4_msgtag_t t;
101  l4_cap_idx_t f;
102 
103  public:
104  /**
105  * Create a copy.
106  *
107  * \param o Instance of S to copy.
108  */
109  S(S const &o)
110  : u(o.u), t(o.t), f(o.f)
111  { const_cast<S&>(o).t.raw = 0; }
112 
113  /**
114  * Create a stream for a specific create() call.
115  *
116  * \param f The capability for the factory object (L4::Factory).
117  * \param obj The protocol ID to describe the type of the object
118  * that shall be created.
119  * \param[out] target The capability selector for the new object. The
120  * caller must allocate the capability slot. The kernel
121  * stores the new object's capability into this slot.
122  * \param utcb The UTCB to use for the operation.
123  */
124  S(l4_cap_idx_t f, long obj, L4::Cap<void> target,
125  l4_utcb_t *utcb) throw()
126  : u(utcb), t(l4_factory_create_start_u(obj, target.cap(), u)), f(f)
127  {}
128 
129  /**
130  * Commit the operation in the destructor to have a cool syntax for
131  * create().
132  */
133  ~S()
134  {
135  if (t.raw)
136  l4_factory_create_commit_u(f, t, u);
137  }
138 
139  /**
140  * Explicitly commits the operation and returns the result.
141  *
142  * \return The result of the create() operation.
143  */
144  operator l4_msgtag_t ()
145  {
146  l4_msgtag_t r = l4_factory_create_commit_u(f, t, u);
147  t.raw = 0;
148  return r;
149  }
150 
151  /**
152  * Put a single l4_mword_t as next argument.
153  *
154  * \param i The value to add as next argument.
155  *
156  * \return Reference to this stream.
157  */
158  S &operator << (l4_mword_t i)
159  {
160  l4_factory_create_add_int_u(i, &t, u);
161  return *this;
162  }
163 
164  /**
165  * Put a single l4_umword_t as next argument.
166  *
167  * \param i The value to add as next argument.
168  *
169  * \return Reference to this stream.
170  */
171  S &operator << (l4_umword_t i)
172  {
173  l4_factory_create_add_uint_u(i, &t, u);
174  return *this;
175  }
176 
177  /**
178  * Add a zero-terminated string as next argument.
179  *
180  * \param s The string to add as next argument.
181  *
182  * \return Reference to this stream.
183  *
184  * The string will be added with the zero-terminator.
185  */
186  S &operator << (char const *s)
187  {
188  l4_factory_create_add_str_u(s, &t, u);
189  return *this;
190  }
191 
192  /**
193  * Add a pascal string as next argument.
194  *
195  * \param s The string to add as next argument.
196  *
197  * \return Reference to this stream.
198  *
199  * The string will be added with the exact length given. It is the
200  * responsibility of the caller to make sure that the string is zero-
201  * terminated when that is required by the server.
202  */
203  S &operator << (Lstr const &s)
204  {
205  l4_factory_create_add_lstr_u(s.s, s.len, &t, u);
206  return *this;
207  }
208 
209  /**
210  * Add an empty argument.
211  *
212  * \return Reference to this stream.
213  */
214  S &operator << (Nil)
215  {
216  l4_factory_create_add_nil_u(&t, u);
217  return *this;
218  }
219 
220  /**
221  * Add a flex page as next argument.
222  *
223  * \param d The flex page to add (there will be no map operation).
224  *
225  * \return Reference to this stream.
226  */
227  S &operator << (l4_fpage_t d)
228  {
229  l4_factory_create_add_fpage_u(d, &t, u);
230  return *this;
231  }
232  };
233 
234 
235 public:
236 
237  /**
238  * Generic create call to the factory.
239  *
240  * \param[out] target Capability selector for the new object. The caller
241  * must allocate the capability slot. The kernel stores
242  * the new objects's capability into this slot.
243  * \param obj The protocol ID that specifies which kind of object
244  * shall be created.
245  * \param utcb The UTCB to use for the operation.
246  *
247  * \return A create stream that allows adding additional arguments to the
248  * create() call.
249  *
250  * This method does currently not directly invoke the factory. It returns a
251  * stream that shall invoke the factory after adding all additional arguments.
252  *
253  * Usage:
254  * ~~~
255  * L4::Cap<L4Re::Namespace> ns = L4Re::Util::cap_alloc.alloc<L4Re::Namespace>();
256  * factory->create(ns, L4Re::Namespace::Protocol) << "Argument text";
257  * ~~~
258  */
259  S create(Cap<void> target, long obj, l4_utcb_t *utcb = l4_utcb()) throw()
260  {
261  return S(cap(), obj, target, utcb);
262  }
263 
264  /**
265  * Create call for typed capabilities.
266  *
267  * \tparam OBJ Capability type of the object to be created.
268  * \param[out] target Capability of type OBJ.
269  * \param utcb UTCB to use.
270  *
271  * \return Argument stream to call the factory.
272  *
273  * \see create
274  */
275  template<typename OBJ>
276  S create(Cap<OBJ> target, l4_utcb_t *utcb = l4_utcb()) throw()
277  {
278  return S(cap(), OBJ::Protocol, target, utcb);
279  }
280 
281  L4_INLINE_RPC_NF(
282  l4_msgtag_t, create, (L4::Ipc::Out<L4::Cap<void> > target, l4_mword_t obj,
283  L4::Ipc::Varg const *args),
284  L4::Ipc::Call_t<L4_CAP_FPAGE_S>);
285 
286  /**
287  * Create a new task.
288  *
289  * \param[out] target_cap The kernel stores the new task's capability into
290  * this slot.
291  * \param utcb_area Flexpage that describes an area in the address
292  * space of the new task, where the kernel should
293  * map the kernel-allocated kernel-user memory to.
294  * The kernel uses the kernel-user memory to store
295  * UTCBs and vCPU state-save-areas of the new task.
296  * \param utcb The UTCB to use for the operation.
297  *
298  * \return Syscall return tag
299  *
300  * \note The size of the UTCB area specifies indirectly the number
301  * of UTCBs available for this task. Refer to L4::Task::add_ku_mem
302  * / l4_task_add_ku_mem() for adding more of this type of memory.
303  *
304  * \see L4::Task
305  */
306  l4_msgtag_t create_task(Cap<Task> const & target_cap,
307  l4_fpage_t const &utcb_area,
308  l4_utcb_t *utcb = l4_utcb()) throw()
309  { return l4_factory_create_task_u(cap(), target_cap.cap(), utcb_area, utcb); }
310 
311  /**
312  * Create a new thread.
313  *
314  * \param[out] target_cap The kernel stores the new thread's capability into
315  * this slot.
316  * \param utcb The UTCB to use for the operation.
317  *
318  * \return Syscall return tag
319  *
320  * \deprecated Use `create()` with `Cap<Thread>` as argument instead.
321  *
322  * \see L4::Thread
323  */
324  l4_msgtag_t create_thread(Cap<Thread> const &target_cap,
325  l4_utcb_t *utcb = l4_utcb()) throw()
326  L4_DEPRECATED("Call create with Cap<Thread> as argument instead.")
327  { return l4_factory_create_thread_u(cap(), target_cap.cap(), utcb); }
328 
329  /**
330  * Create a new factory.
331  *
332  * \param[out] target_cap The kernel stores the new factory's capability into
333  * this slot.
334  * \param limit Limit for the new factory in bytes.
335  * \param utcb The UTCB to use for the operation.
336  *
337  * \return Syscall return tag
338  *
339  * \note The limit of the new factory is subtracted from the available amount
340  * of the factory used for creation.
341  */
342  l4_msgtag_t create_factory(Cap<Factory> const &target_cap,
343  unsigned long limit,
344  l4_utcb_t *utcb = l4_utcb()) throw()
345  { return l4_factory_create_factory_u(cap(), target_cap.cap(), limit, utcb); }
346 
347  /**
348  * Create a new IPC gate.
349  *
350  * \param[out] target_cap The kernel stores the new IPC gate's capability
351  * into this slot.
352  * \param thread_cap Optional capability selector of the thread to
353  * bind the gate to. Use #L4_INVALID_CAP to create
354  * an unbound IPC gate.
355  * \param label Optional label of the gate (is used if
356  * `thread_cap` is valid).
357  * \param utcb The UTCB to use for the operation.
358  *
359  * \return Syscall return tag containing one of the following return codes.
360  *
361  * \retval L4_EOK No error occurred.
362  * \retval -L4_ENOMEM Out-of-memory during allocation of the Ipc_gate object.
363  * \retval -L4_ENOENT `thread_cap` is void or points to something that is not
364  * a thread.
365  * \retval -L4_EPERM No write rights on `thread_cap`.
366  *
367  * An unbound IPC gate can be bound to a thread using
368  * L4::Ipc_gate::bind_thread().
369  *
370  * \see L4::Ipc_gate
371  */
372  l4_msgtag_t create_gate(Cap<void> const &target_cap,
373  Cap<Thread> const &thread_cap, l4_umword_t label,
374  l4_utcb_t *utcb = l4_utcb()) throw()
375  { return l4_factory_create_gate_u(cap(), target_cap.cap(), thread_cap.cap(), label, utcb); }
376 
377  /**
378  * Create a new IRQ.
379  *
380  * \param[out] target_cap The kernel stores the new IRQ's capability into
381  * this slot.
382  * \param utcb The UTCB to use for the operation.
383  *
384  * \return Syscall return tag
385  *
386  * \deprecated Use `create()` with `Cap<Irq>` as argument instead.
387  *
388  * \see L4::Irq
389  */
390  l4_msgtag_t create_irq(Cap<Irq>const &target_cap,
391  l4_utcb_t *utcb = l4_utcb()) throw()
392  L4_DEPRECATED("Call create with Cap<Irq> as argument instead.")
393  { return l4_factory_create_irq_u(cap(), target_cap.cap(), utcb); }
394 
395  /**
396  * Create a new virtual machine.
397  *
398  * \param[out] target_cap The kernel stores the new VM's capability into this
399  * slot.
400  * \param utcb The UTCB to use for the operation.
401  *
402  * \return Syscall return tag
403  *
404  * \deprecated Use `create()` with `Cap<Vm>` as argument instead.
405  *
406  * \see L4::Vm
407  */
408  l4_msgtag_t create_vm(Cap<Vm>const &target_cap,
409  l4_utcb_t *utcb = l4_utcb()) throw()
410  L4_DEPRECATED("Call create with Cap<Vm> as argument instead.")
411  { return l4_factory_create_vm_u(cap(), target_cap.cap(), utcb); }
412 
413  typedef L4::Typeid::Rpc_nocode<create_t> Rpcs;
414 };
415 
416 }