sys.c

来自「realview22.rar」· C语言 代码 · 共 517 行

C
517
字号
/*
 * Implementation of the full _sys() layer for Linux.
 */

#include <stddef.h> /* for size_t */
#include <errno.h>
#include <stdio.h>
#include <assert.h>

#include <rt_misc.h>
#include <rt_sys.h>

#include "asm/unistd.h"
#include "linux/types.h"
#include "linux/stat.h"
#include "linux/fcntl.h"
#include "linux/termios.h"
#include "linux/ioctl.h"

/*
 * I couldn't include "linux/time.h" due to absence of asm/arch
 * subdir, so I'll have to make these up myself
 */
struct timeval {
    long tv_sec;
    long tv_usec;
};
struct timezone {
    int  tz_minuteswest;
    int  tz_dsttime;
};

struct tms {
    clock_t tms_utime;
    clock_t tms_stime;
    clock_t tms_cutime;
    clock_t tms_cstime;
};

/*
 * These system calls are direct definitions of the kernel SWI
 * interface. This means they report errors in the way the actual
 * kernel syscalls do, which is to return specific negative values
 * such as -EFAULT and -ENOENT. Traditionally C libraries surround
 * each raw syscall with a wrapper function which notices negative
 * values and sets errno appropriately. Since these syscalls are
 * only used within this module, though, we don't need to bother
 * with this.
 */

#ifdef __thumb
#define DEF_SYSCALL_START(name)  __swi_indirect_r7(0) SWI_##name(unsigned,
#define CALL_SYSCALL_START(name) SWI_##name(__NR_##name,
#define DEF_SYSCALL_END          )
#define CALL_SYSCALL_END         )
#define DEF_SYSCALL_0(name)  __swi_indirect_r7(0) SWI_##name(unsigned)
#define CALL_SYSCALL_0(name) SWI_##name(__NR_##name)
#else
#define DEF_SYSCALL_START(name)  __swi(__NR_##name) SWI_##name(
#define CALL_SYSCALL_START(name) SWI_##name(
#define DEF_SYSCALL_END          )
#define CALL_SYSCALL_END         )
#define DEF_SYSCALL_0(name)  __swi(__NR_##name) SWI_##name()
#define CALL_SYSCALL_0(name) SWI_##name()
#endif

#define SYSCALL0(type,name) \
    ({DEF_SYSCALL_0(name); \
      CALL_SYSCALL_0(name); })

#define SYSCALL1(type,name,type1,arg1) \
    ({DEF_SYSCALL_START(name) type1 DEF_SYSCALL_END; \
      CALL_SYSCALL_START(name) arg1 CALL_SYSCALL_END; })

#define SYSCALL2(type,name,type1,arg1,type2,arg2) \
    ({DEF_SYSCALL_START(name) type1, type2 DEF_SYSCALL_END; \
      CALL_SYSCALL_START(name) arg1, arg2 CALL_SYSCALL_END; })

#define SYSCALL3(type,name,type1,arg1,type2,arg2,type3,arg3) \
    ({DEF_SYSCALL_START(name) type1, type2, type3 DEF_SYSCALL_END; \
      CALL_SYSCALL_START(name) arg1, arg2, arg3 CALL_SYSCALL_END; })

#define SYSCALL4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
    ({DEF_SYSCALL_START(name) type1, type2, type3, type4 DEF_SYSCALL_END; \
      CALL_SYSCALL_START(name) arg1, arg2, arg3, arg4 CALL_SYSCALL_END; })

#define ioctl(d, request, term) \
SYSCALL3(int,ioctl,int,d,int,request,void *,term)

#define open(pathname, flags, mode) \
SYSCALL3(int,open,const char *,pathname,int,flags,mode_t,mode)

#define close(fd) \
SYSCALL1(int,close,int,fd)

#define read(fd, buf, count) \
SYSCALL3(ssize_t,read,int,fd,void *,buf,size_t,count)

#define write(fd, buf, count) \
SYSCALL3(long,write,int,fd,const void *,buf,size_t,count)

#define lseek(fildes, offset, whence) \
SYSCALL3(off_t,lseek,int,fildes,off_t,offset,int,whence)

#define exit(exit_code) \
SYSCALL1(long,exit,int,exit_code)

#define unlink(filename) \
SYSCALL1(int,unlink,const char *,filename)

#define gettimeofday(tv, tz) \
SYSCALL2(int,gettimeofday,struct timeval *,tv,struct timezone *,tz)

#define times(buf) \
SYSCALL1(clock_t,times,struct tms *,buf)

#define rename(oldpath, newpath) \
SYSCALL2(int,rename,const char *,oldpath,const char *,newpath)

#define execve(filename, argv, envp) \
SYSCALL3(int,execve,const char *,filename,char *const *,argv, \
         char *const *, envp)

#define fork() \
SYSCALL0(int,fork)

struct rusage;                         /* we don't need the contents! */

#define wait4(pid, status, options, r) \
SYSCALL4(pid_t,wait4,pid_t,pid,int *,status,int,options,struct rusage *,r)

#define brk(value) \
SYSCALL1(int,brk,int,value)

/* These are set up by __main */
extern int __argc;
extern char **__argv;
extern int __stktop;

#ifdef ttywrch_c

void _ttywrch(int ch)
{
    char c = ch;
    write(2, &c, 1);
}

#endif

#ifdef open_c

static const int mode_map[] = {
    O_RDONLY,                      /* 0:  OPEN_R */
    O_RDWR,                        /* 2:  OPEN_PLUS */
    O_WRONLY | O_CREAT | O_TRUNC,  /* 4:  OPEN_W */
    O_RDWR | O_CREAT | O_TRUNC,    /* 6:  OPEN_PLUS | OPEN_W */
    O_WRONLY | O_APPEND,           /* 8:  OPEN_A */
    O_RDWR | O_APPEND,             /* 10: OPEN_PLUS | OPEN_A */
};

const char __stdin_name[] = "0";
const char __stdout_name[] = "1";
const char __stderr_name[] = "2";

FILEHANDLE _sys_open(const char *name, int openmode)
{
    int ret;

    if (name == __stdin_name)
        return 0;
    else if (name == __stdout_name)
        return 1;
    else if (name == __stderr_name)
        return 2;

    /* I think that Linux doesn't care about text/binary status of the file */
    openmode >>= 1;
    /* Assuming "wa" or "wa+" cannot be specified */
    assert(openmode < 6);

    /* "u+rw,g+rw,o+r" permissions in case the file has to be created */
    ret = open(name, mode_map[openmode], 0664);
    if (ret < 0)
        ret = -1;
    return ret;
}

#endif

#ifdef close_c

int _sys_close(FILEHANDLE fh)
{
    /* returns zero on success or -1 on error */
    return close(fh) < 0 ? -1 : 0;
}

#endif

#ifdef read_c

int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)
{
    int read_result;

    if(len == 0) return 0;

    /* read when len > SSIZE_MAX is unspecified -- Where's SSIZE_MAX??? */

    read_result = read(fh,buf,len);
    /* we get the number of bytes read, or -1 for an error. */
    if(read_result < 0)
        return -1;

    /* we return something entirely different. */
    return ((read_result < len) ? 0x80000000 : 0) | (len - read_result);
}

#endif

#ifdef write_c

int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
{
    int write_result;

    if(len == 0) return 0;
    /* actually, the results of writing to a special file aren't portable, but
       i'm guessing we don't care about that for now. */

    write_result = write(fh,buf,len);

    if(write_result < 0)
        return -1;

    return (len - write_result);
}

#endif

#ifdef ensure_c

int _sys_ensure(FILEHANDLE fh)
{
    return 0;
}

#endif

#ifdef flen_c

long _sys_flen(FILEHANDLE fh)
{
    off_t end_pos, cur_pos = lseek(fh,0,SEEK_CUR);
    
    /* If return is -1, there was a seek error...  we've probably destroyed
       the world and everything.  Oh well! */
    if(cur_pos == (off_t)-1)
        return -1;

    end_pos = lseek(fh,0,SEEK_END);
    if(end_pos < 0)
        return -1; /* can't find the end of the file? */

    if(lseek(fh,cur_pos,SEEK_SET) != cur_pos)
        return -1; /* couldn't reset the file pos */

    return end_pos;
}

#endif

#ifdef seek_c

int _sys_seek(FILEHANDLE fh, long pos)
{
    off_t new_pos = lseek(fh,pos,SEEK_SET);

    if(new_pos < 0)
        return -1;

    assert(new_pos == pos);
    return 1;
}

#endif

#ifdef istty_c

int _sys_istty(FILEHANDLE fh)
{
    struct termios term;
    return (ioctl(fh,TCGETS,&term) == 0) ? 1 : 0;
}

#endif

#ifdef exit_c

void _sys_exit(int exit_code) 
{ 
    exit(exit_code); 
}

#endif

#ifdef argv_c

/* override the ARM C library cmd line processing */
__value_in_regs struct __argc_argv __ARM_get_argv(void *allocparam) {
    struct __argc_argv ret;
    char **envp = __argv + (__argc + 1);
    ret.argc = __argc;
    ret.argv = __argv;
    ret.r2 = (int)envp;
    ret.r3 = 0;
    return ret;
}

#endif

#ifdef cmdstr_c

/* We don't need to retarget this, because we've rewritten __ARM_get_argv
 * which calls it. Instead, I'll just reference an undefined symbol here
 * as a sort of link-time-assertion that this function is never required. */
char *_sys_command_string(char *cmd, int len)
{
    extern char *__ARM_THIS_SYMBOL_SHOULD_NEVER_BE_DEFINED;
    return __ARM_THIS_SYMBOL_SHOULD_NEVER_BE_DEFINED;
}

#endif

#ifdef stackheap_c

#pragma import __use_no_semihosting_swi
#pragma import __use_two_region_memory

__value_in_regs struct __initial_stackheap
__user_initial_stackheap(unsigned R0, unsigned SP,
                         unsigned R2, unsigned SL)
{
    struct __initial_stackheap ret;

    ret.heap_base = 0;
    ret.heap_limit = 0;
    ret.stack_base = __stktop;
    ret.stack_limit = __stktop;

    return ret;
}

unsigned __user_heap_extend(int zero, void **base, unsigned requested_size)
{
    static int ourbrk = 0;
    int ret;

    requested_size = (requested_size + 0xFFF) &~ 0xFFF;

    if (!ourbrk)
        ourbrk = brk(0);

    ret = ourbrk;
    ourbrk = brk(ourbrk + requested_size);
    if (ourbrk > ret) {
        assert(ourbrk - ret == requested_size);
        *base = (void *)ret;
        return requested_size;
    } else
        return 0;
}

#endif

#ifdef getenv_c

char *getenv(const char *name)
{
    char **envp = __argv + (__argc + 1);
    while (*envp) {
        char *p;
        const char *q;

        p = *envp;
        q = name;
        while (*q) {
            if (*p != *q)
                break;
            p++, q++;
        }
        if (!*q && *p == '=')
            return p+1;

        envp++;
    }

    return NULL;
}

#endif

#ifdef time_c

time_t time(time_t *timer)
{
    struct timeval tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);
    if (timer) *timer = tv.tv_sec;
    return tv.tv_sec;
}

#endif

#ifdef clock_c

clock_t clock(void)
{
    struct tms tms;

    times(&tms);

    return tms.tms_utime + tms.tms_stime;
}

#endif

#ifdef remove_c

int remove(const char *pathname)
{
    return unlink(pathname) < 0 ? -1 : 0;
}

#endif

#ifdef rename_c

int (rename)(const char *oldname, const char *newname)
{
    return rename(oldname, newname) < 0 ? -1 : 0;
}

#endif

#ifdef system_c

int system(const char *string)
{
    int pid;

    pid = fork();

    if (pid < 0) {                     /* error */
        return -1;
    } else if (pid == 0) {             /* child */
        char *argv[4];
        char **envp = __argv + (__argc + 1);

        argv[0] = "sh";
        argv[1] = "-c";
        argv[2] = (char *)string;
        argv[3] = NULL;

        execve("/bin/sh", argv, envp);

        /* ... and if that failed ... */
        exit(127);
        return -1;                     /* placate compiler; can't be reached */
    } else {                           /* parent */
        int status;
        (void)wait4(pid, &status, 0, NULL);
        return status;
    }
}

#endif

#ifdef tmpnam_c

int _sys_tmpnam(char *name, int fileno, unsigned maxlength)
{
    char *tmpdir;
    int i;
    extern char *getenv(const char *name);

    tmpdir = getenv("TMPDIR");
    if (!tmpdir)
        tmpdir = "/tmp";
    while (maxlength > 0 && *tmpdir)
        maxlength--, *name++ = *tmpdir++;
    if (maxlength > 0)
        maxlength--, *name++ = '/';
    if (maxlength > 0)
        maxlength--, *name++ = 't';
    if (maxlength > 0)
        maxlength--, *name++ = 'm';
    if (maxlength > 0)
        maxlength--, *name++ = 'p';
    for (i = 0; i < 8; i++) {
        char digit = "0123456789ABCDEF"[(fileno >> 28) & 15];
        if (maxlength > 0)
            maxlength--, *name++ = digit;
        fileno <<= 4;
    }

    if (maxlength > 0) {
        *name = '\0';
        return 1;
    } else
        return 0;                      /* failure */
}

#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?