1 /**
2  * \file
3  * Virtual console interface.
4  */
5 /*
6  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
7  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
8  *               Torsten Frenzel <frenzel@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 #pragma once
25 
26 #include <l4/sys/ipc.h>
27 
28 /**
29  * \defgroup l4_vcon_api Virtual Console
30  * \ingroup  l4_kernel_object_api
31  * Virtual console for simple character based input and output.
32  *
33  * The interrupt for read events is provided by the virtual key interrupt
34  * which, in contrast to hardware IRQs, implements a limited functionality:
35  *  - Only IRQ line 0 is supported, no MSI vectors.
36  *  - The IRQ is edge-triggered and the IRQ mode cannot be changed.
37  *  - As the IRQ is edge-triggered, it does not have to be explicitly unmasked.
38  *
39  * \includefile{l4/sys/vcon.h}
40  *
41  * See L4::Vcon for the C++ interface.
42  */
43 
44 /**
45  * Send data to virtual console.
46  * \ingroup l4_vcon_api
47  *
48  * \param vcon  Vcon object.
49  * \param buf   Pointer to data buffer.
50  * \param size  Size of buffer in bytes.
51  *
52  * \return Syscall return tag
53  *
54  * \note Size must not exceed #L4_VCON_WRITE_SIZE, a proper value of the
55  *       `size` parameter is NOT checked. Also, this function is a send only
56  *       operation, this means there is no return value except for a failed
57  *       send operation. Use l4_ipc_error() to check for send errors, do not
58  *       use l4_error(), as l4_error() will always return an error.
59  */
60 L4_INLINE l4_msgtag_t
61 l4_vcon_send(l4_cap_idx_t vcon, char const *buf, unsigned size) L4_NOTHROW;
62 
63 /**
64  * \ingroup l4_vcon_api
65  * \copybrief L4::Vcon::send
66  * \param vcon  Capability index of the Vcon object.
67  * \copydetails L4::Vcon::send
68  */
69 L4_INLINE l4_msgtag_t
70 l4_vcon_send_u(l4_cap_idx_t vcon, char const *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW;
71 
72 /**
73  * Write data to virtual console.
74  * \ingroup l4_vcon_api
75  *
76  * \param vcon  Vcon object.
77  * \param buf   Pointer to data buffer.
78  * \param size  Size of buffer in bytes.
79  *
80  * \retval <0   Error.
81  * \retval >=0  Number of bytes written to the virtual console
82  */
83 L4_INLINE long
84 l4_vcon_write(l4_cap_idx_t vcon, char const *buf, unsigned size) L4_NOTHROW;
85 
86 /**
87  * \ingroup l4_vcon_api
88  * \copybrief L4::Vcon::write
89  * \param vcon  Capability index of the vcon object.
90  * \copydetails L4::Vcon::write
91  */
92 L4_INLINE long
93 l4_vcon_write_u(l4_cap_idx_t vcon, char const *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW;
94 
95 /**
96  * Size constants.
97  * \ingroup l4_vcon_api
98  */
99 enum L4_vcon_size_consts
100 {
101   /** Maximum size that can be written with one l4_vcon_write call. */
102   L4_VCON_WRITE_SIZE = (L4_UTCB_GENERIC_DATA_SIZE - 2) * sizeof(l4_umword_t),
103   /** Maximum size that can be read with one l4_vcon_read* call. */
104   L4_VCON_READ_SIZE  = (L4_UTCB_GENERIC_DATA_SIZE - 1) * sizeof(l4_umword_t),
105 };
106 
107 /**
108  * Read data from virtual console.
109  * \ingroup l4_vcon_api
110  *
111  * \param      vcon    Vcon object.
112  * \param[out] buf     Pointer to data buffer.
113  * \param      size    Size of buffer in bytes.
114  *
115  * \retval <0      Error code.
116  * \retval >size   If more bytes are to read, `size` bytes are in the
117  *                 buffer `buf`.
118  * \retval <=size  Number of bytes read.
119  *
120  * \note Size must not exceed #L4_VCON_READ_SIZE.
121  */
122 L4_INLINE int
123 l4_vcon_read(l4_cap_idx_t vcon, char *buf, unsigned size) L4_NOTHROW;
124 
125 /**
126  * \ingroup l4_vcon_api
127  * \copybrief L4::Vcon::read
128  * \param vcon  Capability index of the vcon object.
129  * \copydetails L4::Vcon::read
130  */
131 L4_INLINE int
132 l4_vcon_read_u(l4_cap_idx_t vcon, char *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW;
133 
134 /**
135  * Read data from virtual console, extended version including flags.
136  * \ingroup l4_vcon_api
137  *
138  * \param      vcon  Vcon object.
139  * \param[out] buf   Pointer to data buffer.
140  * \param      size  Size of buffer in bytes.
141  *
142  * If this function returns a positive value the caller can check the
143  * #L4_VCON_READ_STAT_BREAK flag bit for a break condition. The bytes read
144  * can be obtained by masking the return value with #L4_VCON_READ_SIZE_MASK.
145  *
146  * If a break condition is signaled, it is always the first event in the
147  * transmitted content, i.e. all characters supplied by this read call
148  * follow the break condition.
149  *
150  * `buf` might be a `NULL`, in this case the input data will be dropped.
151  *
152  * \note Size must not exceed #L4_VCON_READ_SIZE.
153  *
154  * \retval <0      Error code.
155  * \retval >size   More bytes to read, `size` bytes are in the buffer `buf`.
156  * \retval <=size  Number of bytes read.
157  */
158 L4_INLINE int
159 l4_vcon_read_with_flags(l4_cap_idx_t vcon, char *buf, unsigned size) L4_NOTHROW;
160 
161 /**
162  * \internal
163  */
164 L4_INLINE int
165 l4_vcon_read_with_flags_u(l4_cap_idx_t vcon, char *buf, unsigned size,
166                           l4_utcb_t *utcb) L4_NOTHROW;
167 
168 /**
169  * Vcon read flags
170  */
171 enum L4_vcon_read_flags
172 {
173   L4_VCON_READ_SIZE_MASK  = 0x3fffffff,  ///< Size mask
174   L4_VCON_READ_STAT_BREAK = 1 << 30,     ///< Break condition flag
175   L4_VCON_READ_STAT_DONE  = 1 << 31,     ///< Done condition flag
176 };
177 
178 /**
179  * Vcon attribute structure.
180  * \ingroup l4_vcon_api
181  */
182 typedef struct l4_vcon_attr_t
183 {
184   l4_umword_t i_flags; ///< input flags
185   l4_umword_t o_flags; ///< output flags
186   l4_umword_t l_flags; ///< local flags
187 } l4_vcon_attr_t;
188 
189 /**
190  * Input flags.
191  * \ingroup l4_vcon_api
192  */
193 enum L4_vcon_i_flags
194 {
195   L4_VCON_INLCR  = 000100, ///< Translate NL to CR
196   L4_VCON_IGNCR  = 000200, ///< Ignore CR
197   L4_VCON_ICRNL  = 000400, ///< Translate CR to NL if L4_VCON_IGNCR is not set
198 };
199 
200 /**
201  * Output flags.
202  * \ingroup l4_vcon_api
203  */
204 enum L4_vcon_o_flags
205 {
206   L4_VCON_ONLCR  = 000004, ///< Translate NL to CR-NL
207   L4_VCON_OCRNL  = 000010, ///< Translate CR to NL
208   L4_VCON_ONLRET = 000040, ///< Do not output CR
209 };
210 
211 /**
212  * Local flags.
213  * \ingroup l4_vcon_api
214  */
215 enum L4_vcon_l_flags
216 {
217   L4_VCON_ICANON = 000002,  ///< Canonical mode
218   L4_VCON_ECHO   = 000010,  ///< Echo input
219 };
220 
221 /**
222  * Set attributes of a Vcon.
223  * \ingroup l4_vcon_api
224  *
225  * \param vcon  Vcon object.
226  * \param attr  Attribute structure.
227  * \return Syscall return tag
228  */
229 L4_INLINE l4_msgtag_t
230 l4_vcon_set_attr(l4_cap_idx_t vcon, l4_vcon_attr_t const *attr) L4_NOTHROW;
231 
232 /**
233  * \ingroup l4_vcon_api
234  * \copybrief L4::Vcon::set_attr
235  * \param vcon  Capability index of the vcon object.
236  * \copydetails L4::Vcon::set_attr
237  */
238 L4_INLINE l4_msgtag_t
239 l4_vcon_set_attr_u(l4_cap_idx_t vcon, l4_vcon_attr_t const *attr,
240                    l4_utcb_t *utcb) L4_NOTHROW;
241 
242 /**
243  * Get attributes of a Vcon.
244  * \ingroup l4_vcon_api
245  *
246  * \param      vcon  Vcon object.
247  * \param[out] attr  Attribute structure.
248  * \return Syscall return tag
249  */
250 L4_INLINE l4_msgtag_t
251 l4_vcon_get_attr(l4_cap_idx_t vcon, l4_vcon_attr_t *attr) L4_NOTHROW;
252 
253 /**
254  * \ingroup l4_vcon_api
255  * \copybrief L4::Vcon::get_attr
256  * \param vcon  Capability index of the vcon object.
257  * \copydetails L4::Vcon::get_attr
258  */
259 L4_INLINE l4_msgtag_t
260 l4_vcon_get_attr_u(l4_cap_idx_t vcon, l4_vcon_attr_t *attr,
261                    l4_utcb_t *utcb) L4_NOTHROW;
262 
263 
264 /**
265  * Operations on vcon objects.
266  * \ingroup l4_protocol_ops
267  */
268 enum L4_vcon_ops
269 {
270   L4_VCON_WRITE_OP       = 0UL,    /**< Write */
271   L4_VCON_READ_OP        = 1UL,    /**< Read */
272   L4_VCON_SET_ATTR_OP    = 2UL,    /**< Get console attributes */
273   L4_VCON_GET_ATTR_OP    = 3UL,    /**< Set console attributes */
274 };
275 
276 /******* Implementations ********************/
277 
278 L4_INLINE l4_msgtag_t
l4_vcon_send_u(l4_cap_idx_t vcon,char const * buf,unsigned size,l4_utcb_t * utcb)279 l4_vcon_send_u(l4_cap_idx_t vcon, char const *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW
280 {
281   l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
282   mr->mr[0] = L4_VCON_WRITE_OP;
283   mr->mr[1] = size;
284   __builtin_memcpy(&mr->mr[2], buf, size);
285   return l4_ipc_send(vcon, utcb,
286                      l4_msgtag(L4_PROTO_LOG, 2 + l4_bytes_to_mwords(size),
287                                0, L4_MSGTAG_SCHEDULE),
288                      L4_IPC_NEVER);
289 }
290 
291 L4_INLINE l4_msgtag_t
l4_vcon_send(l4_cap_idx_t vcon,char const * buf,unsigned size)292 l4_vcon_send(l4_cap_idx_t vcon, char const *buf, unsigned size) L4_NOTHROW
293 {
294   return l4_vcon_send_u(vcon, buf, size, l4_utcb());
295 }
296 
297 L4_INLINE long
l4_vcon_write_u(l4_cap_idx_t vcon,char const * buf,unsigned size,l4_utcb_t * utcb)298 l4_vcon_write_u(l4_cap_idx_t vcon, char const *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW
299 {
300   l4_msgtag_t t;
301 
302   if (size > L4_VCON_WRITE_SIZE)
303     size = L4_VCON_WRITE_SIZE;
304 
305   t = l4_vcon_send_u(vcon, buf, size, utcb);
306   if (l4_msgtag_has_error(t))
307     return l4_error(t);
308 
309   return (long) size;
310 }
311 
312 L4_INLINE long
l4_vcon_write(l4_cap_idx_t vcon,char const * buf,unsigned size)313 l4_vcon_write(l4_cap_idx_t vcon, char const *buf, unsigned size) L4_NOTHROW
314 {
315   return l4_vcon_write_u(vcon, buf, size, l4_utcb());
316 }
317 
318 L4_INLINE int
l4_vcon_read_with_flags_u(l4_cap_idx_t vcon,char * buf,unsigned size,l4_utcb_t * utcb)319 l4_vcon_read_with_flags_u(l4_cap_idx_t vcon, char *buf, unsigned size,
320                           l4_utcb_t *utcb) L4_NOTHROW
321 {
322   int ret;
323   unsigned r;
324   l4_msg_regs_t *mr;
325 
326   mr = l4_utcb_mr_u(utcb);
327   mr->mr[0] = (size << 16) | L4_VCON_READ_OP;
328 
329   ret = l4_error_u(l4_ipc_call(vcon, utcb,
330                                l4_msgtag(L4_PROTO_LOG, 1, 0, 0),
331                                L4_IPC_NEVER),
332                    utcb);
333   if (ret < 0)
334     return ret;
335 
336   r = mr->mr[0] & L4_VCON_READ_SIZE_MASK;
337 
338   if (!(mr->mr[0] & L4_VCON_READ_STAT_DONE)) // !eof
339     ret = size + 1;
340   else if (r < size)
341     ret = r;
342   else
343     ret = size;
344 
345   if (L4_LIKELY(buf != NULL))
346     __builtin_memcpy(buf, &mr->mr[1], r < size ? r : size);
347 
348   return ret | (mr->mr[0] & ~(L4_VCON_READ_STAT_DONE | L4_VCON_READ_SIZE_MASK));
349 }
350 
351 L4_INLINE int
l4_vcon_read_with_flags(l4_cap_idx_t vcon,char * buf,unsigned size)352 l4_vcon_read_with_flags(l4_cap_idx_t vcon, char *buf, unsigned size) L4_NOTHROW
353 {
354   return l4_vcon_read_with_flags_u(vcon, buf, size, l4_utcb());
355 }
356 
357 L4_INLINE int
l4_vcon_read_u(l4_cap_idx_t vcon,char * buf,unsigned size,l4_utcb_t * utcb)358 l4_vcon_read_u(l4_cap_idx_t vcon, char *buf, unsigned size, l4_utcb_t *utcb) L4_NOTHROW
359 {
360   int r = l4_vcon_read_with_flags_u(vcon, buf, size, utcb);
361   if (r < 0)
362     return r;
363 
364   return r & L4_VCON_READ_SIZE_MASK;
365 }
366 
367 L4_INLINE int
l4_vcon_read(l4_cap_idx_t vcon,char * buf,unsigned size)368 l4_vcon_read(l4_cap_idx_t vcon, char *buf, unsigned size) L4_NOTHROW
369 {
370   return l4_vcon_read_u(vcon, buf, size, l4_utcb());
371 }
372 
373 L4_INLINE l4_msgtag_t
l4_vcon_set_attr_u(l4_cap_idx_t vcon,l4_vcon_attr_t const * attr,l4_utcb_t * utcb)374 l4_vcon_set_attr_u(l4_cap_idx_t vcon, l4_vcon_attr_t const *attr,
375                    l4_utcb_t *utcb) L4_NOTHROW
376 {
377   l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
378 
379   mr->mr[0] = L4_VCON_SET_ATTR_OP;
380   __builtin_memcpy(&mr->mr[1], attr, sizeof(*attr));
381 
382   return l4_ipc_call(vcon, utcb,
383                      l4_msgtag(L4_PROTO_LOG, 4, 0, 0),
384                      L4_IPC_NEVER);
385 }
386 
387 L4_INLINE l4_msgtag_t
l4_vcon_set_attr(l4_cap_idx_t vcon,l4_vcon_attr_t const * attr)388 l4_vcon_set_attr(l4_cap_idx_t vcon, l4_vcon_attr_t const *attr) L4_NOTHROW
389 {
390   return l4_vcon_set_attr_u(vcon, attr, l4_utcb());
391 }
392 
393 L4_INLINE l4_msgtag_t
l4_vcon_get_attr_u(l4_cap_idx_t vcon,l4_vcon_attr_t * attr,l4_utcb_t * utcb)394 l4_vcon_get_attr_u(l4_cap_idx_t vcon, l4_vcon_attr_t *attr,
395                    l4_utcb_t *utcb) L4_NOTHROW
396 {
397   l4_msgtag_t res;
398   l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
399 
400   mr->mr[0] = L4_VCON_GET_ATTR_OP;
401 
402   res = l4_ipc_call(vcon, utcb,
403                     l4_msgtag(L4_PROTO_LOG, 1, 0, 0),
404                     L4_IPC_NEVER);
405   if (l4_error_u(res, utcb) >= 0)
406     __builtin_memcpy(attr, &mr->mr[1], sizeof(*attr));
407 
408   return res;
409 }
410 
411 L4_INLINE l4_msgtag_t
l4_vcon_get_attr(l4_cap_idx_t vcon,l4_vcon_attr_t * attr)412 l4_vcon_get_attr(l4_cap_idx_t vcon, l4_vcon_attr_t *attr) L4_NOTHROW
413 {
414   return l4_vcon_get_attr_u(vcon, attr, l4_utcb());
415 }
416