Contiki 3.x
newlib-syscalls.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Eistec AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * This file is part of the Mulle platform port of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Syscall implementations for K60 CPU.
36  * \author
37  * Joakim Gebart <joakim.gebart@eistec.se>
38  */
39 
40 
41 #include <unistd.h>
42 #include <sys/reent.h>
43 #include <sys/times.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 
49 #include <errno.h>
50 //~ #undef errno
51 //~ extern int errno;
52 
53 #include "K60.h"
54 #include "devopttab.h"
55 #include "devicemap.h"
56 #include "cfs.h"
57 #include "synchronization.h"
58 
59 /* Empty environment definition */
60 char *__env[1] = { 0 };
61 char **environ = __env;
62 
63 /* Lock variable used to protect sbrk_r from clobbering the break variable when
64  * called simultaneously from more than one thread. */
65 static lock_t sbrk_lock = 0;
66 
67 /* Align all sbrk arguments to this many bytes */
68 #define DYNAMIC_MEMORY_ALIGN 4
69 
70 /* ************************ */
71 /* Process control syscalls */
72 /* ************************ */
73 
74 void
75 _exit(int code) {
76  volatile int status; /* volatile to prevent optimizations to remove the variable from memory */
77  status = code;
78  (void)status; /* Suppress compiler warnings about unused variable */
79 
80  /* See local variable `status` during debugger break. */
81  DEBUGGER_BREAK(BREAK_EXIT);
83  while(1);
84 }
85 
86 int
87 _fork_r(struct _reent *r) {
88  /* return "not supported" */
89  r->_errno = ENOTSUP;
90  return -1;
91 }
92 
93 int
94 _execve_r(struct _reent *r, const char *name, char *const *argv, char *const *env) {
95  /* Not supported */
96  (void)name; /* Suppress compiler warnings about unused parameters */
97  (void)argv;
98  (void)env;
99 
100  r->_errno = ENOMEM;
101  return -1;
102 }
103 
104 int
105 _kill_r(struct _reent *r, int pid, int sig) {
106  /* Not supported */
107  (void)pid; /* Suppress compiler warnings about unused parameters */
108  (void)sig;
109 
110  r->_errno = EINVAL;
111  return -1;
112 }
113 
114 pid_t
115 _getpid(void)
116 {
117  /** \todo Return some process identifier on getpid() */
118  return 1;
119 }
120 
121 clock_t
122 _times_r(struct _reent *r, struct tms *buf)
123 {
124  /* Not supported, yet */
125  (void)buf; /* Suppress compiler warnings about unused parameters */
126 
127  r->_errno = EACCES;
128  return -1;
129 }
130 
131 int
132 _wait_r(struct _reent *r, int *status)
133 {
134  /* Not supported, yet */
135  (void)status; /* Suppress compiler warnings about unused parameters */
136 
137  r->_errno = ECHILD;
138  return -1;
139 }
140 
141 /* ******************************** */
142 /* File descriptor related syscalls */
143 /* ******************************** */
144 
145 static int get_next_dev_fd(void);
146 
147 /** Internal helper for generating FDs */
148 static int get_next_dev_fd(void) {
149  int fd;
150  for (fd = 0; fd < MAX_OPEN_DEVICES; ++fd) {
151  if (devoptab_list[fd] == NULL) {
152  return fd;
153  }
154  }
155  return -1;
156 }
157 
158 int
159 _open_r(struct _reent *r, const char *name, int flags, int mode) {
160  unsigned int i;
161  int fd;
162  int cfs_flags = 0;
163  /* Search for devices */
164  for (i = 0; i < devoptab_name_list.len; ++i) {
165  if (strcmp(devoptab_name_list.data[i].name, name) == 0) {
166  /* Device found */
167  fd = get_next_dev_fd();
168  if (fd < 0)
169  {
170  /* No free FDs. */
171  /* ENFILE means too many file descriptors open, system-wide. */
172  r->_errno = ENFILE;
173  return -1;
174  }
175  /* Set up device operations table and call open method */
176  devoptab_list[fd] = devoptab_name_list.data[i].devoptab;
177  /* open_r method is mandatory */
178  devoptab_list[fd]->open_r(r, name, flags, mode);
179  return fd;
180  }
181  }
182  /* Not a device name, try searching for files. */
183  /* Translate POSIX O_* flags to CFS */
184  if (flags & O_APPEND) {
185  cfs_flags |= CFS_APPEND;
186  }
187  if (flags & O_RDWR) {
188  cfs_flags |= CFS_READ | CFS_WRITE;
189  }
190  if (flags & O_RDONLY) {
191  cfs_flags |= CFS_READ;
192  }
193  if (flags & O_WRONLY) {
194  cfs_flags |= CFS_WRITE;
195  }
196  fd = cfs_open(name, cfs_flags);
197  if (fd < 0) {
198  /* Not found or whatever, CFS doesn't tell us why it failed. */
199  r->_errno = ENOENT;
200  return -1;
201  }
202  fd += MAX_OPEN_DEVICES; /* Remap from CFS FD number */
203  return fd;
204 }
205 
206 int
207 _close_r(struct _reent *r, int fd) {
208  int ret;
209 
210  if (fd < 0) {
211  /* invalid file descriptor */
212  r->_errno = EBADF;
213  return -1;
214  }
215 
216  if (fd >= MAX_OPEN_DEVICES) {
217  /* CFS file */
218  fd -= MAX_OPEN_DEVICES; /* Remap to CFS FD number */
219  cfs_close(fd);
220  return 0; /* cfs_close does not indicate failures */
221  }
222  if (devoptab_list[fd] == NULL) {
223  /* nothing mapped on that FD */
224  r->_errno = EBADF;
225  return -1;
226  }
227  if (devoptab_list[fd]->close_r == NULL) {
228  /* Function not implemented */
229  r->_errno = ENOSYS;
230  return -1;
231  }
232  /* Call method from device operations table */
233  ret = devoptab_list[fd]->close_r(r, fd);
234  if (ret == 0) {
235  /* Successfully closed, clear out device operations table entry to free up
236  * the file descriptor. */
237  devoptab_list[fd] = NULL;
238  }
239  return ret;
240 }
241 
242 ssize_t
243 _read_r(struct _reent *r, int fd, void *ptr, size_t len) {
244 
245  if (fd < 0) {
246  /* invalid file descriptor */
247  r->_errno = EBADF;
248  return -1;
249  }
250 
251  if (fd >= MAX_OPEN_DEVICES) {
252  int ret;
253  /* CFS file */
254  fd -= MAX_OPEN_DEVICES; /* Remap to CFS FD number */
255  /* this is not really reentrant */
256  ret = cfs_read(fd, ptr, len);
257  if (ret < 0) {
258  r->_errno = EBADF;
259  }
260  return ret;
261  }
262  if (devoptab_list[fd] == NULL) {
263  /* nothing mapped on that FD */
264  r->_errno = EBADF;
265  return -1;
266  }
267  if (devoptab_list[fd]->read_r == NULL) {
268  /* Function not implemented */
269  r->_errno = ENOSYS;
270  return -1;
271  }
272  /* Call method from device operations table */
273  return devoptab_list[fd]->read_r(r, fd, ptr, len);
274 }
275 
276 ssize_t
277 _write_r(struct _reent *r, int fd, const void *ptr, size_t len) {
278 
279  if (fd < 0) {
280  /* invalid file descriptor */
281  r->_errno = EBADF;
282  return -1;
283  }
284 
285  if (fd >= MAX_OPEN_DEVICES) {
286  int ret;
287  /* CFS file */
288  fd -= MAX_OPEN_DEVICES; /* Remap to CFS FD number */
289  /* this is not really reentrant */
290  ret = cfs_write(fd, (const char *)ptr, len);
291  if (ret < 0) {
292  r->_errno = EBADF;
293  }
294  return ret;
295  }
296  if (devoptab_list[fd] == NULL) {
297  /* nothing mapped on that FD */
298  r->_errno = EBADF;
299  return -1;
300  }
301  if (devoptab_list[fd]->write_r == NULL) {
302  /* Function not implemented */
303  r->_errno = ENOSYS;
304  return -1;
305  }
306  /* Call method from device operations table */
307  return devoptab_list[fd]->write_r(r, fd, ptr, len);
308 }
309 
310 off_t
311 _lseek_r(struct _reent *r, int fd, off_t offset, int whence) {
312 
313  if (fd < 0) {
314  /* invalid file descriptor */
315  r->_errno = EBADF;
316  return -1;
317  }
318 
319  if (fd >= MAX_OPEN_DEVICES) {
320  int ret;
321  /* CFS file */
322  fd -= MAX_OPEN_DEVICES; /* Remap to CFS FD number */
323  /* CFS_SEEK_* macros used by the CFS whence parameter is assumed to
324  * correspond with POSIX constants */
325  /* this is not really reentrant */
326  ret = cfs_seek(fd, offset, whence);
327  if (ret < 0) {
328  r->_errno = EBADF;
329  }
330  return ret;
331  }
332  if (devoptab_list[fd] == NULL) {
333  /* nothing mapped on that FD */
334  r->_errno = EBADF;
335  return -1;
336  }
337  if (devoptab_list[fd]->lseek_r == NULL) {
338  /* Function not implemented */
339  r->_errno = ENOSYS;
340  return -1;
341  }
342  /* Call method from device operations table */
343  return devoptab_list[fd]->lseek_r(r, fd, offset, whence);
344 }
345 
346 int
347 _fstat_r(struct _reent *r, int fd, struct stat *st) {
348 
349  if (fd < 0) {
350  /* invalid file descriptor */
351  r->_errno = EBADF;
352  return -1;
353  }
354 
355  if (fd >= MAX_OPEN_DEVICES) {
356  /* CFS file */
357  st->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; /* regular file, 0777 perms (-rwxrwxrwx) */
358  /** \todo Handle file size with fstat */
359  /* st->st_uid = 0; */
360  /* st->st_gid = 0; */
361  /* st->st_size = 0; */
362  return 0;
363  }
364  if (devoptab_list[fd] != NULL) {
365  /* Check device operations table to determine mode */
366  st->st_mode = devoptab_list[fd]->st_mode;
367  return 0;
368  } else {
369  /* nothing mapped on that FD */
370  r->_errno = EBADF;
371  return -1;
372  }
373 }
374 
375 int
376 _isatty_r(struct _reent *r, int fd) {
377 
378  if (fd < 0) {
379  /* invalid file descriptor */
380  r->_errno = EBADF;
381  return -1;
382  }
383 
384  if (fd >= MAX_OPEN_DEVICES) {
385  /* CFS file, not a TTY */
386  r->_errno = ENOTTY;
387  return 0;
388  }
389  if (devoptab_list[fd] != NULL) {
390  /* Check device operations table to determine if it is considered a TTY */
391  if (devoptab_list[fd]->isatty == 0) {
392  r->_errno = ENOTTY;
393  }
394  return devoptab_list[fd]->isatty;
395  } else {
396  /* nothing mapped on that FD */
397  r->_errno = EBADF;
398  return -1;
399  }
400 }
401 
402 /* Compatibility define for newlib built without REENTRANT_SYSCALLS_PROVIDED */
403 int
404 _isatty(int fd)
405 {
406  /* _REENT is an internal newlib macro, this may cause issues in some situations. */
407  return _isatty_r (_REENT, fd);
408 }
409 
410 /* **************************** */
411 /* File system related syscalls */
412 /* **************************** */
413 
414 int
415 _stat_r(struct _reent *r, const char *file, struct stat *st) {
416  /* not supported, yet */
417  (void)file; /* Suppress compiler warnings about unused parameters */
418  (void)st;
419  r->_errno = ENOENT;
420  return -1;
421 }
422 
423 int
424 _link_r(struct _reent *r, const char *old, const char *new)
425 {
426  /* not supported, yet */
427  (void)old; /* Suppress compiler warnings about unused parameters */
428  (void)new;
429  r->_errno = EMLINK;
430  return -1;
431 }
432 
433 int
434 _unlink_r(struct _reent *r, const char *name)
435 {
436  /* not supported, yet */
437  (void)name; /* Suppress compiler warnings about unused parameters */
438  r->_errno = ENOENT;
439  return -1;
440 }
441 
442 /* ********************************** */
443 /* Memory management related syscalls */
444 /* ********************************** */
445 
446 /* Beginning of unallocated RAM, defined by the linker script */
447 /* extern int _end; */
448 extern int _heap_start;
449 /* End of RAM area available for allocation */
450 extern int _heap_end;
451 /* Current edge of dynamically allocated space */
452 static void* current_break = (void *)(&_heap_start);
453 
454 /**
455  * Move the program break.
456  *
457  * This function can increase the size of the allocated memory.
458  *
459  * NEVER call this from ISRs (or anything that may call this function, e.g. malloc, free).
460  */
461 void* _sbrk_r(struct _reent *r, ptrdiff_t increment) {
462  void* ret;
463  /* Make sure we have exclusive access to the system break variable. */
464  lock_acquire(&sbrk_lock);
465  /* Align memory increment to nearest DYNAMIC_MEMORY_ALIGN bytes upward */
466  if (increment % DYNAMIC_MEMORY_ALIGN)
467  {
468  increment += DYNAMIC_MEMORY_ALIGN - (increment % DYNAMIC_MEMORY_ALIGN);
469  }
470  if ((current_break + increment) < ((void *)(&_heap_end)))
471  {
472  ret = current_break;
473  current_break += increment;
474  }
475  else
476  {
477  r->_errno = ENOMEM;
478  ret = (void*)-1;
479  }
480  lock_release(&sbrk_lock);
481  return ret;
482 }
File-like I/O device operations table.
__STATIC_INLINE void NVIC_SystemReset(void)
System Reset.
Definition: core_cm0.h:638
int cfs_open(const char *name, int flags)
Open a file.
Definition: cfs-coffee.c:996
Device I/O mappings for the Mulle platform.
cfs_offset_t cfs_seek(int fd, cfs_offset_t offset, int whence)
Seek to a specified position in an open file.
Definition: cfs-coffee.c:1042
#define CFS_WRITE
Specify that cfs_open() should open a file for writing.
Definition: cfs.h:104
#define NULL
The null pointer.
void * _sbrk_r(struct _reent *r, ptrdiff_t increment)
Move the program break.
#define CFS_READ
Specify that cfs_open() should open a file for reading.
Definition: cfs.h:90
K60 hardware register header wrapper.
#define DEBUGGER_BREAK(sig)
Make the CPU signal to the debugger and break execution by issuing a bkpt instruction.
Definition: K60.h:164
void lock_release(lock_t *Lock_Variable)
Release a lock after having acquired it using lock_acquire or lock_try_acquire.
pid_t _getpid(void)
#define CFS_APPEND
Specify that cfs_open() should append written data to the file rather than overwriting it...
Definition: cfs.h:118
void lock_acquire(lock_t *Lock_Variable)
Blocking access to lock variable.
volatile uint8_t lock_t
Lock variable typedef.
Synchronization primitives for Cortex-M3/M4 processors.
int _fstat_r(struct _reent *r, int fd, struct stat *st)
#define MAX_OPEN_DEVICES
Maximum number of file descriptors allocated to hardware devices.
Definition: devicemap.h:50
void cfs_close(int fd)
Close an open file.
Definition: cfs-coffee.c:1032
CFS header file.