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