/************** syscall routing table ***********/ int kcinth() { u16 x, y, z, w, r; u16 seg, off; seg = running->uss; off = running->usp; x = get_word(seg, off+13*2); y = get_word(seg, off+14*2); z = get_word(seg, off+15*2); w = get_word(seg, off+16*2); switch(x){ case 0 : r = running->pid; break; case 1 : r = kps(); break; case 2 : r = chname(y); break; case 3 : r = kmode(); break; case 4 : r = tswitch(); break; case 5 : r = kwait(); break; case 6 : r = kexit(); break; case 7 : r = fork(); break; case 8 : r = kexec(y); break; case 9 : r = sout(y); break; case 10: r = sin(y); break; case 99: r = kexit(); break; default: printf("invalid syscall # : %d\n", x); } put_word(r, seg, off+2*8); }
int body() { char c; int event; while(1){ printf("\n***************************************\n"); print(); printf("\nI am task %d My parent=%d\n", running->pid, running->ppid); printf("input a char [fork:f|switch:s|exit:q|sleep:z|wakeup:a|wait:w] : "); c = getchar(); switch(c){ case 'f': kfork(); break; case 's': tswitch(); break; case 'q': kexit(0); break; case 'z': {printf("enter event to put process to sleep"); scanf("%d",&event); ksleep(event);} break; case 'a': {printf("enter event to wake up process"); scanf("%d",&event); kwakeup(event);} break; case 'w': kwait(0); break; default: printf("invalid char\n"); break; } } return; }
/* * Newly forked processes start executing at forkret. * The very first process, init, starts executing at touser(sp), * where sp is its stack pointer. */ void forkret(void) { extern void kexit(Ureg*); kexit(nil); touser(0); }
int kkexit(int value) { if(running->pid == 1 && nproc > 2){ printf("other procs still exist, P1 can't die yet !%c\n",007); return -1; } kexit(value); }
int do_exit(){ int val; char c; printf("Enter an exit value (0-9): "); c = getc(); val = c-'0'; kexit(val); }
do_exit(){ int val = 0; bzero(buf, BUF_SIZE); printf("enter exitValue: "); gets(buf); val = atoi(buf); //printf("exitValue: %d\n", val); kexit(val); }
int do_exit() { int exitValue; if (running->pid == 1 && nproc > 2){ printf("other killMods still exist, P1 can't die yet !%c\n",007); return -1; } printf("enter an exitValue : "); exitValue = geti(); printf("\n"); kexit(exitValue); }
/** * Handles a request for a task. * */ int handle(Task *task, Request *req) { // Handle Interrupts. if (req == 0) { int data; int event = process_interrupt(&data); kevent(event, data); make_ready(task); return 0; } // Handle System Calls. switch (req->request) { case MY_TID: kmytid(task); break; case CREATE: kcreate(task, (int)req->args[0] /* priority */, req->args[1] /* code */, (int)req->args[2] /* args */); break; case MY_PARENT_TID: kmy_parent_tid(task); break; case PASS: make_ready(task); break; case EXIT: kexit(task); break; case SEND: ksend(task, (int)req->args[0], (char *)req->args[1], (int)req->args[2], (char *)req->args[3], (int)req->args[4]); break; case RECEIVE: krecieve(task, (int *)req->args[0], (char *)req->args[1], (int)req->args[2]); break; case REPLY: kreply(task, (int)req->args[0], (char *)req->args[1], (int)req->args[2]); break; case AWAIT_EVENT: kawait(task, (int)req->args[0]); break; case WAIT_TID: kwait_tid(task, (int)req->args[0]); break; case SHUTDOWN: return -1; default: bwprintf(COM2, "Undefined request number %u\n", req->request); break; } return 0; }
int do_exit(){ int exitValue; char buf[32]; printf("please enter an exitValue: "); gets(buf); exitValue = stoi(buf); printf("\nExiting with %d...\n", exitValue); kexit(exitValue); }
int do_exit(int exitValue) { //int exitValue; if (running->pid == 1 && nproc > 2){ printf("other procs still exist, P1 can't die yet !%c\n",007); return -1; } /*************************************** printf("enter an exitValue (0-9) : "); exitValue = (getc()&0x7F) - '0'; printf("%d\n", exitValue); **************************************/ kexit(exitValue); }
int kwait_tid_test() { reset(); kexit(t0); vassert(t0->state == ZOMBIE); // Shouldn't block when calling wait on ZOMBIE task kwait_tid(t1, t0->tid); vassert(t1->state == READY); vassert(task_get_return_value(t1) == 0); vassert(t0->state == ZOMBIE); // Should block on non zombie. kwait_tid(t1, t2->tid); vassert(t2->state != ZOMBIE); vassert(t1->state == WAIT_BLOCKED); // Should unblock when non zombie exits. kexit(t2); vassert(t2->state == ZOMBIE); vassert(t1->state == READY); return 0; }
int ksend_transaction_failed() { reset(); char *msg = "Hello!"; int msglen = 7; char reply[5]; int replylen = 5; ksend(t0, t1->tid, msg, msglen, reply, replylen); vassert(t0->state == SEND_BLOCKED); kexit(t1); vassert(t0->state == READY); vassert(task_get_return_value(t0) == -3); vassert(t1->state == ZOMBIE); return 0; }
int system( char * path, /* Path to the executable to run */ int argc, /* Argument count (ie, /bin/echo hello world = 3) */ char ** argv /* Argument strings (including executable path) */ ) { int child = fork(); if (child == 0) { char * env[] = {NULL}; exec(path,argc,argv,env); debug_print(ERROR, "Failed to execute process!"); kexit(-1); return -1; } else { switch_next(); return -1; } }
int write_pipe(int fd, char *buf, int n) { char c; int r=0; PIPE *p; OFT *op; if (fd < 0 || fd > NFD || running->fd[fd] == 0){ printf("bad fd %d\n", fd); return -1; } op = running->fd[fd]; if (op->mode != WRITE_PIPE){ printf("fd = %d is NOT for write\n", fd); return -1; } p = op->pipe_ptr; printf("pipe before writing\n"); show_pipe(p); while(n){ if (!p->nreader){ // no more readers printf("proc %d : BROKEN_PIPE error\n", running->pid); kexit(0x0D); // simulate SIGPIPE=13 } while(p->room && n){ p->buf[p->head++] = get_byte(running->uss, buf); p->head %= PSIZE; p->data++; p->room--; n--; r++; buf++; } kwakeup(&p->data); // wakeup ALL readers, if any. if (n==0){ printf("pipe after writing\n"); show_pipe(p); return r; // finished writing n bytes } // still has data to write but pipe has no room printf("pipe before writer goes to sleep\n"); show_pipe(p); ksleep(&p->room); // sleep for room } return r; }
int kcinth() { u16 segment, offset; int a,b,c,d,r; segment = running->uss; offset = running->usp; a = get_word(segment, offset + 2*PA); b = get_word(segment, offset + 2*(PA+1)); c = get_word(segment, offset + 2*(PA+2)); d = get_word(segment, offset + 2*(PA+3)); switch(a) { case 0: r = getpid(); break; case 1: r = kps(); break; case 2: k = kchname(); break; case 3: r = kkfork(); break; case 4: r = kswitch(); break; case 5: r = kwait(b); break; case 6: kexit(); break; default: printf("invalid syscall %d\n", a); } put_word(r, segment, offset + 2*AX); }
int body() { char c, CR, buf[64]; while(1){ printf("=======================================\n"); printQueue(readyQueue); printf("proc %d %s in Kmode\n", running->pid, running->name); printf("input a command (s|f|u|q|i|o) : "); c=getc(); putc(c); CR=getc(); putc(CR); switch(c){ case 's' : tswitch(); break; case 'u' : printf("\nProc %d ready to go U mode\n", running->pid); goUmode(); break; case 'f': fork(); break; case 'q' : kexit(); break; case 'i' : iline(); break; case 'o' : oline(); break; } } }
int system( char * path, /* Path to the executable to run */ int argc, /* Argument count (ie, /bin/echo hello world = 3) */ char ** argv /* Argument strings (including executable path) */ ) { char ** argv_ = malloc(sizeof(char *) * (argc + 1)); for (int j = 0; j < argc; ++j) { argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char)); memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); } argv_[argc] = 0; char * env[] = {NULL}; set_process_environment((process_t*)current_process, clone_directory(current_directory)); current_directory = current_process->thread.page_directory; switch_page_directory(current_directory); exec(path,argc,argv_,env); debug_print(ERROR, "Failed to execute process!"); kexit(-1); return -1; }
int body() { char c; printf("proc %d resumes to body()\n", running->pid); while(1) { printLists(); printf("proc %d[%d] running: parent=%d\n", running->pid, running->priority, running->ppid); printf("enter a char [Debug|Fork|Umode|Ps|Quit|Sleep|Wait] : "); c = getc(); printf("%c\n", c); switch(c) { case 's' : tswitch(); break; case 'f' : kfork(); break; case 'q' : kexit(); break; case 'p' : kps(); break; case 'w' : kwait(); break; case 'd' : debugStatement(); break; case 'u' : goUmode(); break; } } }
/* * Cleanup done by runacore to pretend we are going back to user space. * We won't return and won't do what syscall() would normally do. * Do it here instead. */ static void fakeretfromsyscall(Ureg *ureg) { Proc *up = externup(); int s; poperror(); /* as syscall() would do if we would return */ if(up->procctl == Proc_tracesyscall){ /* Would this work? */ up->procctl = Proc_stopme; s = splhi(); procctl(up); splx(s); } up->insyscall = 0; /* if we delayed sched because we held a lock, sched now */ if(up->delaysched){ sched(); splhi(); } kexit(ureg); }
/* it should be unsigned. FIXME */ void syscall(int badscallnr, Ureg* ureg) { unsigned int scallnr = (unsigned int) badscallnr; char *e; uintptr sp; int s; vlong startns, stopns; Ar0 ar0; static Ar0 zar0; if(!userureg(ureg)) panic("syscall: cs %#llux\n", ureg->cs); cycles(&up->kentry); m->syscall++; up->nsyscall++; up->nqsyscall++; up->insyscall = 1; up->pc = ureg->ip; up->dbgreg = ureg; sp = ureg->sp; startns = 0; if(up->procctl == Proc_tracesyscall){ /* * Redundant validaddr. Do we care? * Tracing syscalls is not exactly a fast path... * Beware, validaddr currently does a pexit rather * than an error if there's a problem; that might * change in the future. */ if(sp < (USTKTOP-BIGPGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE)) validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0); syscallfmt(scallnr, (va_list)(sp+BY2SE)); up->procctl = Proc_stopme; procctl(up); if(up->syscalltrace) free(up->syscalltrace); up->syscalltrace = nil; startns = todget(nil); } up->scallnr = scallnr; if(scallnr == RFORK) fpusysrfork(ureg); spllo(); sp = ureg->sp; up->nerrlab = 0; ar0 = zar0; if(!waserror()){ if(scallnr >= nsyscall || systab[scallnr].f == nil){ pprint("bad sys call number %d pc %#llux\n", scallnr, ureg->ip); postnote(up, 1, "sys: bad sys call", NDebug); error(Ebadarg); } if(sp < (USTKTOP-BIGPGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE)) validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0); memmove(up->arg, UINT2PTR(sp+BY2SE), sizeof(up->arg)); up->psstate = systab[scallnr].n; systab[scallnr].f(&ar0, (va_list)up->arg); if(scallnr == SYSR1){ /* * BUG: must go when ron binaries go. * NIX: Returning from execac(). * This means that the process is back to the * time sharing core. However, the process did * already return from the system call, when dispatching * the user code to the AC. The only thing left is to * return. The user registers should be ok, because * up->dbgreg has been the user context for the process. */ return; } poperror(); } else{ /* failure: save the error buffer for errstr */ e = up->syserrstr; up->syserrstr = up->errstr; up->errstr = e; if(DBGFLG && up->pid == 1) iprint("%s: syscall %s error %s\n", up->text, systab[scallnr].n, up->syserrstr); ar0 = systab[scallnr].r; } /* * NIX: for the execac() syscall, what follows is done within * the system call, because it never returns. * See acore.c:/^retfromsyscall */ noerrorsleft(); /* * Put return value in frame. */ ureg->ax = ar0.p; if(up->procctl == Proc_tracesyscall){ stopns = todget(nil); up->procctl = Proc_stopme; sysretfmt(scallnr, (va_list)(sp+BY2SE), &ar0, startns, stopns); s = splhi(); procctl(up); splx(s); if(up->syscalltrace) free(up->syscalltrace); up->syscalltrace = nil; }else if(up->procctl == Proc_totc || up->procctl == Proc_toac) procctl(up); up->insyscall = 0; up->psstate = 0; if(scallnr == NOTED) noted(ureg, *(uintptr*)(sp+BY2SE)); splhi(); if(scallnr != RFORK && (up->procctl || up->nnote)) notify(ureg); /* if we delayed sched because we held a lock, sched now */ if(up->delaysched){ sched(); splhi(); } kexit(ureg); }
// exits a process int kkexit(int value) { // use your kexit() in LAB3. do NOT let P1 die kexit(value); }
/* * All traps come here. It is slower to have all traps call trap() * rather than directly vectoring the handler. However, this avoids a * lot of code duplication and possible bugs. The only exception is * VectorSYSCALL. * Trap is called with interrupts disabled via interrupt-gates. */ void trap(Ureg* ureg) { int clockintr, vno, user; // cache the previous vno to see what might be causing // trouble static int lastvno; vno = ureg->type; uint64_t gsbase = rdmsr(GSbase); //if (sce > scx) iprint("===================="); if (vno == 8) { iprint("Lstar is %p\n", (void *)rdmsr(Lstar)); iprint("GSbase is %p\n", (void *)gsbase); iprint("ire %d irx %d sce %d scx %d lastvno %d\n", ire, irx, sce, scx, lastvno); iprint("irxe %d \n", irxe); die("8"); } lastvno = vno; if (gsbase < 1ULL<<63) die("bogus gsbase"); Mach *m = machp(); char buf[ERRMAX]; Vctl *ctl, *v; if (0 && m && m->externup && m->externup->pid == 6) { //iprint("type %x\n", ureg->type); if (ureg->type != 0x49) die("6\n"); } m->perf.intrts = perfticks(); user = userureg(ureg); if(user && (m->nixtype == NIXTC)){ m->externup->dbgreg = ureg; cycles(&m->externup->kentry); } clockintr = 0; //_pmcupdate(m); if(ctl = vctl[vno]){ if(ctl->isintr){ m->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) m->lastintr = ctl->irq; }else if(m->externup) m->externup->nqtrap++; if(ctl->isr) ctl->isr(vno); for(v = ctl; v != nil; v = v->next){ if(v->f) v->f(ureg, v->a); } if(ctl->eoi) ctl->eoi(vno); intrtime(vno); if(ctl->isintr){ if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER) clockintr = 1; if(m->externup && !clockintr) preempted(); } } else if(vno < nelem(excname) && user){ spllo(); snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]); postnote(m->externup, 1, buf, NDebug); } else if(vno >= VectorPIC && vno != VectorSYSCALL){ /* * An unknown interrupt. * Check for a default IRQ7. This can happen when * the IRQ input goes away before the acknowledge. * In this case, a 'default IRQ7' is generated, but * the corresponding bit in the ISR isn't set. * In fact, just ignore all such interrupts. */ /* clear the interrupt */ i8259isr(vno); iprint("cpu%d: spurious interrupt %d, last %d\n", m->machno, vno, m->lastintr); intrtime(vno); if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ nmienable(); if(m->machno != 0){ iprint("cpu%d: PC %#llux\n", m->machno, ureg->ip); for(;;); } } dumpregs(ureg); if(!user){ ureg->sp = PTR2UINT(&ureg->sp); dumpstackwithureg(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d\n", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(m->externup && m->externup->delaysched && clockintr){ if(0) if(user && m->externup->ac == nil && m->externup->nqtrap == 0 && m->externup->nqsyscall == 0){ if(!waserror()){ m->externup->ac = getac(m->externup, -1); poperror(); runacore(); return; } } sched(); splhi(); } if(user){ if(m->externup && m->externup->procctl || m->externup->nnote) notify(ureg); kexit(ureg); } }
/* * Move the current process to an application core. * This is performed at the end of execac(), and * we pretend to be returning to user-space, but instead we * dispatch the process to another core. * 1. We do the final bookkeeping that syscall() would do after * a return from sysexec(), because we are not returning. * 2. We dispatch the process to an AC using an ICC. * * This function won't return unless the process is reclaimed back * to the time-sharing core, and is the handler for the process * to deal with traps and system calls until the process dies. * * Remember that this function is the "line" between user and kernel * space, it's not expected to raise|handle any error. * * We install a safety error label, just in case we raise errors, * which we shouldn't. (noerrorsleft knows that for exotic processes * there is an error label pushed by us). */ void runacore(void) { Proc *up = externup(); Ureg *ureg; void (*fn)(void); int rc, flush, s; char *n; uint64_t t1; if(waserror()) panic("runacore: error: %s\n", up->errstr); ureg = up->dbgreg; fakeretfromsyscall(ureg); fpusysrfork(ureg); procpriority(up, PriKproc, 1); rc = runac(up->ac, actouser, 1, nil, 0); procpriority(up, PriNormal, 0); for(;;){ t1 = fastticks(nil); flush = 0; fn = nil; switch(rc){ case ICCTRAP: s = splhi(); machp()->MMU.cr2 = up->ac->MMU.cr2; DBG("runacore: trap %llu cr2 %#llx ureg %#p\n", ureg->type, machp()->MMU.cr2, ureg); switch(ureg->type){ case IdtIPI: if(up->procctl || up->nnote) notify(up->dbgreg); if(up->ac == nil) goto ToTC; kexit(up->dbgreg); break; case IdtNM: case IdtMF: case IdtXF: /* these are handled in the AC; * If we get here, they left in m->NIX.icc->data * a note to be posted to the process. * Post it, and make the vector a NOP. */ n = up->ac->NIX.icc->note; if(n != nil) postnote(up, 1, n, NDebug); ureg->type = IdtIPI; /* NOP */ break; default: cr3put(machp()->MMU.pml4->pa); if(0 && ureg->type == IdtPF){ print("before PF:\n"); print("AC:\n"); dumpptepg(4, up->ac->MMU.pml4->pa); print("\n%s:\n", rolename[NIXTC]); dumpptepg(4, machp()->MMU.pml4->pa); } trap(ureg); } splx(s); flush = 1; fn = actrapret; break; case ICCSYSCALL: DBG("runacore: syscall ax %#llx ureg %#p\n", ureg->ax, ureg); cr3put(machp()->MMU.pml4->pa); //syscall(ureg->ax, ureg); flush = 1; fn = acsysret; if(0) if(up->nqtrap > 2 || up->nsyscall > 1) goto ToTC; if(up->ac == nil) goto ToTC; break; default: panic("runacore: unexpected rc = %d", rc); } up->tctime += fastticks2us(fastticks(nil) - t1); procpriority(up, PriExtra, 1); rc = runac(up->ac, fn, flush, nil, 0); procpriority(up, PriNormal, 0); } ToTC: /* * to procctl, then syscall, to * be back in the TC */ DBG("runacore: up %#p: return\n", up); }
/* * All traps come here. It is slower to have all traps call trap() * rather than directly vectoring the handler. However, this avoids a * lot of code duplication and possible bugs. The only exception is * VectorSYSCALL. * Trap is called with interrupts disabled via interrupt-gates. */ void trap(Ureg* ureg) { int clockintr, vno, user; // cache the previous vno to see what might be causing // trouble vno = ureg->type; uint64_t gsbase = rdmsr(GSbase); //if (sce > scx) iprint("===================="); lastvno = vno; if (gsbase < 1ULL<<63) die("bogus gsbase"); Proc *up = externup(); char buf[ERRMAX]; Vctl *ctl, *v; machp()->perf.intrts = perfticks(); user = userureg(ureg); if(user && (machp()->NIX.nixtype == NIXTC)){ up->dbgreg = ureg; cycles(&up->kentry); } clockintr = 0; //_pmcupdate(machp()); if((ctl = vctl[vno]) != nil){ if(ctl->isintr){ machp()->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) machp()->lastintr = ctl->Vkey.irq; }else if(up) up->nqtrap++; if(ctl->isr){ ctl->isr(vno); if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr); } for(v = ctl; v != nil; v = v->next){ if(v->f){ v->f(ureg, v->a); if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f); } } if(ctl->eoi){ ctl->eoi(vno); if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi); } intrtime(vno); if(ctl->isintr){ if(ctl->Vkey.irq == IrqCLOCK || ctl->Vkey.irq == IrqTIMER) clockintr = 1; if (ctl->Vkey.irq == IrqTIMER) oprof_alarm_handler(ureg); if(up && !clockintr) preempted(); } } else if(vno < nelem(excname) && user){ spllo(); snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]); postnote(up, 1, buf, NDebug); } else if(vno >= VectorPIC && vno != VectorSYSCALL){ /* * An unknown interrupt. * Check for a default IRQ7. This can happen when * the IRQ input goes away before the acknowledge. * In this case, a 'default IRQ7' is generated, but * the corresponding bit in the ISR isn't set. * In fact, just ignore all such interrupts. */ /* clear the interrupt */ i8259isr(vno); iprint("cpu%d: spurious interrupt %d, last %d\n", machp()->machno, vno, machp()->lastintr); intrtime(vno); if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ nmienable(); if(machp()->machno != 0){ iprint("cpu%d: PC %#llx\n", machp()->machno, ureg->ip); for(;;); } } dumpregs(ureg); if(!user){ ureg->sp = PTR2UINT(&ureg->sp); dumpstackwithureg(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d\n", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ if(0) if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0){ if(!waserror()){ up->ac = getac(up, -1); poperror(); runacore(); return; } } sched(); splhi(); } if(user){ if(up != nil && (up->procctl || up->nnote)) notify(ureg); kexit(ureg); } }
int kwrite_pipe(int fd, char *buf, int n){ char c; int r = 0; PIPE *pp; OFT* op; printf("Attempt pipe write of %d bytes to fd (%d)\n", n, fd); // if(n <= 0){ // return 0; // } if(fd >= NFD || fd < 0){ printf("invalid file descriptor (out of bounds).\n"); return -1; } if(!running->fd[fd]){ printf("invalid file descriptor (not opened).\n"); return -1; } op = running->fd[fd]; pp = op->pipe_ptr; if(op->mode != WRITE_PIPE){ printf("fd (%d) is not for pipe read\n", fd); return -1; } printf("pipe before writing\n"); show_pipe(pp); while(n){ if(!pp->nreader){ printf("proc %d : BROKEN_PIPE error\n", running->pid); kexit(0x0D); } while(pp->room && n){ pp->buf[pp->head++] = get_byte(running->uss, buf); pp->head = pp->head % PSIZE; pp->data++; pp->room--; n--; r++; buf++; } kwakeup(&(pp->data)); if(n==0){ printf("pipe after writing\n"); show_pipe(pp); return r; } printf("pipe before writer goes to sleep\n"); show_pipe(pp); ksleep(&(pp->room)); } return r; }
/** * Call by the exeption to handle the syscall * \private */ void syscall_handler(registers_t * regs) { int32_t res = 0; int32_t syscall = regs->v_reg[0]; // code of the syscall switch (syscall) { case FOURCHETTE: res = create_proc(get_arg((char **) regs->a_reg[2], 0), regs->a_reg[0], regs->a_reg[1], (char **) regs->a_reg[2]); break; case PRINT: res = print_string((char *) regs->a_reg[0]); return; /* We save the good return value in the pcb */ case READ: res = read_string((char *) regs->a_reg[0], regs->a_reg[1]); return; /* We save the good return value in the pcb */ case FPRINT: if (regs->a_reg[0] == CONSOLE) kprint((char *) regs->a_reg[1]); else kmaltaprint8((char *) regs->a_reg[1]); break; case SLEEP: res = go_to_sleep(regs->a_reg[0]); break; case BLOCK: res = kblock(regs->a_reg[0], BLOCKED); break; case UNBLOCK: kwakeup(regs->a_reg[0]); break; case WAIT: res = waitfor(regs->a_reg[0], (int32_t *) regs->a_reg[1]); break; case SEND: res = send_msg(pcb_get_pid(get_current_pcb()), (msg_arg *) regs->a_reg[0]); break; case RECV: res = recv_msg(pcb_get_pid(get_current_pcb()), (msg_arg *) regs->a_reg[0]); if (res == NOTFOUND) go_to_sleep(((msg_arg *) regs->a_reg[0])->timeout); break; case PERROR: kperror((char *) regs->a_reg[0]); break; case GERROR: res = kgerror(); break; case SERROR: kserror(regs->a_reg[0]); break; case GETPINFO: res = get_pinfo(regs->a_reg[0], (pcbinfo *) regs->a_reg[1]); break; case GETPID: res = pcb_get_pid(get_current_pcb()); break; case GETALLPID: res = get_all_pid((int *) regs->a_reg[0]); break; case CHGPPRI: res = chg_ppri(regs->a_reg[0], regs->a_reg[1]); break; case KILL: res = kkill(regs->a_reg[0]); break; case EXIT: kexit(regs->a_reg[0]); break; default: kprintln("ERROR: Unknown syscall"); break; } // saves the return code regs->v_reg[0] = res; return; }
void syscall(Ureg* ureg) { char *e; u32int s; ulong sp; long ret; int i, scallnr; vlong startns, stopns; if(!userureg(ureg)) panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux", ureg->pc, ureg->r14, ureg->psr); cycles(&up->kentry); m->syscall++; up->insyscall = 1; up->pc = ureg->pc; up->dbgreg = ureg; scallnr = ureg->r0; up->scallnr = scallnr; if(scallnr == RFORK) fpusysrfork(ureg); spllo(); sp = ureg->sp; if(up->procctl == Proc_tracesyscall){ /* * Redundant validaddr. Do we care? * Tracing syscalls is not exactly a fast path... * Beware, validaddr currently does a pexit rather * than an error if there's a problem; that might * change in the future. */ if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) validaddr(sp, sizeof(Sargs)+BY2WD, 0); syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD)); up->procctl = Proc_stopme; procctl(up); if (up->syscalltrace) free(up->syscalltrace); up->syscalltrace = nil; } up->nerrlab = 0; ret = -1; startns = todget(nil); if(!waserror()){ if(scallnr >= nsyscall){ pprint("bad sys call number %d pc %#lux\n", scallnr, ureg->pc); postnote(up, 1, "sys: bad sys call", NDebug); error(Ebadarg); } if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) validaddr(sp, sizeof(Sargs)+BY2WD, 0); up->s = *((Sargs*)(sp+BY2WD)); up->psstate = sysctab[scallnr]; /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */ ret = systab[scallnr](up->s.args); poperror(); }else{ /* failure: save the error buffer for errstr */ e = up->syserrstr; up->syserrstr = up->errstr; up->errstr = e; } if(up->nerrlab){ print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab); for(i = 0; i < NERR; i++) print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc); panic("error stack"); } /* * Put return value in frame. On the x86 the syscall is * just another trap and the return value from syscall is * ignored. On other machines the return value is put into * the results register by caller of syscall. */ ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ stopns = todget(nil); up->procctl = Proc_stopme; sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns); s = splhi(); procctl(up); splx(s); if(up->syscalltrace) free(up->syscalltrace); up->syscalltrace = nil; } up->insyscall = 0; up->psstate = 0; if(scallnr == NOTED) noted(ureg, *(ulong*)(sp+BY2WD)); splhi(); if(scallnr != RFORK && (up->procctl || up->nnote)) notify(ureg); /* if we delayed sched because we held a lock, sched now */ if(up->delaysched){ sched(); splhi(); } kexit(ureg); }
/* * All traps come here. It is slower to have all traps call trap() * rather than directly vectoring the handler. However, this avoids a * lot of code duplication and possible bugs. The only exception is * VectorSYSCALL. * Trap is called with interrupts disabled via interrupt-gates. */ void trap(Ureg* ureg) { int clockintr, i, vno, user; char buf[ERRMAX]; Vctl *ctl, *v; Mach *mach; if(!trapinited){ /* fault386 can give a better error message */ if(ureg->trap == VectorPF) fault386(ureg, nil); panic("trap %lud: not ready", ureg->trap); } m->perf.intrts = perfticks(); user = (ureg->cs & 0xFFFF) == UESEL; if(user){ up->dbgreg = ureg; cycles(&up->kentry); } clockintr = 0; vno = ureg->trap; if(ctl = vctl[vno]){ if(ctl->isintr){ m->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) m->lastintr = ctl->irq; } if(ctl->isr) ctl->isr(vno); for(v = ctl; v != nil; v = v->next){ if(v->f) v->f(ureg, v->a); } if(ctl->eoi) ctl->eoi(vno); if(ctl->isintr){ intrtime(m, vno); if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER) clockintr = 1; if(up && !clockintr) preempted(); } } else if(vno < nelem(excname) && user){ spllo(); sprint(buf, "sys: trap: %s", excname[vno]); postnote(up, 1, buf, NDebug); } else if(vno >= VectorPIC && vno != VectorSYSCALL){ /* * An unknown interrupt. * Check for a default IRQ7. This can happen when * the IRQ input goes away before the acknowledge. * In this case, a 'default IRQ7' is generated, but * the corresponding bit in the ISR isn't set. * In fact, just ignore all such interrupts. */ /* call all interrupt routines, just in case */ for(i = VectorPIC; i <= MaxIrqLAPIC; i++){ ctl = vctl[i]; if(ctl == nil) continue; if(!ctl->isintr) continue; for(v = ctl; v != nil; v = v->next){ if(v->f) v->f(ureg, v->a); } /* should we do this? */ if(ctl->eoi) ctl->eoi(i); } /* clear the interrupt */ i8259isr(vno); if(0)print("cpu%d: spurious interrupt %d, last %d\n", m->machno, vno, m->lastintr); if(0)if(conf.nmach > 1){ for(i = 0; i < 32; i++){ if(!(active.machs & (1<<i))) continue; mach = MACHP(i); if(m->machno == mach->machno) continue; print(" cpu%d: last %d", mach->machno, mach->lastintr); } print("\n"); } m->spuriousintr++; if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ /* * Don't re-enable, it confuses the crash dumps. nmienable(); */ iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc); while(m->machno != 0) ; } dumpregs(ureg); if(!user){ ureg->sp = (ulong)&ureg->sp; _dumpstack(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ if(up->procctl || up->nnote) notify(ureg); kexit(ureg); } }
/* * Syscall is called directly from assembler without going through trap(). */ void syscall(Ureg* ureg) { char *e; ulong sp; long ret; int i, s; ulong scallnr; if((ureg->cs & 0xFFFF) != UESEL) panic("syscall: cs 0x%4.4luX", ureg->cs); cycles(&up->kentry); m->syscall++; up->insyscall = 1; up->pc = ureg->pc; up->dbgreg = ureg; if(up->procctl == Proc_tracesyscall){ up->procctl = Proc_stopme; procctl(up); } scallnr = ureg->ax; up->scallnr = scallnr; if(scallnr == RFORK && up->fpstate == FPactive){ fpsave(&up->fpsave); up->fpstate = FPinactive; } spllo(); sp = ureg->usp; up->nerrlab = 0; ret = -1; if(!waserror()){ if(scallnr >= nsyscall || systab[scallnr] == 0){ pprint("bad sys call number %lud pc %lux\n", scallnr, ureg->pc); postnote(up, 1, "sys: bad sys call", NDebug); error(Ebadarg); } if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) validaddr(sp, sizeof(Sargs)+BY2WD, 0); up->s = *((Sargs*)(sp+BY2WD)); up->psstate = sysctab[scallnr]; ret = systab[scallnr](up->s.args); poperror(); }else{ /* failure: save the error buffer for errstr */ e = up->syserrstr; up->syserrstr = up->errstr; up->errstr = e; if(0 && up->pid == 1) print("syscall %lud error %s\n", scallnr, up->syserrstr); } if(up->nerrlab){ print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab); for(i = 0; i < NERR; i++) print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc); panic("error stack"); } /* * Put return value in frame. On the x86 the syscall is * just another trap and the return value from syscall is * ignored. On other machines the return value is put into * the results register by caller of syscall. */ ureg->ax = ret; if(up->procctl == Proc_tracesyscall){ up->procctl = Proc_stopme; s = splhi(); procctl(up); splx(s); } up->insyscall = 0; up->psstate = 0; if(scallnr == NOTED) noted(ureg, *(ulong*)(sp+BY2WD)); if(scallnr!=RFORK && (up->procctl || up->nnote)){ splhi(); notify(ureg); } /* if we delayed sched because we held a lock, sched now */ if(up->delaysched) sched(); kexit(ureg); }
int kkexit(int value) { int i = kexit(value); return i; }