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