shithub: drawcpu

ref: eff99e9be0f63c0cc54146e21af5bd423238c226
dir: /kern/sysproc.c/

View raw version
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "proc.h"
#include "user.h"
#include "mem.h"
#include "sys.h"
#include <a.out.h>
#include <signal.h>
#include <sys/mman.h>
#include <setjmp.h>

#undef rfork
#undef read
jmp_buf exec_jmp;

static void
nop(int x)
{
    USED(x);
}

static u32int
arg(int n)
{
	/* no locking necessary, since we're on the stack */
	return *(u32int*) vaddrnol(up->R[13] + 4 + 4 * n, 4);
}

int
sysrfork(int flags)
{
    int pid, status;
    int p[2];
    int n;
    char buf[128], *q;
    extern char **environ;
    struct sigaction oldchld;

    memset(&oldchld, 0, sizeof oldchld);

    if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
        flags &= ~(RFPROC|RFFDG|RFENVG);
        n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
        if(n){
            werrstr("unknown flags %08ux in rfork", n);
            return -1;
        }
        if(flags&RFNOWAIT){
            sigaction(SIGCHLD, nil, &oldchld);
            signal(SIGCHLD, nop);
            if(pipe(p) < 0)
                return -1;
        }
        pid = fork();
        if(pid == -1)
            return -1;
        if(flags&RFNOWAIT){
            flags &= ~RFNOWAIT;
            if(pid){
                close(p[1]);
                status = 0;
                if(wait4(pid, &status, 0, 0) < 0){
                    werrstr("pipe dance - wait4 - %r");
                    close(p[0]);
                    return -1;
                }
                n = readn(p[0], buf, sizeof buf-1);
                close(p[0]);
                if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
                    if(!WIFEXITED(status))
                        werrstr("pipe dance - !exited 0x%ux", status);
                    else if(WEXITSTATUS(status) != 0)
                        werrstr("pipe dance - non-zero status 0x%ux", status);
                    else if(n < 0)
                        werrstr("pipe dance - pipe read error - %r");
                    else if(n == 0)
                        werrstr("pipe dance - pipe read eof");
                    else
                        werrstr("pipe dance - unknown failure");
                    return -1;
                }
                buf[n] = 0;
                if(buf[0] == 'x'){
                    werrstr("%s", buf+2);
                    return -1;
                }
                pid = strtol(buf, &q, 0);
            }else{
                signal(SIGCHLD, SIG_IGN);
                close(p[0]);
                pid = fork();
                if(pid){
                    if(pid > 0)
                        print("%d\n", pid);
                    else
                        print("x %r\n");
                    close(p[1]);
                    _exit(0);
                }else{
                    close(p[1]);
                }
            }
            sigaction(SIGCHLD, &oldchld, nil);
        }
        if(pid != 0)
            return pid;
        if(flags&RFCENVG)
            if(environ)
                *environ = nil;
    }
    if(flags&RFPROC){
        werrstr("cannot use rfork for shared memory -- use libthread");
        return -1;
    }
    if(flags&RFNAMEG){
        flags &= ~RFNAMEG;
    }
    if(flags&RFNOTEG){
        setpgid(0, getpid());
        flags &= ~RFNOTEG;
    }
    if(flags&RFNOWAIT){
        werrstr("cannot use RFNOWAIT without RFPROC");
        return -1;
    }
    if(flags){
        werrstr("unknown flags %08ux in rfork", flags);
        return -1;
    }
    return 0;
}

static int
shargs(char *s, int n, char **ap, int nap)
{
    char *p;
    int i;

    if(n <= 2 || s[0] != '#' || s[1] != '!')
        return -1;
    s += 2;
    n -= 2;
    if((p = memchr(s, '\n', n)) == nil)
        return 0;
    *p = 0;
    i = tokenize(s, ap, nap-1);
    ap[i] = nil;
    return i;
}

ulong
beswal(ulong l)
{
    uchar *p;
    p = (uchar*)&l;
    return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}

uvlong
beswav(uvlong v)
{
    uchar *p;
    p = (uchar*)&v;
    return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
           | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
           | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
           | (uvlong)p[7];
}

void*
vmemchr(void *s, int c, ulong n)
{
    uintptr a;
    ulong m, i;
    void *t;

    i = n;
    a = (uintptr)s;
    for(;;){
        m = BY2PG - (a & (BY2PG-1));
        if(i <= m)
            break;
        t = memchr((void*)a, c, m);
        if(t != nil)
            return t;
        a += m;
        i -= m;
        if(a < KZERO)
            validaddr(a, 1, 0);
    }
    return memchr((void*)a, c, i);
}

void
addnote(char *msg)
{
	int new;
	
	new = up->notein + 1;
	if((new - up->noteout) % NNOTE == 0)
		return;

	strncpy(up->notes[up->notein % NNOTE], msg, ERRMAX - 1);
	up->notein = new;
}

void
donote(char *msg, ulong type)
{
    int rc;
    u32int *ureg, *sp, uregp, msgp;
    char *msgb;

    if(up->notehandler == 0)
        exits(msg);

    clrex();
    uregp = up->R[13] - 18 * 4;
    ureg = vaddrnol(uregp, 18 * 4);
    memcpy(ureg, up->R, 15 * 4);
    ureg[15] = type;
    ureg[16] = up->CPSR;
    ureg[17] = up->R[15];
    up->R[13] = uregp;
    msgp = up->R[13] -= ERRMAX;
    msgb = vaddrnol(msgp, ERRMAX);
    strncpy(msgb, msg, ERRMAX);
    up->R[13] -= 3 * 4;
    sp = vaddrnol(up->R[13], 3 * 4);
    sp[0] = 0;
    sp[2] = msgp;
    up->R[0] = uregp;
    up->R[15] = up->notehandler;
    up->innote = 1;
    switch(rc = setjmp(up->notejmp) - 1) {
    case -1:
        for(;;) {
            step();
        }
    case NDFLT:
        exits(msg);
    case NCONT:
        break;
    default:
        sysfatal("unhandled noted argument %d", rc);
    }
    up->innote = 0;
    ureg = vaddrnol(uregp, 18 * 4); /* just to be sure */
    memcpy(up->R, ureg, 15 * 4);
    up->CPSR = ureg[16];
    up->R[15] = ureg[17];
}

static void
initstack(int argc, char **argv)
{
    ulong tos, sp, ap, size, i, len;
    
    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
    sp = tos;
    
    size = 8;
    for(i = 0; i < argc; i++)
        size += strlen(argv[i]) + 5;
    
    sp -= size;
    sp &= ~7;
    up->R[0] = tos;
    up->R[1] = USTKTOP - 4;
    up->R[13] = sp;

	*(ulong *) vaddrnol(sp, 4) = argc;
    sp += 4;
    ap = sp + (argc + 1) * 4;
    for(i = 0; i < argc; i++) {
        *(ulong *) vaddrnol(sp, 4) = ap;
        sp += 4;
        len = strlen(argv[i]) + 1;
        memcpy(vaddrnol(ap, len), argv[i], len);
        ap += len;
    }
    *(ulong *) vaddrnol(sp, 4) = 0;
    inittos();

}

void
inittos(void)
{
    ulong tos;

    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
    ((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
}

static int
loadscript(Chan *tc, char *file, int argc, char **argv)
{
    char buf[513], *p, **q, **nargv;
    int rc, nargc, i;
    
	rc = devtab[tc->type]->read(tc, &buf, 512, 0);
    if(rc <= 0)
        goto invalid;

    buf[rc] = 0;
    p = strchr(buf, '\n');
    if(p == nil)
        goto invalid;
    *p = 0;
    while(isspace(*--p))
        *p = 0;
    nargc = 0;
    p = buf + 2;
    while(*p) {
        while(*p && isspace(*p))
            p++;
        nargc++;
        while(*p && !isspace(*p))
            p++;
    }
    if(nargc == 0)
        goto invalid;
    nargv = mallocz(sizeof(char *) * (nargc + argc), 1);
    q = nargv;
    p = buf + 2;
    while(*p) {
        while(*p && isspace(*p))
            p++;
        *(p-1) = 0;
        *q++ = p;
        while(*p && !isspace(*p))
            p++;
    }
    *q++ = file;
    for(i = 1; i < argc; i++)
        *q++ = argv[i];
    rc = loadtext(*nargv, argc + nargc, nargv);
    free(nargv);
    return rc;

invalid:
    werrstr("exec header invalid");
    return -1;
}

int
loadtext(char *file, int argc, char **argv)
{
    Chan *tc;
    Segment *text, *data, *bss;
    Exec hdr;
	char buf[2];
    vlong off;
    int n;
    
    /* Open the file using namespaced access */
    tc = namec(file, Aopen, OEXEC, 0);
    if(tc == nil) {
        print("cannot open %s: %r", file);
        return -1;
    }
    
	/* Peek the first two bytes */
	devtab[tc->type]->read(tc, &buf, 2, 0);
	if(buf[0] =='#' && buf[1] == '!') {
		return loadscript(tc, file, argc, argv);
	}

    n = devtab[tc->type]->read(tc, &hdr, sizeof(Exec), 0);
    if(n != sizeof(Exec)) {
        print("short read on exec header");
        cclose(tc);
        return -1;
    }
    
    if(beswal(hdr.magic) != E_MAGIC) {
        print("bad magic number in exec header: got 0x%lux, want 0x%lux", beswal(hdr.magic), E_MAGIC);
        cclose(tc);
        return -1;
    }

    freesegs();
    up->CPSR = 0;
    
    /* Create segments: text, data, bss, stack */
    text = newseg(beswal(hdr.entry), beswal(hdr.text) + sizeof(Exec), SEGTEXT);
    data = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec), beswal(hdr.data), SEGDATA);
    bss = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec) + beswal(hdr.data), beswal(hdr.bss), SEGBSS);
    newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, SEGSTACK);

    /* Read text segment (including header) */
    off = sizeof(Exec);
    n = devtab[tc->type]->read(tc, text->data, beswal(hdr.text) + sizeof(Exec), off);
    if(n != beswal(hdr.text) + sizeof(Exec)) {
        freesegs();
        werrstr("short read on text segment: got %d, want %lud", n, beswal(hdr.text) + sizeof(Exec));
        cclose(tc);
        return -1;
    }
    
    /* Read data segment */
    off += beswal(hdr.text);
    n = devtab[tc->type]->read(tc, data->data, beswal(hdr.data), off);
    if(n != beswal(hdr.data)) {
        freesegs();
        werrstr("short read on data segment: got %d, want %lud", n, beswal(hdr.data));
        cclose(tc);
        return -1;
    }
    
    memset(bss->data, 0, bss->size);
    up->R[15] = beswal(hdr.entry);

    initstack(argc, argv);

    //if(debug)
        print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
    
    /* Close the channel */
    cclose(tc);
    resetvfp();
    
    return 0;
}