1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "console.h"
33 #include "fcntl.h"
34 #include "sys/ioctl.h"
35 #ifdef LOSCFG_FILE_MODE
36 #include "stdarg.h"
37 #endif
38 #include "unistd.h"
39 #include "securec.h"
40 #ifdef LOSCFG_SHELL_DMESG
41 #include "dmesg_pri.h"
42 #endif
43 #ifdef LOSCFG_SHELL
44 #include "shcmd.h"
45 #include "shell_pri.h"
46 #endif
47 #include "los_exc_pri.h"
48 #include "los_process_pri.h"
49 #include "los_sched_pri.h"
50 #include "user_copy.h"
51 #include "fs/driver.h"
52
53 #define EACH_CHAR 1
54 #define UART_IOC_MAGIC 'u'
55 #define UART_CFG_ATTR _IOW(UART_IOC_MAGIC, 5, int)
56 #define UART_CFG_PRIVATE _IOW(UART_IOC_MAGIC, 6, int)
57 /* Inter-module variable */
58 extern UINT32 g_uart_fputc_en;
59 STATIC UINT32 ConsoleSendTask(UINTPTR param);
60
61 STATIC UINT8 g_taskConsoleIDArray[LOSCFG_BASE_CORE_TSK_LIMIT];
62 STATIC SPIN_LOCK_INIT(g_consoleSpin);
63 STATIC SPIN_LOCK_INIT(g_consoleWriteSpinLock);
64
65 #define SHELL_ENTRYID_INVALID 0xFFFFFFFF
66 #define SHELL_TASK_PRIORITY 9
67 #define CONSOLE_CIRBUF_EVENT 0x02U
68 #define CONSOLE_SEND_TASK_EXIT 0x04U
69 #define CONSOLE_SEND_TASK_RUNNING 0x10U
70
71 #define SHELL_ENTRY_NAME "ShellEntry"
72 #define SHELL_ENTRY_NAME_LEN 10
73
74 CONSOLE_CB *g_console[CONSOLE_NUM];
75 #define MIN(a, b) ((a) < (b) ? (a) : (b))
76
77 /*
78 * acquire uart driver function and filep of /dev/console,
79 * then store uart driver function in *filepOps
80 * and store filep of /dev/console in *privFilep.
81 */
GetFilepOps(const struct file * filep,struct file ** privFilep,const struct file_operations_vfs ** filepOps)82 INT32 GetFilepOps(const struct file *filep, struct file **privFilep, const struct file_operations_vfs **filepOps)
83 {
84 INT32 ret;
85
86 if ((filep == NULL) || (filep->f_vnode == NULL) || (filep->f_vnode->data == NULL)) {
87 ret = EINVAL;
88 goto ERROUT;
89 }
90
91 /* to find console device's filep(now it is *privFilep) through i_private */
92 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
93 *privFilep = (struct file *)drv->priv;
94 if (((*privFilep)->f_vnode == NULL) || ((*privFilep)->f_vnode->data == NULL)) {
95 ret = EINVAL;
96 goto ERROUT;
97 }
98
99 /* to find uart driver operation function through u.i_opss */
100
101 drv = (struct drv_data *)(*privFilep)->f_vnode->data;
102
103 *filepOps = (const struct file_operations_vfs *)drv->ops;
104
105 return ENOERR;
106 ERROUT:
107 set_errno(ret);
108 return VFS_ERROR;
109 }
110
ConsoleTcGetAttr(INT32 fd,struct termios * termios)111 INT32 ConsoleTcGetAttr(INT32 fd, struct termios *termios)
112 {
113 struct file *filep = NULL;
114 CONSOLE_CB *consoleCB = NULL;
115
116 INT32 ret = fs_getfilep(fd, &filep);
117 if (ret < 0) {
118 return -EPERM;
119 }
120
121 consoleCB = (CONSOLE_CB *)filep->f_priv;
122 if (consoleCB == NULL) {
123 return -EFAULT;
124 }
125
126 (VOID)memcpy_s(termios, sizeof(struct termios), &consoleCB->consoleTermios, sizeof(struct termios));
127 return LOS_OK;
128 }
129
ConsoleTcSetAttr(INT32 fd,INT32 actions,const struct termios * termios)130 INT32 ConsoleTcSetAttr(INT32 fd, INT32 actions, const struct termios *termios)
131 {
132 struct file *filep = NULL;
133 CONSOLE_CB *consoleCB = NULL;
134
135 (VOID)actions;
136
137 INT32 ret = fs_getfilep(fd, &filep);
138 if (ret < 0) {
139 return -EPERM;
140 }
141
142 consoleCB = (CONSOLE_CB *)filep->f_priv;
143 if (consoleCB == NULL) {
144 return -EFAULT;
145 }
146
147 (VOID)memcpy_s(&consoleCB->consoleTermios, sizeof(struct termios), termios, sizeof(struct termios));
148 return LOS_OK;
149 }
150
ConsoleRefcountGet(const CONSOLE_CB * consoleCB)151 STATIC UINT32 ConsoleRefcountGet(const CONSOLE_CB *consoleCB)
152 {
153 return consoleCB->refCount;
154 }
155
ConsoleRefcountSet(CONSOLE_CB * consoleCB,BOOL flag)156 STATIC VOID ConsoleRefcountSet(CONSOLE_CB *consoleCB, BOOL flag)
157 {
158 (consoleCB->refCount) += flag ? 1 : -1;
159 }
160
IsConsoleOccupied(const CONSOLE_CB * consoleCB)161 BOOL IsConsoleOccupied(const CONSOLE_CB *consoleCB)
162 {
163 return ConsoleRefcountGet(consoleCB);
164 }
165
ConsoleCtrlCaptureLine(CONSOLE_CB * consoleCB)166 STATIC INT32 ConsoleCtrlCaptureLine(CONSOLE_CB *consoleCB)
167 {
168 struct termios consoleTermios = {0};
169 UINT32 intSave;
170
171 LOS_SpinLockSave(&g_consoleSpin, &intSave);
172 (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
173 consoleTermios.c_lflag |= ICANON | ECHO;
174 (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
175 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
176
177 return LOS_OK;
178 }
179
ConsoleCtrlCaptureChar(CONSOLE_CB * consoleCB)180 STATIC INT32 ConsoleCtrlCaptureChar(CONSOLE_CB *consoleCB)
181 {
182 struct termios consoleTermios = {0};
183 UINT32 intSave;
184
185 LOS_SpinLockSave(&g_consoleSpin, &intSave);
186 (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
187 consoleTermios.c_lflag &= ~(ICANON | ECHO);
188 (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
189 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
190
191 return LOS_OK;
192 }
193
ConsoleCtrlRightsCapture(CONSOLE_CB * consoleCB)194 STATIC INT32 ConsoleCtrlRightsCapture(CONSOLE_CB *consoleCB)
195 {
196 (VOID)LOS_SemPend(consoleCB->consoleSem, LOS_WAIT_FOREVER);
197 if ((ConsoleRefcountGet(consoleCB) == 0) &&
198 (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) {
199 /* not 0:indicate that shellentry is in uart_read, suspend shellentry task directly */
200 (VOID)LOS_TaskSuspend(consoleCB->shellEntryId);
201 }
202 ConsoleRefcountSet(consoleCB, TRUE);
203 return LOS_OK;
204 }
205
ConsoleCtrlRightsRelease(CONSOLE_CB * consoleCB)206 STATIC INT32 ConsoleCtrlRightsRelease(CONSOLE_CB *consoleCB)
207 {
208 if (ConsoleRefcountGet(consoleCB) == 0) {
209 PRINT_ERR("console is free\n");
210 (VOID)LOS_SemPost(consoleCB->consoleSem);
211 return LOS_NOK;
212 } else {
213 ConsoleRefcountSet(consoleCB, FALSE);
214 if ((ConsoleRefcountGet(consoleCB) == 0) &&
215 (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) {
216 (VOID)LOS_TaskResume(consoleCB->shellEntryId);
217 }
218 }
219 (VOID)LOS_SemPost(consoleCB->consoleSem);
220 return LOS_OK;
221 }
222
OsGetConsoleByDevice(const CHAR * deviceName)223 STATIC CONSOLE_CB *OsGetConsoleByDevice(const CHAR *deviceName)
224 {
225 INT32 ret;
226 struct Vnode *vnode = NULL;
227
228 VnodeHold();
229 ret = VnodeLookup(deviceName, &vnode, 0);
230 VnodeDrop();
231 if (ret < 0) {
232 set_errno(EACCES);
233 return NULL;
234 }
235
236 if (g_console[CONSOLE_SERIAL - 1]->devVnode == vnode) {
237 return g_console[CONSOLE_SERIAL - 1];
238 } else if (g_console[CONSOLE_TELNET - 1]->devVnode == vnode) {
239 return g_console[CONSOLE_TELNET - 1];
240 } else {
241 set_errno(ENOENT);
242 return NULL;
243 }
244 }
245
OsGetConsoleID(const CHAR * deviceName)246 STATIC INT32 OsGetConsoleID(const CHAR *deviceName)
247 {
248 if ((deviceName != NULL) &&
249 (strlen(deviceName) == strlen(SERIAL)) &&
250 (!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
251 return CONSOLE_SERIAL;
252 }
253 #ifdef LOSCFG_NET_TELNET
254 else if ((deviceName != NULL) &&
255 (strlen(deviceName) == strlen(TELNET)) &&
256 (!strncmp(deviceName, TELNET, strlen(TELNET)))) {
257 return CONSOLE_TELNET;
258 }
259 #endif
260 return -1;
261 }
262
OsConsoleFullpathToID(const CHAR * fullpath)263 STATIC INT32 OsConsoleFullpathToID(const CHAR *fullpath)
264 {
265 #define CONSOLE_SERIAL_1 "/dev/console1"
266 #define CONSOLE_TELNET_2 "/dev/console2"
267
268 size_t len;
269
270 if (fullpath == NULL) {
271 return -1;
272 }
273
274 len = strlen(fullpath);
275 if ((len == strlen(CONSOLE_SERIAL_1)) &&
276 (!strncmp(fullpath, CONSOLE_SERIAL_1, strlen(CONSOLE_SERIAL_1)))) {
277 return CONSOLE_SERIAL;
278 }
279 #ifdef LOSCFG_NET_TELNET
280 else if ((len == strlen(CONSOLE_TELNET_2)) &&
281 (!strncmp(fullpath, CONSOLE_TELNET_2, strlen(CONSOLE_TELNET_2)))) {
282 return CONSOLE_TELNET;
283 }
284 #endif
285 return -1;
286 }
287
ConsoleFifoEmpty(const CONSOLE_CB * console)288 STATIC BOOL ConsoleFifoEmpty(const CONSOLE_CB *console)
289 {
290 return console->fifoOut == console->fifoIn;
291 }
292
ConsoleFifoClearup(CONSOLE_CB * console)293 STATIC VOID ConsoleFifoClearup(CONSOLE_CB *console)
294 {
295 console->fifoOut = 0;
296 console->fifoIn = 0;
297 (VOID)memset_s(console->fifo, CONSOLE_FIFO_SIZE, 0, CONSOLE_FIFO_SIZE);
298 }
299
ConsoleFifoLenUpdate(CONSOLE_CB * console)300 STATIC VOID ConsoleFifoLenUpdate(CONSOLE_CB *console)
301 {
302 console->currentLen = console->fifoIn - console->fifoOut;
303 }
304
ConsoleReadFifo(CHAR * buffer,CONSOLE_CB * console,size_t bufLen)305 STATIC INT32 ConsoleReadFifo(CHAR *buffer, CONSOLE_CB *console, size_t bufLen)
306 {
307 INT32 ret;
308 UINT32 readNum;
309
310 readNum = MIN(bufLen, console->currentLen);
311 ret = memcpy_s(buffer, bufLen, console->fifo + console->fifoOut, readNum);
312 if (ret != EOK) {
313 PRINTK("%s,%d memcpy_s failed\n", __FUNCTION__, __LINE__);
314 return -1;
315 }
316 console->fifoOut += readNum;
317 if (ConsoleFifoEmpty(console)) {
318 ConsoleFifoClearup(console);
319 }
320 ConsoleFifoLenUpdate(console);
321 return (INT32)readNum;
322 }
323
FilepOpen(struct file * filep,const struct file_operations_vfs * fops)324 INT32 FilepOpen(struct file *filep, const struct file_operations_vfs *fops)
325 {
326 INT32 ret;
327 if (fops->open == NULL) {
328 return -EFAULT;
329 }
330
331 /*
332 * adopt uart open function to open filep (filep is
333 * corresponding to filep of /dev/console)
334 */
335 ret = fops->open(filep);
336 return (ret < 0) ? -EPERM : ret;
337 }
338
UserEndOfRead(CONSOLE_CB * consoleCB,struct file * filep,const struct file_operations_vfs * fops)339 STATIC INLINE VOID UserEndOfRead(CONSOLE_CB *consoleCB, struct file *filep,
340 const struct file_operations_vfs *fops)
341 {
342 CHAR ch;
343 if (consoleCB->consoleTermios.c_lflag & ECHO) {
344 ch = '\r';
345 (VOID)fops->write(filep, &ch, 1);
346 }
347 consoleCB->fifo[consoleCB->fifoIn++] = '\n';
348 consoleCB->fifo[consoleCB->fifoIn] = '\0';
349 consoleCB->currentLen = consoleCB->fifoIn;
350 }
351
352 enum {
353 STAT_NORMAL_KEY,
354 STAT_ESC_KEY,
355 STAT_MULTI_KEY
356 };
357
UserShellCheckUDRL(const CHAR ch,INT32 * lastTokenType)358 STATIC INT32 UserShellCheckUDRL(const CHAR ch, INT32 *lastTokenType)
359 {
360 INT32 ret = LOS_OK;
361 if (ch == 0x1b) { /* 0x1b: ESC */
362 *lastTokenType = STAT_ESC_KEY;
363 return ret;
364 } else if (ch == 0x5b) { /* 0x5b: first Key combination */
365 if (*lastTokenType == STAT_ESC_KEY) {
366 *lastTokenType = STAT_MULTI_KEY;
367 return ret;
368 }
369 } else if (ch == 0x41) { /* up */
370 if (*lastTokenType == STAT_MULTI_KEY) {
371 *lastTokenType = STAT_NORMAL_KEY;
372 return ret;
373 }
374 } else if (ch == 0x42) { /* down */
375 if (*lastTokenType == STAT_MULTI_KEY) {
376 *lastTokenType = STAT_NORMAL_KEY;
377 return ret;
378 }
379 } else if (ch == 0x43) { /* right */
380 if (*lastTokenType == STAT_MULTI_KEY) {
381 *lastTokenType = STAT_NORMAL_KEY;
382 return ret;
383 }
384 } else if (ch == 0x44) { /* left */
385 if (*lastTokenType == STAT_MULTI_KEY) {
386 *lastTokenType = STAT_NORMAL_KEY;
387 return ret;
388 }
389 }
390 return LOS_NOK;
391 }
392
IsNeedContinue(CONSOLE_CB * consoleCB,char ch,INT32 * lastTokenType)393 STATIC INT32 IsNeedContinue(CONSOLE_CB *consoleCB, char ch, INT32 *lastTokenType)
394 {
395 if (((ch == '\b') && (consoleCB->consoleTermios.c_lflag & ECHO) && (ConsoleFifoEmpty(consoleCB))) ||
396 (UserShellCheckUDRL(ch, lastTokenType) == LOS_OK)) { /* parse the up/down/right/left key */
397 return LOS_NOK;
398 }
399
400 return LOS_OK;
401 }
402
EchoToTerminal(CONSOLE_CB * consoleCB,struct file * filep,const struct file_operations_vfs * fops,char ch)403 STATIC VOID EchoToTerminal(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops, char ch)
404 {
405 if (consoleCB->consoleTermios.c_lflag & ECHO) {
406 if (ch == '\b') {
407 (VOID)fops->write(filep, "\b \b", 3); // 3: length of "\b \b"
408 } else {
409 (VOID)fops->write(filep, &ch, EACH_CHAR);
410 }
411 }
412 }
413
StoreReadChar(CONSOLE_CB * consoleCB,char ch,INT32 readcount)414 STATIC VOID StoreReadChar(CONSOLE_CB *consoleCB, char ch, INT32 readcount)
415 {
416 /* 3, store read char len need to minus \b */
417 if ((readcount == EACH_CHAR) && (consoleCB->fifoIn <= (CONSOLE_FIFO_SIZE - 3))) {
418 if (ch == '\b') {
419 if (!ConsoleFifoEmpty(consoleCB)) {
420 consoleCB->fifo[--consoleCB->fifoIn] = '\0';
421 }
422 } else {
423 consoleCB->fifo[consoleCB->fifoIn] = (UINT8)ch;
424 consoleCB->fifoIn++;
425 }
426 }
427 }
428
KillPgrp(UINT16 consoleId)429 VOID KillPgrp(UINT16 consoleId)
430 {
431 if ((consoleId > CONSOLE_NUM) || (consoleId <= 0)) {
432 return;
433 }
434
435 CONSOLE_CB *consoleCB = g_console[consoleId - 1];
436 /* the default of consoleCB->pgrpId is -1, may not be set yet, avoid killing all processes */
437 if (consoleCB->pgrpId < 0) {
438 return;
439 }
440 (VOID)OsKillLock(consoleCB->pgrpId, SIGINT);
441 }
442
UserFilepRead(CONSOLE_CB * consoleCB,struct file * filep,const struct file_operations_vfs * fops,CHAR * buffer,size_t bufLen)443 STATIC INT32 UserFilepRead(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops,
444 CHAR *buffer, size_t bufLen)
445 {
446 INT32 ret;
447 INT32 needreturn = LOS_NOK;
448 CHAR ch;
449 INT32 lastTokenType = STAT_NORMAL_KEY;
450
451 if (fops->read == NULL) {
452 return -EFAULT;
453 }
454
455 /* Non-ICANON mode */
456 if ((consoleCB->consoleTermios.c_lflag & ICANON) == 0) {
457 ret = fops->read(filep, buffer, bufLen);
458 return (ret < 0) ? -EPERM : ret;
459 }
460 /* ICANON mode: store data to console buffer, read data and stored data into console fifo */
461 if (consoleCB->currentLen == 0) {
462 while (1) {
463 ret = fops->read(filep, &ch, EACH_CHAR);
464 if (ret <= 0) {
465 return ret;
466 }
467
468 if (IsNeedContinue(consoleCB, ch, &lastTokenType))
469 continue;
470
471 switch (ch) {
472 case '\r':
473 ch = '\n';
474 case '\n':
475 EchoToTerminal(consoleCB, filep, fops, ch);
476 UserEndOfRead(consoleCB, filep, fops);
477 ret = ConsoleReadFifo(buffer, consoleCB, bufLen);
478
479 needreturn = LOS_OK;
480 break;
481 case '\b':
482 default:
483 EchoToTerminal(consoleCB, filep, fops, ch);
484 StoreReadChar(consoleCB, ch, ret);
485 break;
486 }
487
488 if (needreturn == LOS_OK)
489 break;
490 }
491 } else {
492 /* if data is already in console fifo, we return them immediately */
493 ret = ConsoleReadFifo(buffer, consoleCB, bufLen);
494 }
495
496 return ret;
497 }
498
FilepRead(struct file * filep,const struct file_operations_vfs * fops,CHAR * buffer,size_t bufLen)499 INT32 FilepRead(struct file *filep, const struct file_operations_vfs *fops, CHAR *buffer, size_t bufLen)
500 {
501 INT32 ret;
502 if (fops->read == NULL) {
503 return -EFAULT;
504 }
505 /*
506 * adopt uart read function to read data from filep
507 * and write data to buffer (filep is
508 * corresponding to filep of /dev/console)
509 */
510 ret = fops->read(filep, buffer, bufLen);
511 return (ret < 0) ? -EPERM : ret;
512 }
513
FilepWrite(struct file * filep,const struct file_operations_vfs * fops,const CHAR * buffer,size_t bufLen)514 INT32 FilepWrite(struct file *filep, const struct file_operations_vfs *fops, const CHAR *buffer, size_t bufLen)
515 {
516 INT32 ret;
517 if (fops->write == NULL) {
518 return -EFAULT;
519 }
520
521 ret = fops->write(filep, buffer, bufLen);
522 return (ret < 0) ? -EPERM : ret;
523 }
524
FilepClose(struct file * filep,const struct file_operations_vfs * fops)525 INT32 FilepClose(struct file *filep, const struct file_operations_vfs *fops)
526 {
527 INT32 ret;
528 if ((fops == NULL) || (fops->close == NULL)) {
529 return -EFAULT;
530 }
531
532 /*
533 * adopt uart close function to open filep (filep is
534 * corresponding to filep of /dev/console)
535 */
536 ret = fops->close(filep);
537 return ret < 0 ? -EPERM : ret;
538 }
539
FilepIoctl(struct file * filep,const struct file_operations_vfs * fops,INT32 cmd,unsigned long arg)540 INT32 FilepIoctl(struct file *filep, const struct file_operations_vfs *fops, INT32 cmd, unsigned long arg)
541 {
542 INT32 ret;
543 if (fops->ioctl == NULL) {
544 return -EFAULT;
545 }
546
547 ret = fops->ioctl(filep, cmd, arg);
548 return (ret < 0) ? -EPERM : ret;
549 }
550
FilepPoll(struct file * filep,const struct file_operations_vfs * fops,poll_table * fds)551 INT32 FilepPoll(struct file *filep, const struct file_operations_vfs *fops, poll_table *fds)
552 {
553 INT32 ret;
554 if (fops->poll == NULL) {
555 return -EFAULT;
556 }
557
558 /*
559 * adopt uart poll function to poll filep (filep is
560 * corresponding to filep of /dev/serial)
561 */
562 ret = fops->poll(filep, fds);
563 return (ret < 0) ? -EPERM : ret;
564 }
565
ConsoleOpen(struct file * filep)566 STATIC INT32 ConsoleOpen(struct file *filep)
567 {
568 INT32 ret;
569 UINT32 consoleID;
570 struct file *privFilep = NULL;
571 const struct file_operations_vfs *fileOps = NULL;
572
573 consoleID = (UINT32)OsConsoleFullpathToID(filep->f_path);
574 if (consoleID == (UINT32)-1) {
575 ret = EPERM;
576 goto ERROUT;
577 }
578 filep->f_priv = g_console[consoleID - 1];
579
580 ret = GetFilepOps(filep, &privFilep, &fileOps);
581 if (ret != ENOERR) {
582 ret = EINVAL;
583 goto ERROUT;
584 }
585 ret = FilepOpen(privFilep, fileOps);
586 if (ret < 0) {
587 ret = EPERM;
588 goto ERROUT;
589 }
590 return ENOERR;
591
592 ERROUT:
593 set_errno(ret);
594 return VFS_ERROR;
595 }
596
ConsoleClose(struct file * filep)597 STATIC INT32 ConsoleClose(struct file *filep)
598 {
599 INT32 ret;
600 struct file *privFilep = NULL;
601 const struct file_operations_vfs *fileOps = NULL;
602
603 ret = GetFilepOps(filep, &privFilep, &fileOps);
604 if (ret != ENOERR) {
605 ret = EINVAL;
606 goto ERROUT;
607 }
608 ret = FilepClose(privFilep, fileOps);
609 if (ret < 0) {
610 ret = EPERM;
611 goto ERROUT;
612 }
613
614 return ENOERR;
615
616 ERROUT:
617 set_errno(ret);
618 return VFS_ERROR;
619 }
620
DoRead(CONSOLE_CB * consoleCB,CHAR * buffer,size_t bufLen,struct file * privFilep,const struct file_operations_vfs * fileOps)621 STATIC ssize_t DoRead(CONSOLE_CB *consoleCB, CHAR *buffer, size_t bufLen,
622 struct file *privFilep,
623 const struct file_operations_vfs *fileOps)
624 {
625 INT32 ret;
626
627 #ifdef LOSCFG_SHELL
628 if (OsCurrTaskGet()->taskID == consoleCB->shellEntryId) {
629 ret = FilepRead(privFilep, fileOps, buffer, bufLen);
630 } else {
631 #endif
632 (VOID)ConsoleCtrlRightsCapture(consoleCB);
633 ret = UserFilepRead(consoleCB, privFilep, fileOps, buffer, bufLen);
634 (VOID)ConsoleCtrlRightsRelease(consoleCB);
635 #ifdef LOSCFG_SHELL
636 }
637 #endif
638
639 return ret;
640 }
641
ConsoleRead(struct file * filep,CHAR * buffer,size_t bufLen)642 STATIC ssize_t ConsoleRead(struct file *filep, CHAR *buffer, size_t bufLen)
643 {
644 INT32 ret;
645 struct file *privFilep = NULL;
646 CONSOLE_CB *consoleCB = NULL;
647 CHAR *sbuffer = NULL;
648 BOOL userBuf = FALSE;
649 const struct file_operations_vfs *fileOps = NULL;
650
651 if ((buffer == NULL) || (bufLen == 0)) {
652 ret = EINVAL;
653 goto ERROUT;
654 }
655
656 if (bufLen > CONSOLE_FIFO_SIZE) {
657 bufLen = CONSOLE_FIFO_SIZE;
658 }
659
660 userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);
661 ret = GetFilepOps(filep, &privFilep, &fileOps);
662 if (ret != ENOERR) {
663 ret = -EINVAL;
664 goto ERROUT;
665 }
666 consoleCB = (CONSOLE_CB *)filep->f_priv;
667 if (consoleCB == NULL) {
668 consoleCB = OsGetConsoleByTaskID(OsCurrTaskGet()->taskID);
669 if (consoleCB == NULL) {
670 return -EFAULT;
671 }
672 }
673
674 /*
675 * shell task use FilepRead function to get data,
676 * user task use UserFilepRead to get data
677 */
678 sbuffer = userBuf ? LOS_MemAlloc(m_aucSysMem0, bufLen) : buffer;
679 if (sbuffer == NULL) {
680 ret = -ENOMEM;
681 goto ERROUT;
682 }
683
684 ret = DoRead(consoleCB, sbuffer, bufLen, privFilep, fileOps);
685 if (ret < 0) {
686 goto ERROUT;
687 }
688
689 if (userBuf) {
690 if (LOS_ArchCopyToUser(buffer, sbuffer, bufLen) != 0) {
691 ret = -EFAULT;
692 goto ERROUT;
693 }
694
695 LOS_MemFree(m_aucSysMem0, sbuffer);
696 }
697
698 return ret;
699
700 ERROUT:
701 if ((userBuf) && (sbuffer != NULL)) {
702 LOS_MemFree(m_aucSysMem0, sbuffer);
703 }
704 set_errno(-ret);
705 return VFS_ERROR;
706 }
707
DoWrite(CirBufSendCB * cirBufSendCB,CHAR * buffer,size_t bufLen)708 STATIC ssize_t DoWrite(CirBufSendCB *cirBufSendCB, CHAR *buffer, size_t bufLen)
709 {
710 INT32 cnt;
711 size_t written = 0;
712 UINT32 intSave;
713
714 #ifdef LOSCFG_SHELL_DMESG
715 (VOID)OsLogMemcpyRecord(buffer, bufLen);
716 if (OsCheckConsoleLock()) {
717 return 0;
718 }
719 #endif
720
721 LOS_SpinLockSave(&g_consoleWriteSpinLock, &intSave);
722 while (written < (INT32)bufLen) {
723 /* Transform for CR/LR mode */
724 if ((buffer[written] == '\n') || (buffer[written] == '\r')) {
725 (VOID)LOS_CirBufWrite(&cirBufSendCB->cirBufCB, "\r", 1);
726 }
727
728 cnt = LOS_CirBufWrite(&cirBufSendCB->cirBufCB, &buffer[written], 1);
729 if (cnt <= 0) {
730 break;
731 }
732 written += cnt;
733 }
734 LOS_SpinUnlockRestore(&g_consoleWriteSpinLock, intSave);
735
736 /* Log is cached but not printed when a system exception occurs */
737 if (OsGetSystemStatus() == OS_SYSTEM_NORMAL) {
738 (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);
739 }
740
741 return written;
742 }
743
ConsoleWrite(struct file * filep,const CHAR * buffer,size_t bufLen)744 STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLen)
745 {
746 INT32 ret;
747 CHAR *sbuffer = NULL;
748 BOOL userBuf = FALSE;
749 CirBufSendCB *cirBufSendCB = NULL;
750 struct file *privFilep = NULL;
751 const struct file_operations_vfs *fileOps = NULL;
752
753 if ((buffer == NULL) || (bufLen == 0)) {
754 ret = EINVAL;
755 goto ERROUT;
756 }
757
758 if (bufLen > CONSOLE_FIFO_SIZE) {
759 bufLen = CONSOLE_FIFO_SIZE;
760 }
761
762 userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);
763
764 ret = GetFilepOps(filep, &privFilep, &fileOps);
765 if ((ret != ENOERR) || (fileOps->write == NULL) || (filep->f_priv == NULL)) {
766 ret = EINVAL;
767 goto ERROUT;
768 }
769 cirBufSendCB = ((CONSOLE_CB *)filep->f_priv)->cirBufSendCB;
770
771 /*
772 * adopt uart open function to read data from buffer
773 * and write data to filep (filep is
774 * corresponding to filep of /dev/console)
775 */
776 sbuffer = userBuf ? LOS_MemAlloc(m_aucSysMem0, bufLen) : (CHAR *)buffer;
777 if (sbuffer == NULL) {
778 ret = ENOMEM;
779 goto ERROUT;
780 }
781
782 if (userBuf && (LOS_ArchCopyFromUser(sbuffer, buffer, bufLen) != 0)) {
783 ret = EFAULT;
784 goto ERROUT;
785 }
786 ret = DoWrite(cirBufSendCB, sbuffer, bufLen);
787
788 if (userBuf) {
789 LOS_MemFree(m_aucSysMem0, sbuffer);
790 }
791
792 return ret;
793
794 ERROUT:
795 if (userBuf && sbuffer != NULL) {
796 LOS_MemFree(m_aucSysMem0, sbuffer);
797 }
798
799 set_errno(ret);
800 return VFS_ERROR;
801 }
802
ConsoleSetSW(CONSOLE_CB * consoleCB,unsigned long arg)803 STATIC INT32 ConsoleSetSW(CONSOLE_CB *consoleCB, unsigned long arg)
804 {
805 struct termios kerTermios;
806 UINT32 intSave;
807
808 if (LOS_ArchCopyFromUser(&kerTermios, (struct termios *)arg, sizeof(struct termios)) != 0) {
809 return -EFAULT;
810 }
811
812 LOS_SpinLockSave(&g_consoleSpin, &intSave);
813 (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &kerTermios);
814 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
815 return LOS_OK;
816 }
817
818 #define DEFAULT_WINDOW_SIZE_COL 80
819 #define DEFAULT_WINDOW_SIZE_ROW 24
ConsoleGetWinSize(unsigned long arg)820 STATIC INT32 ConsoleGetWinSize(unsigned long arg)
821 {
822 struct winsize kws = {
823 .ws_col = DEFAULT_WINDOW_SIZE_COL,
824 .ws_row = DEFAULT_WINDOW_SIZE_ROW
825 };
826
827 return (LOS_CopyFromKernel((VOID *)arg, sizeof(struct winsize), &kws, sizeof(struct winsize)) != 0) ?
828 -EFAULT : LOS_OK;
829 }
830
ConsoleGetTermios(unsigned long arg)831 STATIC INT32 ConsoleGetTermios(unsigned long arg)
832 {
833 struct file *filep = NULL;
834 CONSOLE_CB *consoleCB = NULL;
835
836 INT32 ret = fs_getfilep(0, &filep);
837 if (ret < 0) {
838 return -EPERM;
839 }
840
841 consoleCB = (CONSOLE_CB *)filep->f_priv;
842 if (consoleCB == NULL) {
843 return -EFAULT;
844 }
845
846 return (LOS_ArchCopyToUser((VOID *)arg, &consoleCB->consoleTermios, sizeof(struct termios)) != 0) ?
847 -EFAULT : LOS_OK;
848 }
849
ConsoleSetPgrp(CONSOLE_CB * consoleCB,unsigned long arg)850 INT32 ConsoleSetPgrp(CONSOLE_CB *consoleCB, unsigned long arg)
851 {
852 if (LOS_ArchCopyFromUser(&consoleCB->pgrpId, (INT32 *)(UINTPTR)arg, sizeof(INT32)) != 0) {
853 return -EFAULT;
854 }
855 return LOS_OK;
856 }
857
ConsoleGetPgrp(CONSOLE_CB * consoleCB,unsigned long arg)858 INT32 ConsoleGetPgrp(CONSOLE_CB *consoleCB, unsigned long arg)
859 {
860 return (LOS_ArchCopyToUser((VOID *)arg, &consoleCB->pgrpId, sizeof(INT32)) != 0) ? -EFAULT : LOS_OK;
861 }
862
ConsoleIoctl(struct file * filep,INT32 cmd,unsigned long arg)863 STATIC INT32 ConsoleIoctl(struct file *filep, INT32 cmd, unsigned long arg)
864 {
865 INT32 ret;
866 struct file *privFilep = NULL;
867 CONSOLE_CB *consoleCB = NULL;
868 const struct file_operations_vfs *fileOps = NULL;
869
870 ret = GetFilepOps(filep, &privFilep, &fileOps);
871 if (ret != ENOERR) {
872 ret = EINVAL;
873 goto ERROUT;
874 }
875
876 if (fileOps->ioctl == NULL) {
877 ret = EFAULT;
878 goto ERROUT;
879 }
880
881 consoleCB = (CONSOLE_CB *)filep->f_priv;
882 if (consoleCB == NULL) {
883 ret = EINVAL;
884 goto ERROUT;
885 }
886
887 switch (cmd) {
888 case CONSOLE_CONTROL_RIGHTS_CAPTURE:
889 ret = ConsoleCtrlRightsCapture(consoleCB);
890 break;
891 case CONSOLE_CONTROL_RIGHTS_RELEASE:
892 ret = ConsoleCtrlRightsRelease(consoleCB);
893 break;
894 case CONSOLE_CONTROL_CAPTURE_LINE:
895 ret = ConsoleCtrlCaptureLine(consoleCB);
896 break;
897 case CONSOLE_CONTROL_CAPTURE_CHAR:
898 ret = ConsoleCtrlCaptureChar(consoleCB);
899 break;
900 case CONSOLE_CONTROL_REG_USERTASK:
901 ret = ConsoleTaskReg(consoleCB->consoleID, arg);
902 break;
903 case TIOCGWINSZ:
904 ret = ConsoleGetWinSize(arg);
905 break;
906 case TCSETSW:
907 ret = ConsoleSetSW(consoleCB, arg);
908 break;
909 case TCGETS:
910 ret = ConsoleGetTermios(arg);
911 break;
912 case TIOCGPGRP:
913 ret = ConsoleGetPgrp(consoleCB, arg);
914 break;
915 case TIOCSPGRP:
916 ret = ConsoleSetPgrp(consoleCB, arg);
917 break;
918 default:
919 if ((cmd == UART_CFG_ATTR || cmd == UART_CFG_PRIVATE)
920 && !LOS_IsUserAddress(arg)) {
921 ret = EINVAL;
922 goto ERROUT;
923 }
924 ret = fileOps->ioctl(privFilep, cmd, arg);
925 break;
926 }
927
928 if (ret < 0) {
929 ret = EPERM;
930 goto ERROUT;
931 }
932
933 return ret;
934 ERROUT:
935 set_errno(ret);
936 return VFS_ERROR;
937 }
938
ConsolePoll(struct file * filep,poll_table * fds)939 STATIC INT32 ConsolePoll(struct file *filep, poll_table *fds)
940 {
941 INT32 ret;
942 struct file *privFilep = NULL;
943 const struct file_operations_vfs *fileOps = NULL;
944
945 ret = GetFilepOps(filep, &privFilep, &fileOps);
946 if (ret != ENOERR) {
947 ret = EINVAL;
948 goto ERROUT;
949 }
950
951 ret = FilepPoll(privFilep, fileOps, fds);
952 if (ret < 0) {
953 ret = EPERM;
954 goto ERROUT;
955 }
956 return ret;
957
958 ERROUT:
959 set_errno(ret);
960 return VFS_ERROR;
961 }
962
963 /* console device driver function structure */
964 STATIC const struct file_operations_vfs g_consoleDevOps = {
965 .open = ConsoleOpen, /* open */
966 .close = ConsoleClose, /* close */
967 .read = ConsoleRead, /* read */
968 .write = ConsoleWrite, /* write */
969 .seek = NULL,
970 .ioctl = ConsoleIoctl,
971 .mmap = NULL,
972 #ifndef CONFIG_DISABLE_POLL
973 .poll = ConsolePoll,
974 #endif
975 };
976
OsConsoleTermiosInit(CONSOLE_CB * consoleCB,const CHAR * deviceName)977 STATIC VOID OsConsoleTermiosInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
978 {
979 struct termios consoleTermios = {0};
980
981 if ((deviceName != NULL) &&
982 (strlen(deviceName) == strlen(SERIAL)) &&
983 (!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
984 consoleCB->isNonBlock = SetSerialBlock(consoleCB);
985
986 /* set console to have a buffer for user */
987 (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
988 consoleTermios.c_lflag |= ICANON | ECHO;
989 consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */
990 (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
991 }
992 #ifdef LOSCFG_NET_TELNET
993 else if ((deviceName != NULL) &&
994 (strlen(deviceName) == strlen(TELNET)) &&
995 (!strncmp(deviceName, TELNET, strlen(TELNET)))) {
996 consoleCB->isNonBlock = SetTelnetBlock(consoleCB);
997 /* set console to have a buffer for user */
998 (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
999 consoleTermios.c_lflag |= ICANON | ECHO;
1000 consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */
1001 (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
1002 }
1003 #endif
1004 }
1005
OsConsoleFileInit(CONSOLE_CB * consoleCB)1006 STATIC INT32 OsConsoleFileInit(CONSOLE_CB *consoleCB)
1007 {
1008 INT32 ret;
1009 struct Vnode *vnode = NULL;
1010 struct file *filep = NULL;
1011
1012 VnodeHold();
1013 ret = VnodeLookup(consoleCB->name, &vnode, 0);
1014 if (ret != LOS_OK) {
1015 ret = EACCES;
1016 goto ERROUT;
1017 }
1018
1019 filep = files_allocate(vnode, O_RDWR, 0, consoleCB, FILE_START_FD);
1020 if (filep == NULL) {
1021 ret = EMFILE;
1022 goto ERROUT;
1023 }
1024 filep->ops = (struct file_operations_vfs *)((struct drv_data *)vnode->data)->ops;
1025 consoleCB->fd = filep->fd;
1026
1027 ERROUT:
1028 VnodeDrop();
1029 return ret;
1030 }
1031
1032 /*
1033 * Initialized console control platform so that when we operate /dev/console
1034 * as if we are operating /dev/ttyS0 (uart0).
1035 */
OsConsoleDevInit(CONSOLE_CB * consoleCB,const CHAR * deviceName)1036 STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
1037 {
1038 INT32 ret;
1039 struct file *filep = NULL;
1040 struct Vnode *vnode = NULL;
1041 struct file_operations_vfs *devOps = NULL;
1042
1043 /* allocate memory for filep,in order to unchange the value of filep */
1044 filep = (struct file *)LOS_MemAlloc(m_aucSysMem0, sizeof(struct file));
1045 if (filep == NULL) {
1046 ret = ENOMEM;
1047 goto ERROUT;
1048 }
1049
1050 VnodeHold();
1051 ret = VnodeLookup(deviceName, &vnode, V_DUMMY);
1052 VnodeDrop(); // not correct, but can't fix perfectly here
1053 if (ret != LOS_OK) {
1054 ret = EACCES;
1055 PRINTK("!! can not find %s\n", consoleCB->name);
1056 goto ERROUT;
1057 }
1058
1059 consoleCB->devVnode = vnode;
1060
1061 /*
1062 * initialize the console filep which is associated with /dev/console,
1063 * assign the uart0 vnode of /dev/ttyS0 to console inod of /dev/console,
1064 * then we can operate console's filep as if we operate uart0 filep of
1065 * /dev/ttyS0.
1066 */
1067 (VOID)memset_s(filep, sizeof(struct file), 0, sizeof(struct file));
1068 filep->f_oflags = O_RDWR;
1069 filep->f_pos = 0;
1070 filep->f_vnode = vnode;
1071 filep->f_path = NULL;
1072 filep->f_priv = NULL;
1073 /*
1074 * Use filep to connect console and uart, we can find uart driver function through filep.
1075 * now we can operate /dev/console to operate /dev/ttyS0 through filep.
1076 */
1077 devOps = (struct file_operations_vfs *)((struct drv_data*)vnode->data)->ops;
1078 if (devOps != NULL && devOps->open != NULL) {
1079 (VOID)devOps->open(filep);
1080 } else {
1081 ret = ENOSYS;
1082 goto ERROUT;
1083 }
1084
1085 ret = register_driver(consoleCB->name, &g_consoleDevOps, DEFFILEMODE, filep);
1086 if (ret != LOS_OK) {
1087 goto ERROUT;
1088 }
1089
1090 return LOS_OK;
1091
1092 ERROUT:
1093 if (filep) {
1094 (VOID)LOS_MemFree(m_aucSysMem0, filep);
1095 }
1096
1097 set_errno(ret);
1098 return LOS_NOK;
1099 }
1100
OsConsoleDevDeinit(const CONSOLE_CB * consoleCB)1101 STATIC UINT32 OsConsoleDevDeinit(const CONSOLE_CB *consoleCB)
1102 {
1103 return unregister_driver(consoleCB->name);
1104 }
1105
ConsoleCirBufCreate(VOID)1106 STATIC CirBufSendCB *ConsoleCirBufCreate(VOID)
1107 {
1108 UINT32 ret;
1109 CHAR *fifo = NULL;
1110 CirBufSendCB *cirBufSendCB = NULL;
1111 CirBuf *cirBufCB = NULL;
1112
1113 cirBufSendCB = (CirBufSendCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(CirBufSendCB));
1114 if (cirBufSendCB == NULL) {
1115 return NULL;
1116 }
1117 (VOID)memset_s(cirBufSendCB, sizeof(CirBufSendCB), 0, sizeof(CirBufSendCB));
1118
1119 fifo = (CHAR *)LOS_MemAlloc(m_aucSysMem0, CONSOLE_CIRCBUF_SIZE);
1120 if (fifo == NULL) {
1121 goto ERROR_WITH_SENDCB;
1122 }
1123 (VOID)memset_s(fifo, CONSOLE_CIRCBUF_SIZE, 0, CONSOLE_CIRCBUF_SIZE);
1124
1125 cirBufCB = &cirBufSendCB->cirBufCB;
1126 ret = LOS_CirBufInit(cirBufCB, fifo, CONSOLE_CIRCBUF_SIZE);
1127 if (ret != LOS_OK) {
1128 goto ERROR_WITH_FIFO;
1129 }
1130
1131 (VOID)LOS_EventInit(&cirBufSendCB->sendEvent);
1132 return cirBufSendCB;
1133
1134 ERROR_WITH_FIFO:
1135 (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);
1136 ERROR_WITH_SENDCB:
1137 (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);
1138 return NULL;
1139 }
1140
ConsoleCirBufDelete(CirBufSendCB * cirBufSendCB)1141 STATIC VOID ConsoleCirBufDelete(CirBufSendCB *cirBufSendCB)
1142 {
1143 CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;
1144
1145 (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);
1146 LOS_CirBufDeinit(cirBufCB);
1147 (VOID)LOS_EventDestroy(&cirBufSendCB->sendEvent);
1148 (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);
1149 }
1150
OsConsoleBufInit(CONSOLE_CB * consoleCB)1151 STATIC UINT32 OsConsoleBufInit(CONSOLE_CB *consoleCB)
1152 {
1153 UINT32 ret;
1154 TSK_INIT_PARAM_S initParam = {0};
1155
1156 consoleCB->cirBufSendCB = ConsoleCirBufCreate();
1157 if (consoleCB->cirBufSendCB == NULL) {
1158 return LOS_NOK;
1159 }
1160
1161 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ConsoleSendTask;
1162 initParam.usTaskPrio = SHELL_TASK_PRIORITY;
1163 initParam.auwArgs[0] = (UINTPTR)consoleCB;
1164 initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
1165 initParam.pcName = (consoleCB->consoleID == CONSOLE_SERIAL) ? "SendToSer" : "SendToTelnet";
1166 initParam.uwResved = LOS_TASK_STATUS_DETACHED;
1167
1168 ret = LOS_TaskCreate(&consoleCB->sendTaskID, &initParam);
1169 if (ret != LOS_OK) {
1170 ConsoleCirBufDelete(consoleCB->cirBufSendCB);
1171 consoleCB->cirBufSendCB = NULL;
1172 return LOS_NOK;
1173 }
1174 (VOID)LOS_EventRead(&consoleCB->cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING,
1175 LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
1176
1177 return LOS_OK;
1178 }
1179
OsConsoleBufDeinit(CONSOLE_CB * consoleCB)1180 STATIC VOID OsConsoleBufDeinit(CONSOLE_CB *consoleCB)
1181 {
1182 CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;
1183
1184 consoleCB->cirBufSendCB = NULL;
1185 (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_EXIT);
1186 }
1187
OsConsoleCBInit(UINT32 consoleID)1188 STATIC CONSOLE_CB *OsConsoleCBInit(UINT32 consoleID)
1189 {
1190 CONSOLE_CB *consoleCB = (CONSOLE_CB *)LOS_MemAlloc((VOID *)m_aucSysMem0, sizeof(CONSOLE_CB));
1191 if (consoleCB == NULL) {
1192 return NULL;
1193 }
1194 (VOID)memset_s(consoleCB, sizeof(CONSOLE_CB), 0, sizeof(CONSOLE_CB));
1195
1196 consoleCB->consoleID = consoleID;
1197 consoleCB->pgrpId = -1;
1198 consoleCB->shellEntryId = SHELL_ENTRYID_INVALID; /* initialize shellEntryId to an invalid value */
1199 consoleCB->name = LOS_MemAlloc((VOID *)m_aucSysMem0, CONSOLE_NAMELEN);
1200 if (consoleCB->name == NULL) {
1201 PRINT_ERR("consoleCB->name malloc failed\n");
1202 (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);
1203 return NULL;
1204 }
1205 return consoleCB;
1206 }
1207
OsConsoleCBDeinit(CONSOLE_CB * consoleCB)1208 STATIC VOID OsConsoleCBDeinit(CONSOLE_CB *consoleCB)
1209 {
1210 (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB->name);
1211 consoleCB->name = NULL;
1212 (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);
1213 }
1214
OsConsoleCreate(UINT32 consoleID,const CHAR * deviceName)1215 STATIC CONSOLE_CB *OsConsoleCreate(UINT32 consoleID, const CHAR *deviceName)
1216 {
1217 INT32 ret;
1218 CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);
1219 if (consoleCB == NULL) {
1220 PRINT_ERR("console malloc error.\n");
1221 return NULL;
1222 }
1223
1224 ret = snprintf_s(consoleCB->name, CONSOLE_NAMELEN, CONSOLE_NAMELEN - 1,
1225 "%s%u", CONSOLE, consoleCB->consoleID);
1226 if (ret == -1) {
1227 PRINT_ERR("consoleCB->name snprintf_s failed\n");
1228 goto ERR_WITH_NAME;
1229 }
1230
1231 ret = (INT32)OsConsoleBufInit(consoleCB);
1232 if (ret != LOS_OK) {
1233 PRINT_ERR("console OsConsoleBufInit error. %d\n", ret);
1234 goto ERR_WITH_NAME;
1235 }
1236
1237 ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);
1238 if (ret != LOS_OK) {
1239 PRINT_ERR("create sem for uart failed\n");
1240 goto ERR_WITH_BUF;
1241 }
1242
1243 ret = OsConsoleDevInit(consoleCB, deviceName);
1244 if (ret != LOS_OK) {
1245 PRINT_ERR("console OsConsoleDevInit error. %d\n", ret);
1246 goto ERR_WITH_SEM;
1247 }
1248
1249 ret = OsConsoleFileInit(consoleCB);
1250 if (ret != LOS_OK) {
1251 PRINT_ERR("console OsConsoleFileInit error. %d\n", ret);
1252 goto ERR_WITH_DEV;
1253 }
1254
1255 OsConsoleTermiosInit(consoleCB, deviceName);
1256 return consoleCB;
1257
1258 ERR_WITH_DEV:
1259 ret = (INT32)OsConsoleDevDeinit(consoleCB);
1260 if (ret != LOS_OK) {
1261 PRINT_ERR("OsConsoleDevDeinit failed!\n");
1262 }
1263 ERR_WITH_SEM:
1264 (VOID)LOS_SemDelete(consoleCB->consoleSem);
1265 ERR_WITH_BUF:
1266 OsConsoleBufDeinit(consoleCB);
1267 ERR_WITH_NAME:
1268 OsConsoleCBDeinit(consoleCB);
1269 return NULL;
1270 }
1271
OsConsoleDelete(CONSOLE_CB * consoleCB)1272 STATIC UINT32 OsConsoleDelete(CONSOLE_CB *consoleCB)
1273 {
1274 UINT32 ret;
1275
1276 (VOID)files_close(consoleCB->fd);
1277 ret = OsConsoleDevDeinit(consoleCB);
1278 if (ret != LOS_OK) {
1279 PRINT_ERR("OsConsoleDevDeinit failed!\n");
1280 }
1281 OsConsoleBufDeinit((CONSOLE_CB *)consoleCB);
1282 (VOID)LOS_SemDelete(consoleCB->consoleSem);
1283 (VOID)LOS_MemFree(m_aucSysMem0, consoleCB->name);
1284 consoleCB->name = NULL;
1285 (VOID)LOS_MemFree(m_aucSysMem0, consoleCB);
1286
1287 return ret;
1288 }
1289
1290 /* Initialized system console and return stdinfd stdoutfd stderrfd */
system_console_init(const CHAR * deviceName)1291 INT32 system_console_init(const CHAR *deviceName)
1292 {
1293 #ifdef LOSCFG_SHELL
1294 UINT32 ret;
1295 #endif
1296 INT32 consoleID;
1297 UINT32 intSave;
1298 CONSOLE_CB *consoleCB = NULL;
1299
1300 consoleID = OsGetConsoleID(deviceName);
1301 if (consoleID == -1) {
1302 PRINT_ERR("device is full.\n");
1303 return VFS_ERROR;
1304 }
1305
1306 consoleCB = OsConsoleCreate((UINT32)consoleID, deviceName);
1307 if (consoleCB == NULL) {
1308 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1309 return VFS_ERROR;
1310 }
1311
1312 LOS_SpinLockSave(&g_consoleSpin, &intSave);
1313 g_console[consoleID - 1] = consoleCB;
1314 if (OsCurrTaskGet() != NULL) {
1315 g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = (UINT8)consoleID;
1316 }
1317 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
1318
1319 #ifdef LOSCFG_SHELL
1320 ret = OsShellInit(consoleID);
1321 if (ret != LOS_OK) {
1322 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1323 LOS_SpinLockSave(&g_consoleSpin, &intSave);
1324 (VOID)OsConsoleDelete(consoleCB);
1325 g_console[consoleID - 1] = NULL;
1326 if (OsCurrTaskGet() != NULL) {
1327 g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = 0;
1328 }
1329 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
1330 return VFS_ERROR;
1331 }
1332 #endif
1333
1334 return ENOERR;
1335 }
1336
system_console_deinit(const CHAR * deviceName)1337 INT32 system_console_deinit(const CHAR *deviceName)
1338 {
1339 UINT32 ret;
1340 CONSOLE_CB *consoleCB = NULL;
1341 UINT32 taskIdx;
1342 LosTaskCB *taskCB = NULL;
1343 UINT32 intSave;
1344
1345 consoleCB = OsGetConsoleByDevice(deviceName);
1346 if (consoleCB == NULL) {
1347 return VFS_ERROR;
1348 }
1349
1350 #ifdef LOSCFG_SHELL
1351 (VOID)OsShellDeinit((INT32)consoleCB->consoleID);
1352 #endif
1353
1354 LOS_SpinLockSave(&g_consoleSpin, &intSave);
1355 /* Redirect all tasks to serial as telnet was unavailable after deinitializing */
1356 for (taskIdx = 0; taskIdx < g_taskMaxNum; taskIdx++) {
1357 taskCB = ((LosTaskCB *)g_taskCBArray) + taskIdx;
1358 if (OsTaskIsUnused(taskCB)) {
1359 continue;
1360 } else {
1361 g_taskConsoleIDArray[taskCB->taskID] = CONSOLE_SERIAL;
1362 }
1363 }
1364 g_console[consoleCB->consoleID - 1] = NULL;
1365 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
1366
1367 ret = OsConsoleDelete(consoleCB);
1368 if (ret != LOS_OK) {
1369 PRINT_ERR("%s, Failed to system_console_deinit\n", __FUNCTION__);
1370 return VFS_ERROR;
1371 }
1372
1373 return ENOERR;
1374 }
1375
ConsoleEnable(VOID)1376 BOOL ConsoleEnable(VOID)
1377 {
1378 INT32 consoleID;
1379
1380 if (OsCurrTaskGet() != NULL) {
1381 consoleID = g_taskConsoleIDArray[OsCurrTaskGet()->taskID];
1382 if (g_uart_fputc_en == 0) {
1383 if ((g_console[CONSOLE_TELNET - 1] != NULL) && OsPreemptable()) {
1384 return TRUE;
1385 }
1386 }
1387
1388 if (consoleID == 0) {
1389 return FALSE;
1390 } else if ((consoleID == CONSOLE_TELNET) || (consoleID == CONSOLE_SERIAL)) {
1391 return ((OsGetSystemStatus() == OS_SYSTEM_NORMAL) && !OsPreemptable()) ? FALSE : TRUE;
1392 }
1393 #if defined (LOSCFG_DRIVERS_USB_SERIAL_GADGET) || defined (LOSCFG_DRIVERS_USB_ETH_SER_GADGET)
1394 else if ((SerialTypeGet() == SERIAL_TYPE_USBTTY_DEV) && (userial_mask_get() == 1)) {
1395 return TRUE;
1396 }
1397 #endif
1398 }
1399
1400 return FALSE;
1401 }
1402
IsShellEntryRunning(UINT32 shellEntryId)1403 BOOL IsShellEntryRunning(UINT32 shellEntryId)
1404 {
1405 LosTaskCB *taskCB = NULL;
1406 if (shellEntryId == SHELL_ENTRYID_INVALID) {
1407 return FALSE;
1408 }
1409 taskCB = OsGetTaskCB(shellEntryId);
1410 return !OsTaskIsUnused(taskCB) &&
1411 (strlen(taskCB->taskName) == SHELL_ENTRY_NAME_LEN &&
1412 strncmp(taskCB->taskName, SHELL_ENTRY_NAME, SHELL_ENTRY_NAME_LEN) == 0);
1413 }
1414
ConsoleTaskReg(INT32 consoleID,UINT32 taskID)1415 INT32 ConsoleTaskReg(INT32 consoleID, UINT32 taskID)
1416 {
1417 UINT32 intSave;
1418
1419 LOS_SpinLockSave(&g_consoleSpin, &intSave);
1420 if (!IsShellEntryRunning(g_console[consoleID - 1]->shellEntryId)) {
1421 g_console[consoleID - 1]->shellEntryId = taskID;
1422 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
1423 (VOID)OsSetCurrProcessGroupID(OsGetUserInitProcessID());
1424 return LOS_OK;
1425 }
1426 LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
1427 return (g_console[consoleID - 1]->shellEntryId == taskID) ? LOS_OK : LOS_NOK;
1428 }
1429
SetSerialNonBlock(const CONSOLE_CB * consoleCB)1430 BOOL SetSerialNonBlock(const CONSOLE_CB *consoleCB)
1431 {
1432 if (consoleCB == NULL) {
1433 PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
1434 return FALSE;
1435 }
1436 return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_NONBLOCK) == 0;
1437 }
1438
SetSerialBlock(const CONSOLE_CB * consoleCB)1439 BOOL SetSerialBlock(const CONSOLE_CB *consoleCB)
1440 {
1441 if (consoleCB == NULL) {
1442 PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
1443 return TRUE;
1444 }
1445 return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_BLOCK) != 0;
1446 }
1447
SetTelnetNonBlock(const CONSOLE_CB * consoleCB)1448 BOOL SetTelnetNonBlock(const CONSOLE_CB *consoleCB)
1449 {
1450 if (consoleCB == NULL) {
1451 PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
1452 return FALSE;
1453 }
1454 return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_TELNET, CONSOLE_RD_NONBLOCK) == 0;
1455 }
1456
SetTelnetBlock(const CONSOLE_CB * consoleCB)1457 BOOL SetTelnetBlock(const CONSOLE_CB *consoleCB)
1458 {
1459 if (consoleCB == NULL) {
1460 PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
1461 return TRUE;
1462 }
1463 return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_TELNET, CONSOLE_RD_BLOCK) != 0;
1464 }
1465
is_nonblock(const CONSOLE_CB * consoleCB)1466 BOOL is_nonblock(const CONSOLE_CB *consoleCB)
1467 {
1468 if (consoleCB == NULL) {
1469 PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
1470 return FALSE;
1471 }
1472 return consoleCB->isNonBlock;
1473 }
1474
ConsoleUpdateFd(VOID)1475 INT32 ConsoleUpdateFd(VOID)
1476 {
1477 INT32 consoleID;
1478
1479 if (OsCurrTaskGet() != NULL) {
1480 consoleID = g_taskConsoleIDArray[(OsCurrTaskGet())->taskID];
1481 } else {
1482 return -1;
1483 }
1484
1485 if (g_uart_fputc_en == 0) {
1486 if (g_console[CONSOLE_TELNET - 1] != NULL) {
1487 consoleID = CONSOLE_TELNET;
1488 }
1489 } else if (consoleID == 0) {
1490 if (g_console[CONSOLE_SERIAL - 1] != NULL) {
1491 consoleID = CONSOLE_SERIAL;
1492 } else if (g_console[CONSOLE_TELNET - 1] != NULL) {
1493 consoleID = CONSOLE_TELNET;
1494 } else {
1495 PRINTK("No console dev used.\n");
1496 return -1;
1497 }
1498 }
1499
1500 return (g_console[consoleID - 1] != NULL) ? g_console[consoleID - 1]->fd : -1;
1501 }
1502
OsGetConsoleByID(INT32 consoleID)1503 CONSOLE_CB *OsGetConsoleByID(INT32 consoleID)
1504 {
1505 if (consoleID != CONSOLE_TELNET) {
1506 consoleID = CONSOLE_SERIAL;
1507 }
1508 return g_console[consoleID - 1];
1509 }
1510
OsGetConsoleByTaskID(UINT32 taskID)1511 CONSOLE_CB *OsGetConsoleByTaskID(UINT32 taskID)
1512 {
1513 INT32 consoleID = g_taskConsoleIDArray[taskID];
1514
1515 return OsGetConsoleByID(consoleID);
1516 }
1517
OsSetConsoleID(UINT32 newTaskID,UINT32 curTaskID)1518 VOID OsSetConsoleID(UINT32 newTaskID, UINT32 curTaskID)
1519 {
1520 if ((newTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT) || (curTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT)) {
1521 return;
1522 }
1523
1524 g_taskConsoleIDArray[newTaskID] = g_taskConsoleIDArray[curTaskID];
1525 }
1526
WriteToTerminal(const CONSOLE_CB * consoleCB,const CHAR * buffer,size_t bufLen)1527 STATIC ssize_t WriteToTerminal(const CONSOLE_CB *consoleCB, const CHAR *buffer, size_t bufLen)
1528 {
1529 INT32 ret, fd;
1530 INT32 cnt = 0;
1531 struct file *privFilep = NULL;
1532 struct file *filep = NULL;
1533 const struct file_operations_vfs *fileOps = NULL;
1534
1535 fd = consoleCB->fd;
1536 ret = fs_getfilep(fd, &filep);
1537 if (ret < 0) {
1538 ret = -EPERM;
1539 goto ERROUT;
1540 }
1541 ret = GetFilepOps(filep, &privFilep, &fileOps);
1542 if (ret != ENOERR) {
1543 ret = -EINVAL;
1544 goto ERROUT;
1545 }
1546
1547 if ((fileOps == NULL) || (fileOps->write == NULL)) {
1548 ret = EFAULT;
1549 goto ERROUT;
1550 }
1551 (VOID)fileOps->write(privFilep, buffer, bufLen);
1552
1553 return cnt;
1554
1555 ERROUT:
1556 set_errno(ret);
1557 return VFS_ERROR;
1558 }
1559
ConsoleSendTask(UINTPTR param)1560 STATIC UINT32 ConsoleSendTask(UINTPTR param)
1561 {
1562 CONSOLE_CB *consoleCB = (CONSOLE_CB *)param;
1563 CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;
1564 CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;
1565 UINT32 ret, size;
1566 CHAR *buf = NULL;
1567
1568 (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING);
1569
1570 while (1) {
1571 ret = LOS_EventRead(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT,
1572 LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
1573 if (ret == CONSOLE_CIRBUF_EVENT) {
1574 size = LOS_CirBufUsedSize(cirBufCB);
1575 if (size == 0) {
1576 continue;
1577 }
1578 buf = (CHAR *)LOS_MemAlloc(m_aucSysMem1, size + 1);
1579 if (buf == NULL) {
1580 continue;
1581 }
1582 (VOID)memset_s(buf, size + 1, 0, size + 1);
1583
1584 (VOID)LOS_CirBufRead(cirBufCB, buf, size);
1585
1586 (VOID)WriteToTerminal(consoleCB, buf, size);
1587 (VOID)LOS_MemFree(m_aucSysMem1, buf);
1588 } else if (ret == CONSOLE_SEND_TASK_EXIT) {
1589 break;
1590 }
1591 }
1592
1593 ConsoleCirBufDelete(cirBufSendCB);
1594 return LOS_OK;
1595 }
1596
1597 #ifdef LOSCFG_KERNEL_SMP
OsWaitConsoleSendTaskPend(UINT32 taskID)1598 VOID OsWaitConsoleSendTaskPend(UINT32 taskID)
1599 {
1600 UINT32 i;
1601 CONSOLE_CB *console = NULL;
1602 LosTaskCB *taskCB = NULL;
1603 INT32 waitTime = 3000; /* 3000: 3 seconds */
1604
1605 for (i = 0; i < CONSOLE_NUM; i++) {
1606 console = g_console[i];
1607 if (console == NULL) {
1608 continue;
1609 }
1610
1611 if (OS_TID_CHECK_INVALID(console->sendTaskID)) {
1612 continue;
1613 }
1614
1615 taskCB = OS_TCB_FROM_TID(console->sendTaskID);
1616 while ((waitTime > 0) && (taskCB->taskEvent == NULL) && (taskID != console->sendTaskID)) {
1617 LOS_Mdelay(1); /* 1: wait console task pend */
1618 --waitTime;
1619 }
1620 }
1621 }
1622
OsWakeConsoleSendTask(VOID)1623 VOID OsWakeConsoleSendTask(VOID)
1624 {
1625 UINT32 i;
1626 CONSOLE_CB *console = NULL;
1627
1628 for (i = 0; i < CONSOLE_NUM; i++) {
1629 console = g_console[i];
1630 if (console == NULL) {
1631 continue;
1632 }
1633
1634 if (console->cirBufSendCB != NULL) {
1635 (VOID)LOS_EventWrite(&console->cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);
1636 }
1637 }
1638 }
1639 #endif
1640
1641