xref: /optee_os/core/kernel/semihosting.c (revision 19a31ec40245ae01a9adcd206eec2a4bb4479fc9)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2024 Andes Technology Corporation
4  */
5 
6 #include <kernel/semihosting.h>
7 #include <string.h>
8 
9 /*
10  * ARM and RISC-V have defined the standard way to perform
11  * the semihosting operations.
12  * - Operation codes and open modes are identical.
13  * - The implementation of the low-level __do_semihosting() call is
14  *   architecture-specific.
15  * - Arm semihosting interface:
16  *   https://developer.arm.com/documentation/dui0471/g/Semihosting/The-semihosting-interface
17  * - RISC-V semihosting interface:
18  *   https://github.com/riscv-non-isa/riscv-semihosting/blob/main/binary-interface.adoc
19  */
20 
21 /* An integer that specifies the file open mode */
22 enum semihosting_open_mode {
23 	SEMIHOSTING_OPEN_R = 0,
24 	SEMIHOSTING_OPEN_RB = 1,
25 	SEMIHOSTING_OPEN_RX = 2,
26 	SEMIHOSTING_OPEN_RXB = 3,
27 	SEMIHOSTING_OPEN_W = 4,
28 	SEMIHOSTING_OPEN_WB = 5,
29 	SEMIHOSTING_OPEN_WX = 6,
30 	SEMIHOSTING_OPEN_WXB = 7,
31 	SEMIHOSTING_OPEN_A = 8,
32 	SEMIHOSTING_OPEN_AB = 9,
33 	SEMIHOSTING_OPEN_AX = 10,
34 	SEMIHOSTING_OPEN_AXB = 11,
35 };
36 
37 enum semihosting_sys_ops {
38 	/* Regular operations */
39 	SEMIHOSTING_SYS_OPEN = 0x01,
40 	SEMIHOSTING_SYS_CLOSE = 0x02,
41 	SEMIHOSTING_SYS_WRITEC = 0x03,
42 	SEMIHOSTING_SYS_WRITE = 0x05,
43 	SEMIHOSTING_SYS_READ = 0x06,
44 	SEMIHOSTING_SYS_READC = 0x07,
45 };
46 
47 struct semihosting_param_t {
48 	uintptr_t param0;
49 	uintptr_t param1;
50 	uintptr_t param2;
51 };
52 
53 /**
54  * @brief Read one character byte from the semihosting host debug terminal
55  *
56  * @retval the character read from the semihosting host
57  */
58 char semihosting_sys_readc(void)
59 {
60 	return __do_semihosting(SEMIHOSTING_SYS_READC, 0);
61 }
62 
63 /**
64  * @brief Write one character byte to the semihosting host debug terminal
65  * @param c: the character to be written
66  */
67 void semihosting_sys_writec(char c)
68 {
69 	__do_semihosting(SEMIHOSTING_SYS_WRITEC, (uintptr_t)&c);
70 }
71 
72 /**
73  * @brief Request the semihosting host to open a file on the host system
74  * @param fname: the path or name of the file
75  * @param flags: sys/fcntl.h standard flags to open the file with
76  *
77  * @retval nonzero if OK, or -1 if fails
78  */
79 int semihosting_open(const char *fname, int flags)
80 {
81 	int semi_open_flags = 0;
82 	const int flags_mask = O_RDONLY | O_WRONLY | O_RDWR |
83 			       O_CREAT | O_TRUNC | O_APPEND;
84 	struct semihosting_param_t arg = { };
85 
86 	/* Convert the flags to semihosting open. */
87 	switch (flags & flags_mask) {
88 	case O_RDONLY:				/* 'r' */
89 		semi_open_flags = SEMIHOSTING_OPEN_R;
90 		break;
91 	case O_WRONLY | O_CREAT | O_TRUNC:	/* 'w' */
92 		semi_open_flags = SEMIHOSTING_OPEN_W;
93 		break;
94 	case O_WRONLY | O_CREAT | O_APPEND:	/* 'a' */
95 		semi_open_flags = SEMIHOSTING_OPEN_A;
96 		break;
97 	case O_RDWR:				/* 'r+' */
98 		semi_open_flags = SEMIHOSTING_OPEN_RX;
99 		break;
100 	case O_RDWR | O_CREAT | O_TRUNC:	/* 'w+' */
101 		semi_open_flags = SEMIHOSTING_OPEN_WX;
102 		break;
103 	case O_RDWR | O_CREAT | O_APPEND:	/* 'a+' */
104 		semi_open_flags = SEMIHOSTING_OPEN_AX;
105 		break;
106 	default:
107 		return -1;
108 	}
109 
110 	arg.param0 = (uintptr_t)fname;
111 	arg.param1 = semi_open_flags;
112 	arg.param2 = strlen(fname);
113 
114 	return (int)__do_semihosting(SEMIHOSTING_SYS_OPEN, (uintptr_t)&arg);
115 }
116 
117 /**
118  * @brief Read data from a file on the semihosting host system
119  * @param fd: a handle for a file previously opened
120  * @param ptr: pointer to a buffer
121  * @param len: the number of bytes to read to the buffer from the file
122  *
123  * @retval zero if OK, the same value as @len if fails, smaller value than @len
124  * for partial success
125  */
126 size_t semihosting_read(int fd, void *ptr, size_t len)
127 {
128 	struct semihosting_param_t arg = {
129 		.param0 = fd,
130 		.param1 = (uintptr_t)ptr,
131 		.param2 = len
132 	};
133 
134 	return __do_semihosting(SEMIHOSTING_SYS_READ, (uintptr_t)&arg);
135 }
136 
137 /**
138  * @brief Write data into a file on the semihosting host system
139  * @param fd: a handle for a file previously opened
140  * @param ptr: pointer to a buffer
141  * @param len: the number of bytes to be written from the buffer to the file
142  *
143  * @retval zero if OK, otherwise the number of bytes that are not written
144  */
145 size_t semihosting_write(int fd, const void *ptr, size_t len)
146 {
147 	struct semihosting_param_t arg = {
148 		.param0 = fd,
149 		.param1 = (uintptr_t)ptr,
150 		.param2 = len
151 	};
152 
153 	return __do_semihosting(SEMIHOSTING_SYS_WRITE, (uintptr_t)&arg);
154 }
155 
156 /**
157  * @brief Close a file on the semihosting host system
158  * @param fd: a handle for a file previously opened
159  *
160  * @retval zero if OK, -1 if fails
161  */
162 int semihosting_close(int fd)
163 {
164 	struct semihosting_param_t arg = {
165 		.param0 = fd,
166 	};
167 
168 	return (int)__do_semihosting(SEMIHOSTING_SYS_CLOSE, (uintptr_t)&arg);
169 }
170