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