2013-11-07 17:23:08 +01:00
|
|
|
/**
|
|
|
|
* Native CPU syscall managing
|
|
|
|
*
|
|
|
|
* Wrap system calls and system call invoking library calls to make
|
|
|
|
* sure no context switches happen during a system call.
|
|
|
|
*
|
2014-05-15 18:07:02 +02:00
|
|
|
* Copyright (C) 2013 Ludwig Ortmann <ludwig.ortmann@fu-berlin.de>
|
2013-11-07 17:23:08 +01:00
|
|
|
*
|
2013-11-22 20:47:05 +01:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
2013-11-07 17:23:08 +01:00
|
|
|
* Public License. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* @ingroup native_cpu
|
|
|
|
* @{
|
|
|
|
* @file
|
|
|
|
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#else
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <err.h>
|
2013-12-10 12:10:05 +01:00
|
|
|
#include <errno.h>
|
2013-11-07 17:23:08 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
2014-02-25 12:13:34 +01:00
|
|
|
#ifdef MODULE_VTIMER
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
2013-11-07 17:23:08 +01:00
|
|
|
|
|
|
|
#include "cpu.h"
|
2014-01-29 10:55:57 +01:00
|
|
|
#include "irq.h"
|
2014-02-25 12:13:34 +01:00
|
|
|
#include "vtimer.h"
|
2013-11-07 17:23:08 +01:00
|
|
|
|
|
|
|
#include "native_internal.h"
|
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
2014-01-24 18:26:44 +01:00
|
|
|
#if ENABLE_DEBUG
|
|
|
|
#define LOCAL_DEBUG (1)
|
|
|
|
#endif
|
2013-11-07 17:23:08 +01:00
|
|
|
#include "debug.h"
|
|
|
|
|
2014-04-10 22:28:35 +02:00
|
|
|
extern volatile tcb_t *sched_active_thread;
|
2013-11-07 17:23:08 +01:00
|
|
|
|
|
|
|
ssize_t (*real_read)(int fd, void *buf, size_t count);
|
|
|
|
ssize_t (*real_write)(int fd, const void *buf, size_t count);
|
2014-01-24 17:03:01 +01:00
|
|
|
void* (*real_malloc)(size_t size);
|
|
|
|
void (*real_free)(void *ptr);
|
|
|
|
void* (*real_calloc)(size_t nmemb, size_t size);
|
|
|
|
void* (*real_realloc)(void *ptr, size_t size);
|
2014-06-13 23:52:05 +02:00
|
|
|
int (*real_pipe)(int[2]);
|
|
|
|
int (*real_close)(int);
|
2013-11-07 17:23:08 +01:00
|
|
|
|
2014-05-07 12:36:32 +02:00
|
|
|
void _native_syscall_enter(void)
|
2013-11-07 17:23:08 +01:00
|
|
|
{
|
|
|
|
_native_in_syscall++;
|
2014-01-24 18:26:44 +01:00
|
|
|
#if LOCAL_DEBUG
|
|
|
|
real_write(STDERR_FILENO, "> _native_in_syscall\n", 21);
|
|
|
|
#endif
|
2013-11-07 17:23:08 +01:00
|
|
|
}
|
|
|
|
|
2014-05-07 12:36:32 +02:00
|
|
|
void _native_syscall_leave(void)
|
2013-11-07 17:23:08 +01:00
|
|
|
{
|
2014-01-24 18:26:44 +01:00
|
|
|
#if LOCAL_DEBUG
|
|
|
|
real_write(STDERR_FILENO, "< _native_in_syscall\n", 21);
|
|
|
|
#endif
|
2013-11-07 17:23:08 +01:00
|
|
|
_native_in_syscall--;
|
2013-11-20 21:11:41 +01:00
|
|
|
if (
|
|
|
|
(_native_sigpend > 0)
|
|
|
|
&& (_native_in_isr == 0)
|
|
|
|
&& (_native_in_syscall == 0)
|
|
|
|
&& (native_interrupts_enabled == 1)
|
2014-04-10 22:28:35 +02:00
|
|
|
&& (sched_active_thread != NULL)
|
2013-11-20 21:11:41 +01:00
|
|
|
)
|
|
|
|
{
|
2013-11-07 17:23:08 +01:00
|
|
|
_native_in_isr = 1;
|
2014-01-29 10:55:57 +01:00
|
|
|
dINT();
|
2014-04-10 22:28:35 +02:00
|
|
|
_native_cur_ctx = (ucontext_t *)sched_active_thread->sp;
|
2013-11-20 15:39:08 +01:00
|
|
|
native_isr_context.uc_stack.ss_sp = __isr_stack;
|
|
|
|
native_isr_context.uc_stack.ss_size = SIGSTKSZ;
|
|
|
|
native_isr_context.uc_stack.ss_flags = 0;
|
2013-11-07 17:23:08 +01:00
|
|
|
makecontext(&native_isr_context, native_irq_handler, 0);
|
2013-11-20 15:39:08 +01:00
|
|
|
if (swapcontext(_native_cur_ctx, &native_isr_context) == -1) {
|
2014-01-29 10:51:55 +01:00
|
|
|
err(EXIT_FAILURE, "_native_syscall_leave: swapcontext");
|
2013-11-20 15:39:08 +01:00
|
|
|
}
|
2014-01-29 10:55:57 +01:00
|
|
|
eINT();
|
2013-11-07 17:23:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-24 17:03:01 +01:00
|
|
|
void *malloc(size_t size)
|
|
|
|
{
|
|
|
|
void *r;
|
|
|
|
_native_syscall_enter();
|
|
|
|
r = real_malloc(size);
|
|
|
|
_native_syscall_leave();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free(void *ptr)
|
|
|
|
{
|
|
|
|
_native_syscall_enter();
|
|
|
|
real_free(ptr);
|
|
|
|
_native_syscall_leave();
|
|
|
|
}
|
|
|
|
|
2014-02-26 10:43:07 +01:00
|
|
|
int _native_in_calloc;
|
2014-01-24 17:03:01 +01:00
|
|
|
void *calloc(size_t nmemb, size_t size)
|
|
|
|
{
|
2014-02-26 10:43:07 +01:00
|
|
|
/* dynamically load calloc when it's needed - this is necessary to
|
|
|
|
* support profiling as it uses calloc before startup runs */
|
2014-02-22 13:08:45 +01:00
|
|
|
if (!real_calloc) {
|
2014-02-26 10:43:07 +01:00
|
|
|
if (_native_in_calloc) {
|
|
|
|
/* XXX: This is a dirty hack to enable old dlsym versions to run.
|
|
|
|
* Throw it out when Ubuntu 12.04 support runs out (in 2017-04)! */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_native_in_calloc = 1;
|
|
|
|
*(void **)(&real_calloc) = dlsym(RTLD_NEXT, "calloc");
|
|
|
|
_native_in_calloc = 0;
|
|
|
|
}
|
2014-02-22 13:08:45 +01:00
|
|
|
}
|
|
|
|
|
2014-01-24 17:03:01 +01:00
|
|
|
void *r;
|
|
|
|
_native_syscall_enter();
|
|
|
|
r = real_calloc(nmemb, size);
|
|
|
|
_native_syscall_leave();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *realloc(void *ptr, size_t size)
|
|
|
|
{
|
|
|
|
void *r;
|
|
|
|
_native_syscall_enter();
|
|
|
|
r = real_realloc(ptr, size);
|
|
|
|
_native_syscall_leave();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-03-26 13:49:01 +01:00
|
|
|
ssize_t _native_read(int fd, void *buf, size_t count)
|
2013-11-07 17:23:08 +01:00
|
|
|
{
|
|
|
|
ssize_t r;
|
|
|
|
|
|
|
|
_native_syscall_enter();
|
|
|
|
r = real_read(fd, buf, count);
|
|
|
|
_native_syscall_leave();
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-03-26 13:49:01 +01:00
|
|
|
ssize_t _native_write(int fd, const void *buf, size_t count)
|
2013-11-07 17:23:08 +01:00
|
|
|
{
|
|
|
|
ssize_t r;
|
|
|
|
|
|
|
|
_native_syscall_enter();
|
|
|
|
r = real_write(fd, buf, count);
|
|
|
|
_native_syscall_leave();
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-04-10 14:58:12 +02:00
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
#undef putchar
|
|
|
|
#endif
|
2013-11-07 17:23:08 +01:00
|
|
|
int putchar(int c) {
|
2014-03-26 13:49:01 +01:00
|
|
|
_native_write(STDOUT_FILENO, &c, 1);
|
2013-11-07 17:23:08 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int puts(const char *s)
|
|
|
|
{
|
|
|
|
int r;
|
2014-03-26 13:49:01 +01:00
|
|
|
r = _native_write(STDOUT_FILENO, (char*)s, strlen(s));
|
2013-11-07 17:23:08 +01:00
|
|
|
putchar('\n');
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *make_message(const char *format, va_list argp)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
int size = 100;
|
|
|
|
char *message, *temp;
|
|
|
|
|
|
|
|
if ((message = malloc(size)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
n = vsnprintf(message, size, format, argp);
|
|
|
|
if (n < 0)
|
|
|
|
return NULL;
|
|
|
|
if (n < size)
|
|
|
|
return message;
|
|
|
|
size = n + 1;
|
|
|
|
if ((temp = realloc(message, size)) == NULL) {
|
|
|
|
free(message);
|
|
|
|
return NULL;
|
2014-02-16 20:50:48 +01:00
|
|
|
}
|
|
|
|
else {
|
2013-11-07 17:23:08 +01:00
|
|
|
message = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int printf(const char *format, ...)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
va_list argp;
|
|
|
|
char *m;
|
|
|
|
|
|
|
|
va_start(argp, format);
|
|
|
|
if ((m = make_message(format, argp)) == NULL) {
|
|
|
|
err(EXIT_FAILURE, "malloc");
|
|
|
|
}
|
2014-03-26 13:49:01 +01:00
|
|
|
r = _native_write(STDOUT_FILENO, m, strlen(m));
|
2013-11-07 17:23:08 +01:00
|
|
|
va_end(argp);
|
|
|
|
free(m);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int vprintf(const char *format, va_list argp)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
char *m;
|
|
|
|
|
|
|
|
if ((m = make_message(format, argp)) == NULL) {
|
|
|
|
err(EXIT_FAILURE, "malloc");
|
|
|
|
}
|
2014-03-26 13:49:01 +01:00
|
|
|
r = _native_write(STDOUT_FILENO, m, strlen(m));
|
2013-11-07 17:23:08 +01:00
|
|
|
free(m);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2013-12-10 12:10:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
void vwarn(const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
char *m, *e;
|
|
|
|
|
|
|
|
e = strerror(errno);
|
|
|
|
|
|
|
|
if ((m = make_message(fmt, args)) == NULL) {
|
2014-03-26 13:49:01 +01:00
|
|
|
_native_write(STDERR_FILENO, "malloc\n", 7);
|
2013-12-10 12:10:05 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-03-26 13:49:01 +01:00
|
|
|
_native_write(STDERR_FILENO, _progname, strlen(_progname));
|
|
|
|
_native_write(STDERR_FILENO, ": ", 2);
|
|
|
|
_native_write(STDERR_FILENO, m, strlen(m));
|
|
|
|
_native_write(STDERR_FILENO, ": ", 2);
|
|
|
|
_native_write(STDERR_FILENO, e, strlen(e));
|
|
|
|
_native_write(STDERR_FILENO, "\n", 1);
|
2013-12-10 12:10:05 +01:00
|
|
|
free(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vwarnx(const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
char *m;
|
|
|
|
|
|
|
|
if ((m = make_message(fmt, args)) == NULL) {
|
2014-03-26 13:49:01 +01:00
|
|
|
_native_write(STDERR_FILENO, "malloc\n", 7);
|
2013-12-10 12:10:05 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-03-26 13:49:01 +01:00
|
|
|
_native_write(STDERR_FILENO, _progname, strlen(_progname));
|
|
|
|
_native_write(STDERR_FILENO, ": ", 2);
|
|
|
|
_native_write(STDERR_FILENO, m, strlen(m));
|
|
|
|
_native_write(STDERR_FILENO, "\n", 1);
|
2013-12-10 12:10:05 +01:00
|
|
|
free(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void verr(int eval, const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
vwarn(fmt, args);
|
|
|
|
exit(eval);
|
|
|
|
}
|
|
|
|
|
|
|
|
void verrx(int eval, const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
vwarnx(fmt, args);
|
|
|
|
exit(eval);
|
|
|
|
}
|
|
|
|
|
|
|
|
void warn(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argp;
|
|
|
|
va_start(argp, fmt);
|
|
|
|
vwarn(fmt, argp);
|
|
|
|
va_end(argp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void warnx(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argp;
|
|
|
|
va_start(argp, fmt);
|
|
|
|
vwarnx(fmt, argp);
|
|
|
|
va_end(argp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void err(int eval, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argp;
|
|
|
|
va_start(argp, fmt);
|
|
|
|
verr(eval, fmt, argp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void errx(int eval, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argp;
|
|
|
|
va_start(argp, fmt);
|
|
|
|
verrx(eval, fmt, argp);
|
|
|
|
}
|
2014-02-25 12:13:34 +01:00
|
|
|
|
2014-05-14 16:53:46 +02:00
|
|
|
int getpid(void)
|
2014-05-13 17:41:36 +02:00
|
|
|
{
|
|
|
|
warnx("not implemented");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-25 12:13:34 +01:00
|
|
|
#ifdef MODULE_VTIMER
|
|
|
|
int _gettimeofday(struct timeval *tp, void *restrict tzp) {
|
|
|
|
(void) tzp;
|
|
|
|
vtimer_gettimeofday(tp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|