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
32namespace L4 {
33
34/**
35 * C++ %Factory interface.
36 *
37 * Factories provide an interface to create objects which are accessed via
38 * capabilities.
39 *
40 * For additional information about which objects can be created via this
41 * interface, see server-specific information in
42 * \ref l4re_concepts_kernel_factory and \ref l4re_servers.
43 *
44 * \includefile{l4/sys/factory}
45 *
46 * For the C interface refer to \ref l4_factory_api.
47 */
48class Factory : public Kobject_t<Factory, Kobject, L4_PROTO_FACTORY>
49{
50public:
51
52  typedef l4_mword_t Proto;
53
54  /**
55   * Special type to add a void argument into the factory create stream.
56   */
57  struct Nil {};
58
59  /**
60   * Special type to add a pascal string into the factory create stream.
61   *
62   * This encapsulates a string that has an explicit length.
63   */
64  struct Lstr
65  {
66    /**
67     * The character buffer.
68     */
69    char const *s;
70
71    /**
72     * The number of characters in the buffer.
73     */
74    unsigned len;
75
76    /**
77     * \param s    Pointer to the c-style string.
78     * \param len  Length in number of characters of the string s.
79     */
80    Lstr(char const *s, unsigned len) noexcept : s(s), len(len) {}
81  };
82
83  /**
84   * Stream class for the create() argument stream.
85   *
86   * This stream allows a variable number of arguments to be
87   * added to a create() call.
88   */
89  class S
90  {
91  private:
92    l4_utcb_t *u;
93    l4_msgtag_t t;
94    l4_cap_idx_t f;
95
96    template<typename T>
97    static T &&_move(T &c) { return static_cast<T &&>(c); }
98
99  public:
100    S(S const &) = delete;
101    S &operator = (S const &) & = delete;
102
103    /**
104     * Move ...
105     *
106     * \param o  Instance of S to move.
107     */
108    S(S &&o) noexcept
109    : u(o.u), t(o.t), f(o.f)
110    { o.t.raw = 0; }
111
112    S &operator = (S &&o) & noexcept
113    {
114      u = o.u;
115      t = o.t;
116      f = o.f;
117      o.t.raw = 0;
118      return *this;
119    }
120
121    /**
122     * Create a stream for a specific create() call.
123     *
124     * \param      f       The capability for the factory object (L4::Factory).
125     * \param      obj     The protocol ID to describe the type of the object
126     *                     that shall be created.
127     * \param[out] target  The capability selector for the new object. The
128     *                     caller must allocate the capability slot. The kernel
129     *                     stores the new object's capability into this slot.
130     * \param      utcb    The UTCB to use for the operation.
131     */
132    S(l4_cap_idx_t f, long obj, L4::Cap<void> target,
133      l4_utcb_t *utcb) noexcept
134    : u(utcb), t(l4_factory_create_start_u(obj, target.cap(), u)), f(f)
135    {}
136
137    /**
138     * Commit the operation in the destructor to have a cool syntax for
139     * create().
140     */
141    ~S() noexcept
142    {
143      if (t.raw)
144	l4_factory_create_commit_u(f, t, u);
145    }
146
147    /**
148     * Explicitly commits the operation and returns the result.
149     *
150     * \return The result of the create() operation.
151     */
152    operator l4_msgtag_t () noexcept
153    {
154      l4_msgtag_t r = l4_factory_create_commit_u(f, t, u);
155      t.raw = 0;
156      return r;
157    }
158
159    /**
160     * Put a single l4_mword_t as next argument.
161     *
162     * \param i  The value to add as next argument.
163     *
164     * \return  Reference to this stream.
165     */
166    void put(l4_mword_t i) noexcept
167    {
168      l4_factory_create_add_int_u(i, &t, u);
169    }
170
171    /**
172     * Put a single l4_umword_t as next argument.
173     *
174     * \param i  The value to add as next argument.
175     *
176     * \return  Reference to this stream.
177     */
178    void put(l4_umword_t i) noexcept
179    {
180      l4_factory_create_add_uint_u(i, &t, u);
181    }
182
183    /**
184     * Add a zero-terminated string as next argument.
185     *
186     * \param s  The string to add as next argument.
187     *
188     * \return  Reference to this stream.
189     *
190     * The string will be added with the zero-terminator.
191     */
192    void put(char const *s) & noexcept
193    {
194      l4_factory_create_add_str_u(s, &t, u);
195    }
196
197    /**
198     * Add a pascal string as next argument.
199     *
200     * \param s  The string to add as next argument.
201     *
202     * \return  Reference to this stream.
203     *
204     * The string will be added with the exact length given. It is the
205     * responsibility of the caller to make sure that the string is zero-
206     * terminated when that is required by the server.
207     */
208    void put(Lstr const &s) & noexcept
209    {
210      l4_factory_create_add_lstr_u(s.s, s.len, &t, u);
211    }
212
213    /**
214     * Add an empty argument.
215     *
216     * \return  Reference to this stream.
217     */
218    void put(Nil) & noexcept
219    {
220      l4_factory_create_add_nil_u(&t, u);
221    }
222
223    /**
224     * Add a flex page as next argument.
225     *
226     * \param d  The flex page to add (there will be no map operation).
227     *
228     * \return  Reference to this stream.
229     */
230    void put(l4_fpage_t d) & noexcept
231    {
232      l4_factory_create_add_fpage_u(d, &t, u);
233    }
234
235    template<typename T>
236    S &operator << (T const &d) & noexcept
237    {
238      put(d);
239      return *this;
240    }
241
242    template<typename T>
243    S &&operator << (T const &d) && noexcept
244    {
245      put(d);
246      return _move(*this);
247    }
248  };
249
250
251public:
252
253  /**
254   * Generic create call to the factory.
255   *
256   * \param[out] target  Capability selector for the new object. The caller
257   *                     must allocate the capability slot. The kernel stores
258   *                     the new objects's capability into this slot.
259   * \param      obj     The protocol ID that specifies which kind of object
260   *                     shall be created.
261   * \param      utcb    The UTCB to use for the operation.
262   *
263   * \return A create stream that allows additional arguments to be passed to
264   *         the create() call via the left-shift (<<) operator.
265   *
266   * This method does not directly invoke the factory. The factory is invoked
267   * when the create stream returned by this method is converted to an
268   * `l4_msgtag_t`, or otherwise when the stream goes out of scope.
269   *
270   * \note The create stream uses the UTCB to store parameters for the service
271   *       call. During the lifetime of a create stream or, until it is
272   *       converted to a `l4_msgtag_t`, other UTCB-using operations must not
273   *       be used.
274   *
275   * \see create(Cap<OBJ>, l4_utcb_t *)
276   */
277  S create(Cap<void> target, long obj, l4_utcb_t *utcb = l4_utcb()) noexcept
278  {
279    return S(cap(), obj, target, utcb);
280  }
281
282  /**
283   * Create call for typed capabilities.
284   *
285   * \tparam      OBJ     Capability type of the object to be created.
286   * \param[out]  target  Capability of type OBJ.
287   * \param       utcb    UTCB to use.
288   *
289   * \return A create stream that allows additional arguments to be passed to
290   *         the create() call via the left-shift (<<) operator.
291   *
292   * This method does not directly invoke the factory. The factory is invoked
293   * when the create stream returned by this method is converted to an
294   * `l4_msgtag_t`, or otherwise when the stream goes out of scope.
295   *
296   * \note The create stream uses the UTCB to store parameters for the service
297   *       call. During the lifetime of a create stream or, until it is
298   *       converted to a `l4_msgtag_t`, other UTCB-using operations must not
299   *       be used.
300   *
301   * Usage:
302   * ~~~
303   * L4::Cap<L4Re::Dataspace> ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
304   * factory->create(ds) << l4_mword_t(size_in_bytes);
305   * ~~~
306   */
307  template<typename OBJ>
308  S create(Cap<OBJ> target, l4_utcb_t *utcb = l4_utcb()) noexcept
309  {
310    return S(cap(), OBJ::Protocol, target, utcb);
311  }
312
313  L4_INLINE_RPC_NF(
314      l4_msgtag_t, create, (L4::Ipc::Out<L4::Cap<void> > target, l4_mword_t obj,
315                            L4::Ipc::Varg const *args),
316      L4::Ipc::Call_t<L4_CAP_FPAGE_S>);
317
318  /**
319   * Create a new task.
320   *
321   * \param[out] target_cap  The kernel stores the new task's capability into
322   *                         this slot.
323   * \param      utcb_area   Flexpage that describes an area in the address
324   *                         space of the new task, where the kernel should
325   *                         map the kernel-allocated kernel-user memory to.
326   *                         The kernel uses the kernel-user memory to store
327   *                         UTCBs and vCPU state-save-areas of the new task.
328   * \param      utcb        The UTCB to use for the operation.
329   *
330   * \return Syscall return tag
331   *
332   * \note The size of the UTCB area specifies indirectly the number
333   *       of UTCBs available for this task. Refer to L4::Task::add_ku_mem
334   *       / l4_task_add_ku_mem() for adding more of this type of memory.
335   *
336   * \note This method is only guaranteed to work with the
337   *       \ref l4re_concepts_kernel_factory.
338   *
339   * \see L4::Task
340   */
341  l4_msgtag_t create_task(Cap<Task> const & target_cap,
342                          l4_fpage_t const &utcb_area,
343                          l4_utcb_t *utcb = l4_utcb()) noexcept
344  { return l4_factory_create_task_u(cap(), target_cap.cap(), utcb_area, utcb); }
345
346  /**
347   * Create a new factory.
348   *
349   * \param[out] target_cap  The kernel stores the new factory's capability into
350   *                         this slot.
351   * \param      limit       Limit for the new factory in bytes.
352   * \param      utcb        The UTCB to use for the operation.
353   *
354   * \return Syscall return tag
355   *
356   * \note In addition to memory needed for internal data structures, the
357   *       `limit` (quota) of the new factory is counted towards the quota of
358   *       the creating factory. The `limit` must be within
359   *       `1 ≤ limit ≤ 2^(8 * sizeof(l4_umword_t) − 1) − 2` otherwise the
360   *       behavior is undefined.
361   *
362   * \note This method is only guaranteed to work with the
363   *       \ref l4re_concepts_kernel_factory. For other services, use the
364   *       generic create() method and consult the service documentation for
365   *       information on the arguments that need to be passed to the create
366   *       stream.
367   */
368  l4_msgtag_t create_factory(Cap<Factory> const &target_cap,
369                             unsigned long limit,
370                             l4_utcb_t *utcb = l4_utcb()) noexcept
371  { return l4_factory_create_factory_u(cap(), target_cap.cap(), limit, utcb); }
372
373  /**
374   * Create a new IPC gate.
375   *
376   * \param[out] target_cap  The kernel stores the new IPC gate's capability
377   *                         into this slot.
378   * \param      thread_cap  Optional capability selector of the thread to
379   *                         bind the gate to. Use #L4_INVALID_CAP to create
380   *                         an unbound IPC gate.
381   * \param      label       Optional label of the gate (is used if
382   *                         `thread_cap` is valid).
383   * \param      utcb        The UTCB to use for the operation.
384   *
385   * \return Syscall return tag containing one of the following return codes.
386   *
387   * \retval L4_EOK      No error occurred.
388   * \retval -L4_ENOMEM  Out-of-memory during allocation of the Ipc_gate object.
389   * \retval -L4_ENOENT  `thread_cap` is void or points to something that is not
390   *                     a thread.
391   * \retval -L4_EPERM   No #L4_CAP_FPAGE_S rights on `thread_cap`.
392   *
393   * An unbound IPC gate can be bound to a thread using
394   * L4::Ipc_gate::bind_thread().
395   *
396   * \note This method is only guaranteed to work with the
397   *       \ref l4re_concepts_kernel_factory.
398   *
399   * \see L4::Ipc_gate
400   */
401  l4_msgtag_t create_gate(Cap<void> const &target_cap,
402                          Cap<Thread> const &thread_cap, l4_umword_t label,
403                          l4_utcb_t *utcb = l4_utcb()) noexcept
404  { return l4_factory_create_gate_u(cap(), target_cap.cap(), thread_cap.cap(), label, utcb); }
405
406  typedef L4::Typeid::Rpc_nocode<create_t> Rpcs;
407};
408
409}
410