xref: /optee_os/core/drivers/semihosting_console.c (revision 458ef4426c2dc20d27c3ceec0a18f1eb5098d31c)
1*458ef442SAlvin Chang // SPDX-License-Identifier: BSD-2-Clause
2*458ef442SAlvin Chang /*
3*458ef442SAlvin Chang  * Copyright (c) 2024 Andes Technology Corporation
4*458ef442SAlvin Chang  */
5*458ef442SAlvin Chang 
6*458ef442SAlvin Chang #include <compiler.h>
7*458ef442SAlvin Chang #include <console.h>
8*458ef442SAlvin Chang #include <drivers/semihosting_console.h>
9*458ef442SAlvin Chang #include <drivers/serial.h>
10*458ef442SAlvin Chang #include <kernel/semihosting.h>
11*458ef442SAlvin Chang #include <util.h>
12*458ef442SAlvin Chang 
13*458ef442SAlvin Chang /*
14*458ef442SAlvin Chang  * struct semihosting_console_data - Structure for semihosting console driver
15*458ef442SAlvin Chang  * @chip - General structure for each serial chip
16*458ef442SAlvin Chang  * @fd - Handle of the file at @file_path when semihosting_console_init() is
17*458ef442SAlvin Chang  *       called, or -1 if using the semihosting console
18*458ef442SAlvin Chang  */
19*458ef442SAlvin Chang struct semihosting_console_data {
20*458ef442SAlvin Chang 	struct serial_chip chip;
21*458ef442SAlvin Chang 	int fd;
22*458ef442SAlvin Chang };
23*458ef442SAlvin Chang 
24*458ef442SAlvin Chang static struct semihosting_console_data sh_console_data __nex_bss;
25*458ef442SAlvin Chang 
semihosting_console_putc(struct serial_chip * chip __unused,int ch)26*458ef442SAlvin Chang static void semihosting_console_putc(struct serial_chip *chip __unused, int ch)
27*458ef442SAlvin Chang {
28*458ef442SAlvin Chang 	semihosting_sys_writec(ch);
29*458ef442SAlvin Chang }
30*458ef442SAlvin Chang 
semihosting_console_getchar(struct serial_chip * chip __unused)31*458ef442SAlvin Chang static int semihosting_console_getchar(struct serial_chip *chip __unused)
32*458ef442SAlvin Chang {
33*458ef442SAlvin Chang 	return semihosting_sys_readc();
34*458ef442SAlvin Chang }
35*458ef442SAlvin Chang 
36*458ef442SAlvin Chang static const struct serial_ops semihosting_console_ops = {
37*458ef442SAlvin Chang 	.putc = semihosting_console_putc,
38*458ef442SAlvin Chang 	.getchar = semihosting_console_getchar,
39*458ef442SAlvin Chang };
40*458ef442SAlvin Chang DECLARE_KEEP_PAGER(semihosting_console_ops);
41*458ef442SAlvin Chang 
semihosting_console_fd_putc(struct serial_chip * chip __unused,int ch)42*458ef442SAlvin Chang static void semihosting_console_fd_putc(struct serial_chip *chip __unused,
43*458ef442SAlvin Chang 					int ch)
44*458ef442SAlvin Chang {
45*458ef442SAlvin Chang 	if (sh_console_data.fd >= 0)
46*458ef442SAlvin Chang 		semihosting_write(sh_console_data.fd, &ch, 1);
47*458ef442SAlvin Chang }
48*458ef442SAlvin Chang 
49*458ef442SAlvin Chang static const struct serial_ops semihosting_console_fd_ops = {
50*458ef442SAlvin Chang 	.putc = semihosting_console_fd_putc,
51*458ef442SAlvin Chang };
52*458ef442SAlvin Chang DECLARE_KEEP_PAGER(semihosting_console_fd_ops);
53*458ef442SAlvin Chang 
semihosting_console_init(const char * file_path)54*458ef442SAlvin Chang void semihosting_console_init(const char *file_path)
55*458ef442SAlvin Chang {
56*458ef442SAlvin Chang 	if (file_path) {
57*458ef442SAlvin Chang 		/* Output log to given file on the semihosting host system. */
58*458ef442SAlvin Chang 		sh_console_data.chip.ops = &semihosting_console_fd_ops;
59*458ef442SAlvin Chang 		sh_console_data.fd =
60*458ef442SAlvin Chang 			semihosting_open(file_path, O_RDWR | O_CREAT | O_TRUNC);
61*458ef442SAlvin Chang 	} else {
62*458ef442SAlvin Chang 		/* Output log to semihosting host debug console. */
63*458ef442SAlvin Chang 		sh_console_data.chip.ops = &semihosting_console_ops;
64*458ef442SAlvin Chang 		sh_console_data.fd = -1;
65*458ef442SAlvin Chang 	}
66*458ef442SAlvin Chang 
67*458ef442SAlvin Chang 	register_serial_console(&sh_console_data.chip);
68*458ef442SAlvin Chang }
69