1 /*******************************************************************************
2 * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * MPFS HAL Embedded Software
7 *
8 */
9
10 /*******************************************************************************
11 * @file newlib_stubs.c
12 * @author Microchip-FPGA Embedded Systems Solutions
13 * @brief Stubs for Newlib system calls.
14 *
15 */
16 #include <sys/times.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include "../mss_hal.h"
22
23 /*==============================================================================
24 * Redirection of standard output to a SmartFusion2 MSS UART.
25 *------------------------------------------------------------------------------
26 * A default implementation for the redirection of the output of printf() to a
27 * UART is provided at the bottom of this file. This redirection is enabled by
28 * adding the symbol/define MICROCHIP_STDIO_THRU_MMUART0 or
29 * MICROCHIP_STDIO_THRU_MMUART0 to your project settings and specifying the baud
30 * rate using the MICROCHIP_STDIO_BAUD_RATE define.
31 */
32 #ifdef MICROCHIP_STDIO_THRU_MMUART0
33 #ifndef MICROCHIP_STDIO_THRU_UART
34 #define MICROCHIP_STDIO_THRU_UART
35 #endif
36 #endif /* MICROCHIP_STDIO_THRU_MMUART0 */
37
38 #ifdef MICROCHIP_STDIO_THRU_MMUART1
39 #ifndef MICROCHIP_STDIO_THRU_UART
40 #define MICROCHIP_STDIO_THRU_UART
41 #endif
42 #endif /* MICROCHIP_STDIO_THRU_MMUART1 */
43
44 /*
45 * Select which MMUART will be used for stdio and what baud rate will be used.
46 * Default to 57600 baud if no baud rate is specified using the
47 * MICROCHIP_STDIO_BAUD_RATE #define.
48 */
49 #ifdef MICROCHIP_STDIO_THRU_UART
50 #include "drivers/mss/mss_mmuart/mss_uart.h"
51
52 #ifndef MICROCHIP_STDIO_BAUD_RATE
53 #define MICROCHIP_STDIO_BAUD_RATE MSS_UART_115200_BAUD
54 #endif
55
56 #ifdef MICROCHIP_STDIO_THRU_MMUART0
57 static mss_uart_instance_t * const gp_my_uart = &g_mss_uart0;
58 #else
59 static mss_uart_instance_t * const gp_my_uart = &g_mss_uart1;
60 #endif
61
62 /*------------------------------------------------------------------------------
63 * Global flag used to indicate if the UART driver needs to be initialized.
64 */
65 static int g_stdio_uart_init_done = 0;
66
67 #endif /* MICROCHIP_STDIO_THRU_UART */
68
69 /*==============================================================================
70 * Environment variables.
71 * A pointer to a list of environment variables and their values. For a minimal
72 * environment, this empty list is adequate:
73 */
74 char *__env[1] = { 0 };
75 char **environ = __env;
76
77
78 /*==============================================================================
79 * Close a file.
80 */
81 int _close(int file);
_close(int file)82 int _close(int file)
83 {
84 (void)file;
85 return -1;
86 }
87
88 /*==============================================================================
89 * Transfer control to a new process.
90 */
91 int _execve(char *name, char **argv, char **env);
_execve(char * name,char ** argv,char ** env)92 int _execve(char *name, char **argv, char **env)
93 {
94 (void)name;
95 (void)argv;
96 (void)env;
97 errno = ENOMEM;
98 return -1;
99 }
100
101 /*==============================================================================
102 * Exit a program without cleaning up files.
103 */
_exit(int code)104 void _exit( int code )
105 {
106 (void)code;
107 /* Should we force a system reset? */
108 while( 1 )
109 {
110 ;
111 }
112 }
113
114 /*==============================================================================
115 * Create a new process.
116 */
117 int _fork(void);
_fork(void)118 int _fork(void)
119 {
120 errno = EAGAIN;
121 return -1;
122 }
123
124 /*==============================================================================
125 * Status of an open file.
126 */
127 int _fstat(int file, struct stat *st);
_fstat(int file,struct stat * st)128 int _fstat(int file, struct stat *st)
129 {
130 (void)file;
131 st->st_mode = S_IFCHR;
132 return (0);
133 }
134
135 /*==============================================================================
136 * Process-ID
137 */
138 int _getpid(void);
_getpid(void)139 int _getpid(void)
140 {
141 return (1);
142 }
143
144 /*==============================================================================
145 * Query whether output stream is a terminal.
146 */
147 int _isatty(int file);
_isatty(int file)148 int _isatty(int file)
149 {
150 (void)file;
151 return (1);
152 }
153
154 /*==============================================================================
155 * Send a signal.
156 */
157 int _kill(int pid, int sig);
_kill(int pid,int sig)158 int _kill(int pid, int sig)
159 {
160 (void)pid;
161 (void)sig;
162 errno = EINVAL;
163 return (-1);
164 }
165
166 /*==============================================================================
167 * Establish a new name for an existing file.
168 */
169 int _link(char *old, char *new);
_link(char * old,char * new)170 int _link(char *old, char *new)
171 {
172 (void)old;
173 (void)new;
174 errno = EMLINK;
175 return (-1);
176 }
177
178 /*==============================================================================
179 * Set position in a file.
180 */
181 int _lseek(int file, int ptr, int dir);
_lseek(int file,int ptr,int dir)182 int _lseek(int file, int ptr, int dir)
183 {
184 (void)file;
185 (void)ptr;
186 (void)dir;
187 return (0);
188 }
189
190 /*==============================================================================
191 * Open a file.
192 */
193 int _open(const char *name, int flags, int mode);
_open(const char * name,int flags,int mode)194 int _open(const char *name, int flags, int mode)
195 {
196 (void)name;
197 (void)flags;
198 (void)mode;
199 return (-1);
200 }
201
202 /*==============================================================================
203 * Read from a file.
204 */
205 int _read(int file, char *ptr, int len);
_read(int file,char * ptr,int len)206 int _read(int file, char *ptr, int len)
207 {
208 (void)file;
209 (void)ptr;
210 (void)len;
211 return (0);
212 }
213
214 /*==============================================================================
215 * Write to a file. libc subroutines will use this system routine for output to
216 * all files, including stdout so if you need to generate any output, for
217 * example to a serial port for debugging, you should make your minimal write
218 * capable of doing this.
219 */
220 int _write_r( void * reent, int file, char * ptr, int len );
_write_r(void * reent,int file,char * ptr,int len)221 int _write_r( void * reent, int file, char * ptr, int len )
222 {
223 (void)reent;
224 (void)file;
225 (void)ptr;
226 (void)len;
227 #ifdef MICROCHIP_STDIO_THRU_UART
228 /*--------------------------------------------------------------------------
229 * Initialize the UART driver if it is the first time this function is
230 * called.
231 */
232 if(!g_stdio_uart_init_done)
233 {
234 MSS_UART_init(gp_my_uart,
235 MICROCHIP_STDIO_BAUD_RATE,
236 MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY);
237
238 g_stdio_uart_init_done = 1;
239 }
240
241 /*--------------------------------------------------------------------------
242 * Output text to the UART.
243 */
244 MSS_UART_polled_tx(gp_my_uart, (uint8_t *)ptr, len);
245
246 return len;
247 #else /* MICROCHIP_STDIO_THRU_UART */
248 return (0);
249 #endif /* MICROCHIP_STDIO_THRU_UART */
250 }
251
252 /*==============================================================================
253 * Increase program data space. As malloc and related functions depend on this,
254 * it is useful to have a working implementation. The following suffices for a
255 * standalone system; it exploits the symbol _end automatically defined by the
256 * GNU linker.
257 */
258 caddr_t _sbrk(int incr);
_sbrk(int incr)259 caddr_t _sbrk(int incr)
260 {
261 extern char _end; /* Defined by the linker */
262 extern char __heap_start;
263 extern char __heap_end;
264 static char *heap_end;
265 char *prev_heap_end;
266
267 (void)__heap_start;
268 (void)__heap_end;
269 #ifdef DEBUG_HEAP_SIZE
270 char * stack_ptr = NULL;
271 #endif
272
273 /*
274 * Did we allocated memory for the heap in the linker script?
275 * You need to set HEAP_SIZE to a non-zero value in your linker script if
276 * the following assertion fires.
277 */
278 ASSERT(&__heap_end > &__heap_start);
279
280 if (heap_end == NULL)
281 {
282 heap_end = &_end;
283 }
284
285 prev_heap_end = heap_end;
286
287 #ifdef DEBUG_HEAP_SIZE /* add this define if you want to debug crash due to overflow of heap */
288 /* fixme- this test needs to be reworked to take account of multiple harts and TLS */
289 stack_ptr = read_csr(sp);
290 /* stack_ptr has just been placed on the stack, so its address in currently pointing to the stack end */
291 if(heap_end < stack_ptr)
292 {
293 /*
294 * Heap is at an address below the stack, growing up toward the stack.
295 * The stack is above the heap, growing down towards the heap.
296 * Make sure the stack and heap do not run into each other.
297 */
298 if (heap_end + incr > stack_ptr)
299 {
300 _write_r ((void *)0, 1, "Heap and stack collision\n", 25);
301 _exit (1);
302 }
303 }
304 else
305 {
306 /*
307 * If the heap and stack are not growing towards each other then use the
308 * _eheap linker script symbol to figure out if there is room left on
309 * the heap.
310 * Please note that this use case makes sense when the stack is located
311 * in internal eSRAM in the 0x20000000 address range and the heap is
312 * located in the external memory in the 0xA0000000 memory range.
313 * Please note that external memory should not be accessed using the
314 * 0x00000000 memory range to read/write variables/data because of the
315 * SmartFusion2 cache design.
316 */
317 extern char _heap_end; /* Defined by the linker */
318 char *top_of_heap;
319
320 top_of_heap = &_heap_end;
321 if(heap_end + incr > top_of_heap)
322 {
323 _write_r ((void *)0, 1, "Out of heap memory\n", 25);
324 _exit (1);
325 }
326 }
327 #endif
328 heap_end += incr;
329
330 /*
331 * Did we run out of heap?
332 * You need to increase the heap size in the linker script if the following
333 * assertion fires.
334 * */
335 ASSERT(heap_end <= &__heap_end);
336
337 return ((caddr_t) prev_heap_end);
338 }
339
340 /*==============================================================================
341 * Status of a file (by name).
342 */
343 int _stat(char *file, struct stat *st);
_stat(char * file,struct stat * st)344 int _stat(char *file, struct stat *st)
345 {
346 (void)file;
347 st->st_mode = S_IFCHR;
348 return 0;
349 }
350
351 /*==============================================================================
352 * Timing information for current process.
353 */
354 int _times(struct tms *buf);
_times(struct tms * buf)355 int _times(struct tms *buf)
356 {
357 (void)buf;
358 return (-1);
359 }
360
361 /*==============================================================================
362 * Remove a file's directory entry.
363 */
364 int _unlink(char *name);
_unlink(char * name)365 int _unlink(char *name)
366 {
367 (void)name;
368 errno = ENOENT;
369 return (-1);
370 }
371
372 /*==============================================================================
373 * Wait for a child process.
374 */
375 int _wait(int *status);
_wait(int * status)376 int _wait(int *status)
377 {
378 (void)status;
379 errno = ECHILD;
380 return (-1);
381 }
382