1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <fwk_attributes.h>
9 #include <fwk_io.h>
10 #include <fwk_mm.h>
11 #include <fwk_module.h>
12
13 #include <stddef.h>
14 #include <stdio.h>
15
fwk_io_null_open(const struct fwk_io_stream * stream)16 int fwk_io_null_open(const struct fwk_io_stream *stream)
17 {
18 return FWK_SUCCESS;
19 }
20
fwk_io_null_getch(const struct fwk_io_stream * stream,char * ch)21 int fwk_io_null_getch(const struct fwk_io_stream *stream, char *ch)
22 {
23 return FWK_PENDING;
24 }
25
fwk_io_null_putch(const struct fwk_io_stream * stream,char ch)26 int fwk_io_null_putch(const struct fwk_io_stream *stream, char ch)
27 {
28 return FWK_SUCCESS;
29 }
30
fwk_io_null_close(const struct fwk_io_stream * stream)31 int fwk_io_null_close(const struct fwk_io_stream *stream)
32 {
33 return FWK_SUCCESS;
34 }
35
36 static struct fwk_io_stream fwk_io_null = {
37 .adapter =
38 &(const struct fwk_io_adapter){
39 .open = fwk_io_null_open,
40 .getch = fwk_io_null_getch,
41 .putch = fwk_io_null_putch,
42 .close = fwk_io_null_close,
43 },
44
45 .id = FWK_ID_NONE,
46 .mode = (enum fwk_io_mode)(
47 FWK_IO_MODE_READ | FWK_IO_MODE_WRITE | FWK_IO_MODE_BINARY),
48 };
49
50 struct fwk_io_stream *fwk_io_stdin = &fwk_io_null;
51 struct fwk_io_stream *fwk_io_stdout = &fwk_io_null;
52
fwk_io_init(void)53 int fwk_io_init(void)
54 {
55 static struct fwk_io_stream stdin_stream;
56 static struct fwk_io_stream stdout_stream;
57
58 int status = FWK_SUCCESS;
59
60 bool configure_stdin = !fwk_id_is_equal(FMW_IO_STDIN_ID, FWK_ID_NONE);
61 bool configure_stdout = !fwk_id_is_equal(FMW_IO_STDOUT_ID, FWK_ID_NONE);
62
63 bool stdout_is_stdin = fwk_id_is_equal(FMW_IO_STDIN_ID, FMW_IO_STDOUT_ID);
64
65 if (configure_stdin) {
66 if (stdout_is_stdin) {
67 /*
68 * If stdin and stdout share the same entity, we only want to open
69 * it once and we want to do it with both read and write modes
70 * enabled, rather than opening the same entity twice with different
71 * modes.
72 */
73
74 status = fwk_io_open(
75 &stdin_stream,
76 FMW_IO_STDIN_ID,
77 (enum fwk_io_mode)(
78 ((unsigned int)FWK_IO_MODE_READ) |
79 ((unsigned int)FWK_IO_MODE_WRITE)));
80 if (fwk_expect(status == FWK_SUCCESS)) {
81 fwk_io_stdin = &stdin_stream;
82 fwk_io_stdout = &stdin_stream;
83 }
84 } else {
85 status =
86 fwk_io_open(&stdin_stream, FMW_IO_STDIN_ID, FWK_IO_MODE_READ);
87 if (fwk_expect(status == FWK_SUCCESS)) {
88 fwk_io_stdin = &stdin_stream;
89 }
90 }
91 }
92
93 if (configure_stdout && !stdout_is_stdin) {
94 status =
95 fwk_io_open(&stdout_stream, FMW_IO_STDOUT_ID, FWK_IO_MODE_WRITE);
96 if (fwk_expect(status == FWK_SUCCESS)) {
97 fwk_io_stdout = &stdout_stream;
98 }
99 }
100
101 if (status != FWK_SUCCESS) {
102 status = FWK_E_DEVICE;
103 }
104
105 return status;
106 }
107
fwk_io_open(struct fwk_io_stream * restrict stream,fwk_id_t id,enum fwk_io_mode mode)108 int fwk_io_open(
109 struct fwk_io_stream *restrict stream,
110 fwk_id_t id,
111 enum fwk_io_mode mode)
112 {
113 int status;
114
115 bool read = (((unsigned int)mode & (unsigned int)FWK_IO_MODE_READ) != 0U);
116 bool write = (((unsigned int)mode & (unsigned int)FWK_IO_MODE_WRITE) != 0U);
117
118 if (stream == NULL) {
119 return FWK_E_PARAM;
120 }
121
122 *stream = (struct fwk_io_stream){
123 .adapter = NULL,
124 .id = id,
125 .mode = mode,
126 };
127
128 if (!read && !write) {
129 return FWK_E_PARAM; /* Neither reading nor writing requested */
130 }
131
132 status = fwk_module_adapter(&stream->adapter, id);
133 if (status != FWK_SUCCESS) {
134 return FWK_E_PARAM; /* System entity doesn't exist */
135 }
136
137 fwk_assert(stream->adapter != NULL);
138
139 if (stream->adapter->open == NULL) {
140 return FWK_E_SUPPORT; /* Stream adapter is not implemented */
141 }
142
143 if ((read && (stream->adapter->getch == NULL))) {
144 return FWK_E_SUPPORT; /* Reads requested but no read interface */
145 }
146
147 if (write && (stream->adapter->putch == NULL)) {
148 return FWK_E_SUPPORT; /* Writes requested but no write interface */
149 }
150
151 status = stream->adapter->open(stream);
152 if (status != FWK_SUCCESS) {
153 return FWK_E_HANDLER;
154 }
155
156 return FWK_SUCCESS;
157 }
158
fwk_io_getch(const struct fwk_io_stream * stream,char * ch)159 int fwk_io_getch(const struct fwk_io_stream *stream, char *ch)
160 {
161 int status;
162
163 if (stream == NULL) {
164 return FWK_E_PARAM;
165 }
166
167 if (ch == NULL) {
168 return FWK_E_PARAM;
169 }
170
171 *ch = '\0';
172
173 if (stream->adapter == NULL) {
174 return FWK_E_STATE; /* The stream is not open */
175 }
176
177 if ((((unsigned int)stream->mode) & ((unsigned int)FWK_IO_MODE_READ)) ==
178 0U) {
179 return FWK_E_SUPPORT; /* Stream not open for read operations */
180 }
181
182 fwk_assert(stream->adapter->getch != NULL);
183
184 status = stream->adapter->getch(stream, ch);
185 if (status == FWK_PENDING) {
186 return FWK_PENDING;
187 } else if (status != FWK_SUCCESS) {
188 return FWK_E_HANDLER;
189 }
190
191 return FWK_SUCCESS;
192 }
193
fwk_io_putch(const struct fwk_io_stream * stream,char ch)194 int fwk_io_putch(const struct fwk_io_stream *stream, char ch)
195 {
196 int status;
197
198 if (stream == NULL) {
199 return FWK_E_PARAM;
200 }
201
202 if (stream->adapter == NULL) {
203 return FWK_E_STATE; /* The stream is not open */
204 }
205
206 if ((((unsigned int)stream->mode) & ((unsigned int)FWK_IO_MODE_WRITE)) ==
207 0U) {
208 return FWK_E_SUPPORT; /* Stream not open for write operations */
209 }
210
211 fwk_assert(stream->adapter->putch != NULL);
212
213 status = stream->adapter->putch(stream, ch);
214 if (status != FWK_SUCCESS) {
215 return FWK_E_HANDLER;
216 }
217
218 return FWK_SUCCESS;
219 }
220
fwk_io_read(const struct fwk_io_stream * restrict stream,size_t * restrict read,void * restrict buffer,size_t size,size_t count)221 int fwk_io_read(
222 const struct fwk_io_stream *restrict stream,
223 size_t *restrict read,
224 void *restrict buffer,
225 size_t size,
226 size_t count)
227 {
228 int status = FWK_SUCCESS;
229
230 char *cbuffer = buffer;
231
232 if (read != NULL) {
233 *read = 0;
234 }
235
236 for (size_t i = 0; (i < count) && (status == FWK_SUCCESS); i++) {
237 for (size_t j = 0; (j < size) && (status == FWK_SUCCESS); j++) {
238 status = fwk_io_getch(stream, cbuffer++);
239 }
240
241 if ((status == FWK_SUCCESS) && (read != NULL)) {
242 *read += 1;
243 }
244 }
245
246 if ((status == FWK_PENDING) && (read == NULL)) {
247 return FWK_E_DATA; /* Reached end-of-stream */
248 }
249
250 return status;
251 }
252
fwk_io_write(const struct fwk_io_stream * restrict stream,size_t * restrict written,const void * restrict buffer,size_t size,size_t count)253 int fwk_io_write(
254 const struct fwk_io_stream *restrict stream,
255 size_t *restrict written,
256 const void *restrict buffer,
257 size_t size,
258 size_t count)
259 {
260 int status = FWK_SUCCESS;
261
262 const char *cbuffer = buffer;
263
264 if (cbuffer == NULL) {
265 return FWK_E_PARAM;
266 }
267
268 if (written != NULL) {
269 *written = 0;
270 }
271
272 for (size_t i = 0; (i < count) && (status == FWK_SUCCESS); i++) {
273 for (size_t j = 0; (j < size) && (status == FWK_SUCCESS); j++) {
274 status = fwk_io_putch(stream, *cbuffer++);
275 }
276
277 if ((status == FWK_SUCCESS) && (written != NULL)) {
278 *written += 1;
279 }
280 }
281
282 return status;
283 }
284
fwk_io_close(struct fwk_io_stream * stream)285 int fwk_io_close(struct fwk_io_stream *stream)
286 {
287 int status;
288
289 if (stream == NULL) {
290 return FWK_E_PARAM;
291 }
292
293 if (stream->adapter == NULL) {
294 return FWK_SUCCESS; /* The stream is not open */
295 }
296
297 if (stream->adapter->close == NULL) {
298 return FWK_SUCCESS; /* Nothing else to do */
299 }
300
301 status = stream->adapter->close(stream);
302
303 *stream = (struct fwk_io_stream){
304 .adapter = NULL,
305 .id = FWK_ID_NONE,
306 .mode = 0,
307 };
308
309 if (status != FWK_SUCCESS) {
310 return FWK_E_HANDLER;
311 }
312
313 return FWK_SUCCESS;
314 }
315
fwk_io_puts(const struct fwk_io_stream * restrict stream,const char * restrict str)316 int fwk_io_puts(
317 const struct fwk_io_stream *restrict stream,
318 const char *restrict str)
319 {
320 if (str == NULL) {
321 return FWK_E_PARAM;
322 }
323
324 return fwk_io_write(stream, NULL, str, sizeof(char), strlen(str));
325 }
326
fwk_io_vprintf(const struct fwk_io_stream * restrict stream,const char * restrict format,va_list args)327 int fwk_io_vprintf(
328 const struct fwk_io_stream *restrict stream,
329 const char *restrict format,
330 va_list args)
331 {
332 int status = FWK_SUCCESS;
333
334 int length;
335 va_list length_args;
336
337 char *buffer;
338
339 if (format == NULL) {
340 return FWK_E_PARAM;
341 }
342
343 va_copy(length_args, args);
344 length = vsnprintf(NULL, 0, format, length_args);
345 va_end(length_args);
346
347 if (length < 0) { /* Possibly invalid format string? */
348 return FWK_E_STATE;
349 }
350
351 buffer = fwk_mm_alloc_notrap(sizeof(buffer[0]), (size_t)(length + 1));
352 if (buffer == NULL) { /* Not enough memory for the string buffer */
353 return FWK_E_NOMEM;
354 }
355
356 length = vsnprintf(buffer, (size_t)(length + 1), format, args);
357 if (length >= 0) {
358 status = fwk_io_puts(stream, buffer); /* Write out the buffer */
359 } else {
360 status = FWK_E_STATE;
361 }
362
363 fwk_mm_free(buffer);
364
365 return status;
366 }
367
fwk_io_printf(const struct fwk_io_stream * restrict stream,const char * restrict format,...)368 int fwk_io_printf(
369 const struct fwk_io_stream *restrict stream,
370 const char *restrict format,
371 ...)
372 {
373 int status;
374
375 va_list args;
376
377 va_start(args, format);
378 status = fwk_io_vprintf(stream, format, args);
379 va_end(args);
380
381 return status;
382 }
383