/* * Write or sendto a socket. We don't yet handle message addresses * sensible and that needs fixing */ arg_t net_write(struct socket * s, uint8_t flag) { usize_t n = 0; uint8_t p = 0; struct sockdata *sd = s->s_priv; irqflags_t irq; uint8_t st; irq = di(); while (1) { netstat = s->s_num; st = status(s); if (s->s_state == SS_CLOSED || (s->s_iflag & SI_SHUTW)) { udata.u_error = EPIPE; break; } /* Error or EOF */ if (st & 0xC0) break; /* Good status after a write means byte ok */ n += p; if (n == udata.u_count) { irqrestore(irq); return n; } /* Can we send more bytes ? */ p = 0; if (st & 2) { /* Count bytes sent. The byte we just loaded isn't sent until we check the status of it and it is clean */ p = 1; netdata = ugetc(udata.u_base++); continue; } s->s_iflag |= SI_THROTTLE; if (psleep_flags_io(&s->s_iflag, flag, &n)) { irqrestore(irq); return n; } di(); } /* It broke mummy ! */ irqrestore(irq); if (n) { s->s_error = udata.u_error; udata.u_error = 0; return n; } err_xlate(s); if (udata.u_error == EPIPE) ssig(udata.u_ptab, SIGPIPE); return -1; }
int sock_write(inoptr ino, uint8_t flag) { struct socket *s = &sockets[ino->c_node.i_nlink]; int r; /* FIXME: IRQ protection */ while(1) { if (s->s_state != SS_CONNECTED && s->s_state != SS_CLOSING) { /* FIXME: handle shutdown states properly */ if (s->s_state >= SS_CLOSEWAIT) { ssig(udata.u_ptab, SIGPIPE); udata.u_error = EPIPE; } else udata.u_error = EINVAL; return -1; } switch(r = net_write(s, flag)) { case -2: s->s_iflag |= SI_THROTTLE; break; case -1: return -1; default: return r; } if (s->s_iflag == SI_THROTTLE && psleep_flags(&s->s_iflag, flag) == -1) return -1; } }
void sgrpsig(uint16_t pgrp, uint16_t sig) { ptptr p; for (p = ptab; p < ptab_end; ++p) { if (p->p_pgrp == pgrp) ssig(p, sig); } }
void timer_interrupt(void) { /* Increment processes and global tick counters. We can't do this mid swap because we might have half of the bits for one process and half of another.. */ if (!inswap && udata.u_ptab->p_status == P_RUNNING) { if (udata.u_insys) udata.u_stime++; else udata.u_utime++; } /* Do once-per-decisecond things - this doesn't work out well on boxes with 64 ticks/second.. need a better approach */ if (++ticks_this_dsecond == ticks_per_dsecond) { static ptptr p; /* Update global time counters */ ticks_this_dsecond = 0; ticks.full++; /* Update process alarm clocks and timeouts */ for (p = ptab; p < ptab_end; ++p) { if (p->p_alarm) { p->p_alarm--; if (!p->p_alarm) ssig(p, SIGALRM); } if (p->p_timeout > 1) { p->p_timeout--; if (p->p_timeout == 1) pwake(p); } } updatetod(); load_average(); #ifdef CONFIG_AUDIO audio_tick(); #endif } #ifndef CONFIG_SINGLETASK /* Check run time of current process. We don't charge time while swapping as the last thing we want to do is to swap a process in and decide it took time to swap in so needs to go away again! */ /* FIXME: can we kill off inint ? */ if (!inswap && (++runticks >= udata.u_ptab->p_priority) && !udata.u_insys && inint && nready > 1) { need_resched = 1; #ifdef DEBUG_PREEMPT kprintf("[preempt %p %d]", udata.u_ptab, udata.u_ptab->p_priority); #endif } #endif }
void timer_interrupt(void) { /* Increment processes and global tick counters */ if (udata.u_ptab->p_status == P_RUNNING) { if (udata.u_insys) udata.u_stime++; else udata.u_utime++; } /* Do once-per-decisecond things - this doesn't work out well on boxes with 64 ticks/second.. need a better approach */ if (++ticks_this_dsecond == ticks_per_dsecond) { static ptptr p; /* Update global time counters */ ticks_this_dsecond = 0; ticks.full++; /* Update process alarm clocks and timeouts */ for (p = ptab; p < ptab_end; ++p) { if (p->p_alarm) { p->p_alarm--; if (!p->p_alarm) ssig(p, SIGALRM); } if (p->p_timeout > 1) { p->p_timeout--; if (p->p_timeout == 1) pwake(p); } } updatetod(); load_average(); #ifdef CONFIG_AUDIO audio_tick(); #endif } #ifndef CONFIG_SINGLETASK /* Check run time of current process */ /* Time to switch out? */ if ((++runticks >= udata.u_ptab->p_priority) && !udata.u_insys && inint && nready > 1) { need_resched = 1; #ifdef DEBUG_PREEMPT kprintf("[preempt %x %d %x]", udata.u_ptab, udata.u_ptab->p_priority, *((uint16_t *)0xEAFE)); #endif } #endif }
/* Perform the terminal process signalling */ static int signal_parent(ptptr p) { if (p->p_ignored & (1UL << SIGCHLD)) { /* POSIX.1 says that SIG_IGN for SIGCHLD means don't go zombie, just clean up as we go */ udata.u_ptab->p_status = P_EMPTY; return 0; } ssig(p, SIGCHLD); /* Wake up a waiting parent, if any. */ wakeup((char *)p); udata.u_ptab->p_status = P_ZOMBIE; return 1; }
static void lmsr_adapt_i (LMSR lms) { int i, j, k; REAL sum_sq, scl1, scl2; REAL accum, error; scl1 = (REAL) (1.0 - rate * leak); for (i = 0; i < ssiz; i++) { dlay (dptr) = ssig (i); accum = 0.0; sum_sq = 0.0; for (j = 0; j < asiz; j++) { k = wrap (j); sum_sq += sqr (dlay (k)); accum += afil (j) * dlay (k); } error = ssig (i) - accum; ssig_i (i) = ssig (i) = error; scl2 = (REAL) (rate / (sum_sq + 1.19e-6)); error *= scl2; for (j = 0; j < asiz; j++) { k = wrap (j); afil (j) = afil (j) * scl1 + error * dlay (k); } dptr = bump (dptr); } }
arg_t net_write(struct socket *s, uint8_t flag) { uint16_t n = 0; used(s); used(flag); while(n < udata.u_count) { if (sockets[0].s_state == SS_CLOSED) { udata.u_error = EPIPE; ssig(udata.u_ptab, SIGPIPE); return -1; } /* FIXME - screen +++ handling ! */ netat_outbyte(ugetc(udata.u_base++)); n++; } return udata.u_count; }
static void lmsr_adapt_i (LMSR lms) { int i, j, k; REAL sum_sq, scl1, scl2; COMPLEX accum, error; scl1 = (REAL) (1.0 - rate * leak); for (i = 0; i < ssiz; i++) { dlay (dptr) = CXBdata (lms->signal, i); accum = cxzero; sum_sq = 0; for (j = 0; j < asiz; j++) { k = wrap (j); sum_sq += Csqrmag (dlay (k)); accum.re += afil (j).re * dlay (k).re; accum.im += afil (j).im * dlay (k).im; } error = Csub(cssig(i),accum); ssig_i (i) = error.im; ssig (i) = error.re; scl2 = (REAL) (rate / (sum_sq + 1.19e-7)); error = Cscl(error,scl2); for (j = 0; j < asiz; j++) { k = wrap (j); afil (j).re = afil (j).re * scl1 + error.re * dlay (k).re; afil (j).im = afil (j).im * scl1 + error.im * dlay (k).im; } dptr = bump (dptr); } }
arg_t _kill(void) { ptptr p; int f = 0, s = 0; if (sig < 0 || sig >= NSIGS) { udata.u_error = EINVAL; return (-1); } if (pid == 0) udata.u_argn = -udata.u_ptab->p_pgrp; for (p = ptab; p < ptab_end; ++p) { /* No overlap here */ if (-p->p_pgrp == pid || p->p_pid == pid) { f = 1; /* Found */ if (udata.u_ptab->p_uid == p->p_uid || super()) { if (sig) ssig(p, sig); s = 1; /* Signalled */ /* Only one match possible for a process */ if (pid > 0) return 0; } } } if (s) return 0; /* Not found */ udata.u_error = ESRCH; /* Found but none signalled */ if (f) udata.u_error = EPERM; return (-1); }
/*FGROUP SSM_VME_Access ReadSSM Analyze SSM memory - like AS python + check of serial versus TTC */ int analyze(){ int i,j,bit,word,ier; int first=1; /* L0 L1s L2s AE */ char *SIGname[]={"ORB","PP ","L0 ","L1s","L1d","L2s","L2d","sBU","lBU","1FF","2FF","ChA","ChB","TBU","PPT","SST","STA","AER"}; int NPR=6; char *PRINT[]={"PP ","L0 ","L1s","L2s","AER","LBH"}; int COUNT[18]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* COUNT SSM signals */ int COUNTe[18]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* COUNT errors */ int COUNTl[18]={0,0,-DISTL0,-DISTL1,0,-DISTL2,0,0,0,0,0,0,0,0,0,0,0,0}; /* How close they can be ? */ int COUNTa[18]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Is signal active ? */ int DIST[18]={0,0,DISTL0,DISTL1,0,DISTL2,0,0,0,0,0,0,0,0,0,0,1,0}; /* How close the signals can be ? */ int L1DATA[NL1dat],L2DATA[NL2dat],TT[64]; int iL1d=0,iL2d=0,ivmes=0,ichb=0,iorbi=0,ipp=0,ialls=0; int isdb=0,iltb=0,il1fi=0,il2fi=0,icha=0,ittcbusy=0,ippt=0; if(readFile()!=0) exit(9); dump=NULL; for(i=0;i<Mega;i++){ word=SSMem[i]; // start only after first L0 //bit= ( (word & 4) == 4); //if(bit) first=0; //if(first) continue; for(j=0;j<18;j++){ bit= ( (word & (1<<j)) == (1<<j)); switch(j){ case 0: /* ORBIT */ lsig(0,bit,i,COUNT,COUNTa,&iorbi,"ORBIT"); break; case 1: /* PREPULSE */ lsig(1,bit,i,COUNT,COUNTa,&ipp," PP"); break; case 2: /* L0 */ ssig(2,bit,i,COUNT,COUNTa,COUNTl,COUNTe,DIST,"L0"); break; case 3: /* L1s */ asig(3,bit,i,COUNT,COUNTa,COUNTl,COUNTe,DIST,"L1S"); break; case 4: /* L1data */ ier=data(4,bit,i,COUNTa,L1DATA,NL1dat,&iL1d,"L1DATA"); break; case 5: /* L2 strobe */ asig(5,bit,i,COUNT,COUNTa,COUNTl,COUNTe,DIST,"L2S"); break; case 6: /* L2 data */ ier=data(6,bit,i,COUNTa,L2DATA,NL2dat,&iL2d,"L2DATA"); break; case 7: /* Sub Detector Busy */ lsig(7,bit,i,COUNT,COUNTa,&isdb,"SBUSY"); break; case 8: /* LTU BUSY */ lsig(8,bit,i,COUNT,COUNTa,&iltb,"ALLBUSY"); break; case 9: /* L1 FIFO Nearly Full */ lsig(9,bit,i,COUNT,COUNTa,&il1fi,"L1NF"); break; case 10: /* L2 FIFO Nearly Full */ lsig(10,bit,i,COUNT,COUNTa,&il2fi,"L2NF"); break; case 11: /* Channel A (L0) */ lsig(11,bit,i,COUNT,COUNTa,&icha,"ChanA"); break; case 12: /* Channel B */ channelB(12,bit,i,COUNT,COUNTa,&ichb,TT,"ChanB"); break; case 13: /* TTC BUSY */ lsig(13,bit,i,COUNT,COUNTa,&ittcbusy,"TTCBUSY"); break; case 14: /* PP transmit */ lsig(14,bit,i,COUNT,COUNTa,&ippt,"PPT"); break; case 15: /* vme SLAVE strobe */ lsig(15,bit,i,COUNT,COUNTa,&ivmes,"VMES"); break; case 16: /* START ALL - emulator */ lsig(16,bit,i,COUNT,COUNTa,&ialls,"ALLSTART"); break; case 17: /* ANY ERROR */ ssig(17,bit,i,COUNT,COUNTa,COUNTl,COUNTe,DIST,"ANYERR"); break; } } } // to take into acount signals up in all memory lsig(1,0,Mega,COUNT,COUNTa,&ipp," PP"); lsig(7,0,Mega,COUNT,COUNTa,&isdb,"SBUSY"); lsig(8,0,Mega,COUNT,COUNTa,&iltb,"ALLBUSY"); lsig(9,0,Mega,COUNT,COUNTa,&il1fi,"L1NF"); lsig(10,0,Mega,COUNT,COUNTa,&il2fi,"L2NF"); lsig(11,0,Mega,COUNT,COUNTa,&icha,"LBHALT"); //lsig(12,0,Mega,COUNT,COUNTa,&ivmem,"VMEM"); lsig(13,0,Mega,COUNT,COUNTa,&ittcbusy,"TTCBUSY"); lsig(15,0,Mega,COUNT,COUNTa,&ivmes,"VMES"); lsig(16,0,Mega,COUNT,COUNTa,&ialls,"ALLSTART"); for(i=0;i<NPR;i++){ for(j=0;j<18;j++)if(SIGname[j] == PRINT[i]) printf("<%s=%i> ",SIGname[j],COUNT[j]); } printf("\n"); writeLog(); return 0; }
arg_t _execve(void) { /* We aren't re-entrant where this matters */ uint8_t hdr[16]; staticfast inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint16_t progptr; uint16_t progload; staticfast uint16_t top; uint16_t bin_size; /* Will need to be bigger on some cpus */ uint16_t bss; top = ramtop; if (!(ino = n_open_lock(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = 16; udata.u_base = hdr; udata.u_sysio = true; readi(ino, 0); if (udata.u_done != 16) { udata.u_error = ENOEXEC; goto nogood; } if (!header_ok(hdr)) { udata.u_error = ENOEXEC; goto nogood2; } progload = hdr[7] << 8; if (progload == 0) progload = PROGLOAD; top = *(uint16_t *)(hdr + 8); if (top == 0) /* Legacy 'all space' binary */ top = ramtop; else /* Requested an amount, so adjust for the base */ top += progload; bss = *(uint16_t *)(hdr + 14); /* Binary doesn't fit */ /* FIXME: review overflows */ bin_size = ino->c_node.i_size; progptr = bin_size + 1024 + bss; if (progload < PROGLOAD || top - progload < progptr || progptr < bin_size) { udata.u_error = ENOMEM; goto nogood2; } udata.u_ptab->p_status = P_NOSLEEP; /* If we made pagemap_realloc keep hold of some defined area we could in theory just move the arguments up or down as part of the process - that would save us all this hassle but replace it with new hassle */ /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* SN */ /* This must be the last test as it makes changes if it works */ /* FIXME: once we sort out chmem we can make stack and data two elements. We never allocate 'code' as there is no split I/D */ /* This is only safe from deadlocks providing pagemap_realloc doesn't sleep */ if (pagemap_realloc(0, top - MAPBASE, 0)) goto nogood3; /* From this point on we are commmited to the exec() completing */ /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_top = top; udata.u_ptab->p_top = top; /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; /* FIXME: In the execve case we may on some platforms have space below PROGLOAD to clear... */ /* We are definitely going to succeed with the exec, * so we can start writing over the old program */ uput(hdr, (uint8_t *)progload, 16); /* At this point, we are committed to reading in and * executing the program. This call must not block. */ close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ progptr = progload + 16; if (bin_size > 16) { bin_size -= 16; udata.u_base = (uint8_t *)progptr; /* We copied the first block already */ udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_done != bin_size) goto nogood4; progptr += bin_size; } /* Wipe the memory in the BSS. We don't wipe the memory above that on 8bit boxes, but defer it to brk/sbrk() */ uzero((uint8_t *)progptr, bss); /* Set initial break for program */ udata.u_break = (int)ALIGNUP(progptr + bss); /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); // place the arguments, environment and stack at the top of userspace memory, // Write back the arguments and the environment nargv = wargs(((char *) top - 2), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); // Fill in udata.u_name with program invocation name uget((void *) ugetw(nargv), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_deref(ino); /* Shove argc and the address of argv just below envp FIXME: should flip them in crt0.S of app for R2L setups so we can get rid of the ifdefs */ #ifdef CONFIG_CALL_R2L /* Arguments are stacked the 'wrong' way around */ uputw((uint16_t) nargv, nenvp - 2); uputw((uint16_t) argc, nenvp - 1); #else uputw((uint16_t) nargv, nenvp - 1); uputw((uint16_t) argc, nenvp - 2); #endif /* Set stack pointer for the program */ udata.u_isp = nenvp - 2; /* Start execution (never returns) */ udata.u_ptab->p_status = P_RUNNING; doexec(progload); /* tidy up in various failure modes */ nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: udata.u_ptab->p_status = P_RUNNING; tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_unlock_deref(ino); return (-1); }
void doexit(uint16_t val) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting %d\n", udata.u_ptab->p_pid, val); kprintf ("udata.u_page %u, udata.u_ptab %p, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic(PANIC_KILLED_INIT); sync(); /* Not necessary, but a good idea. */ irq = di(); /* We are exiting, hold all signals (they will never be delivered). If we don't do this we might take a signal while exiting which would be ... unfortunate */ udata.u_ptab->p_held = 0xFFFFFFFFUL; udata.u_cursig = 0; /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = val; i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to init */ if (p->p_pptr == udata.u_ptab) { p->p_pptr = ptab; /* ptab is always init */ /* Suppose our child is a zombie and init has SIGCLD blocked */ if (ptab[0].p_ignored & (1UL << SIGCHLD)) { p->p_status = P_EMPTY; } else { ssig(&ptab[0], SIGCHLD); wakeup(&ptab[0]); } } /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); ssig(p, SIGCONT); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %p, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; signal_parent(udata.u_ptab->p_pptr); nready--; nproc--; switchin(getproc()); panic(PANIC_DOEXIT); }
void doexit(int16_t val, int16_t val2) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting\n", udata.u_ptab->p_pid); kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic("killed init"); _sync(); /* Not necessary, but a good idea. */ irq = di(); /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = (val << 8) | (val2 & 0xff); i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to our parent */ if (p->p_pptr == udata.u_ptab) p->p_pptr = udata.u_ptab->p_pptr; /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; /* FIXME: send SIGCLD here */ /* FIXME: POSIX.1 says that SIG_IGN for SIGCLD means don't go zombie, just clean up as we go */ /* Wake up a waiting parent, if any. */ wakeup((char *) udata.u_ptab->p_pptr); udata.u_ptab->p_status = P_ZOMBIE; nready--; nproc--; switchin(getproc()); panic("doexit: won't exit"); }
arg_t _execve(void) { /* Not ideal on stack */ struct binfmt_flat binflat; inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint32_t bin_size; /* Will need to be bigger on some cpus */ uaddr_t progbase, top; uaddr_t go; uint32_t true_brk; if (!(ino = n_open_lock(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = sizeof(struct binfmt_flat); udata.u_base = (void *)&binflat; udata.u_sysio = true; readi(ino, 0); if (udata.u_done != sizeof(struct binfmt_flat)) { udata.u_error = ENOEXEC; goto nogood; } /* FIXME: ugly - save this as valid_hdr modifies it */ true_brk = binflat.bss_end; /* Hard coded for our 68K format. We don't quite use the ucLinux names, we don't want to load a ucLinux binary in error! */ if (memcmp(binflat.magic, "bFLT", 4) || !valid_hdr(ino, &binflat)) { udata.u_error = ENOEXEC; goto nogood2; } /* Memory needed */ bin_size = binflat.bss_end + binflat.stack_size; /* Overflow ? */ if (bin_size < binflat.bss_end) { udata.u_error = ENOEXEC; goto nogood2; } /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* This must be the last test as it makes changes if it works */ /* FIXME: need to update this to support split code/data and to fix stack handling nicely */ /* FIXME: ENOMEM fix needs to go to 16bit ? */ if ((udata.u_error = pagemap_realloc(0, bin_size, 0)) != 0) goto nogood3; /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_codebase = progbase = pagemap_base(); /* From this point on we are commmited to the exec() completing so we can start writing over the old program */ uput(&binflat, (uint8_t *)progbase, sizeof(struct binfmt_flat)); /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; top = progbase + bin_size; udata.u_top = top; udata.u_ptab->p_top = top; // kprintf("user space at %p\n", progbase); // kprintf("top at %p\n", progbase + bin_size); bin_size = binflat.reloc_start + 4 * binflat.reloc_count; go = (uint32_t)progbase + binflat.entry; close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ if (bin_size > sizeof(struct binfmt_flat)) { /* We copied the header already */ bin_size -= sizeof(struct binfmt_flat); udata.u_base = (uint8_t *)progbase + sizeof(struct binfmt_flat); udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_done != bin_size) goto nogood4; } /* Header isn't counted in relocations */ relocate(&binflat, progbase, bin_size); /* This may wipe the relocations */ uzero((uint8_t *)progbase + binflat.data_end, binflat.bss_end - binflat.data_end + binflat.stack_size); /* Use of brk eats into the stack allocation */ /* Use the temporary we saved (hack) as we mangled bss_end */ udata.u_break = udata.u_codebase + true_brk; /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); /* place the arguments, environment and stack at the top of userspace memory. */ /* Write back the arguments and the environment */ nargv = wargs(((char *) top - 4), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); /* Fill in udata.u_name with Program invocation name */ uget((void *) ugetl(nargv, NULL), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_unlock_deref(ino); /* Shove argc and the address of argv just below envp */ uputl((uint32_t) nargv, nenvp - 1); uputl((uint32_t) argc, nenvp - 2); // Set stack pointer for the program udata.u_isp = nenvp - 2; /* * Sort of - it's a good way to deal with all the stupidity of * random 68K platforms we will have to handle, and a nice place * to stuff the signal trampoline 8) */ install_vdso(); // kprintf("Go = %p ISP = %p\n", go, udata.u_isp); doexec(go); nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_unlock_deref(ino); return (-1); }
void doexit(uint16_t val) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting\n", udata.u_ptab->p_pid); kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic(PANIC_KILLED_INIT); sync(); /* Not necessary, but a good idea. */ irq = di(); /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = val; i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to our parent */ /* FIXME: do we need to wakeup the parent if we do this ? */ if (p->p_pptr == udata.u_ptab) p->p_pptr = udata.u_ptab->p_pptr; /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); ssig(p, SIGCONT); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; signal_parent(udata.u_ptab->p_pptr); nready--; nproc--; switchin(getproc()); panic(PANIC_DOEXIT); }
int exception(struct trapdata *framedata) { ptptr proc; unsigned int frame, fsize; uint8_t trap = framedata->trap; unsigned int sig = 0; uint16_t m; uint16_t *sp = (uint16_t *)framedata; uint16_t *usp = get_usp(); uint16_t *unwind, *context; uint8_t err = 0; int i; /* We translate debug to SIGIOT and A and F line to SIGILL We will need to fix up 68000 v 68010 move to/from SR */ static const uint8_t trap_to_sig[] = { 0, 0, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGABRT/*CHK*/, SIGTRAP/*TRAPV */, SIGILL, SIGIOT, SIGILL, SIGFPE }; proc = udata.u_ptab; if (sysinfo.cpu[0] == 10) { /* Long or short frame: the CPU tells us the frame format */ if (framedata->exception[3] & 0x8000) { fsize = 29; frame = FRAME_C; } else { fsize = 4; frame = FRAME_D; } } else { frame = FRAME_B; fsize = 3; } if (trap == 0) { sig = udata.u_cursig; udata.u_cursig = 0; } else if (trap < 12) { if (trap < 4) { /* On a 68010 this frame is 29 words and the event is restartable (although not always usefully). We need to decide whether to set the restart flag case by case */ if (sysinfo.cpu[0] == 0) { frame = FRAME_A; fsize = 7; } } sig = trap_to_sig[trap]; } else if (trap >= 32 && trap < 48) sig = SIGTRAP; /* This processing only applies to synchronous hardware exceptions */ if (trap) { /* Went boom in kernel space or without a user recovery */ if (kernel_flag || sig == 0) { explode(framedata, frame); panic("trap"); } /* Cheating here .. all our exceptions are low 16 signal */ m = 1 << sig; /* * The caller is ignoring our signal. In some cases this is fine * but in others it's less clear (eg division by zero) and we * may need to take different action. */ if (proc->p_sig[0].s_ignored & m) return 0; /* Weird case - we took a sync signal and the caller wants us to report it later. */ if (proc->p_sig[0].s_held & m) { /* TODO: if it's not meaningfully restartable we should probably treat this as a kill */ ssig(proc, sig); return 0; } recalc_cursig(); /* Put any async signal back */ } if (udata.u_sigvec[sig] == SIG_DFL) { /* Default action for our signal ? */ doexit(dump_core(sig)); /* This will never return. We will go schedule new work */ panic("exret"); } /* build signal frame Our unwinder code does move.l 8(sp),sp movem.l a0-a1/d0-d1,(sp)+ move.w (sp)+,ccr rts */ /* Now update the user stack */ /* - Push the recovery PC */ /* - Patch the kernel exception frame */ if (sysinfo.cpu[0]) { /* FIXME */ err |= pushw(&usp, sp[34]); err |= pushw(&usp, sp[33]); *(uint32_t *)(&sp[33]) = (uint32_t)udata.u_sigvec[sig]; } else { err |= pushw(&usp, sp[31 + fsize]); err |= pushw(&usp, sp[30 + fsize]); *(uint32_t *)(&sp[30 + fsize]) = (uint32_t)udata.u_sigvec[sig]; } /* FIXME: when we do ptrace we will need to support adding the T flag back here as the exception cleared it */ err |= pushw(&usp, framedata->sr); /* Push A1 A0 D1 D0 to match MOVEM.L */ err |= pushl(&usp, framedata->a[1]); err |= pushl(&usp, framedata->a[0]); err |= pushl(&usp, framedata->d[1]); err |= pushl(&usp, framedata->d[0]); /* Remember the target for undoing the frame */ unwind = usp; /* Copy in the signal context itself. 30 words of registers, 2 of trap code and then the hardware exception */ for (i = 0; i < 30 + 2 + fsize; i++) err |= pushw(&usp, *sp++); context = usp; err |= pushl(&usp, (uint32_t)unwind); /* Signal context is a secret extra non portable argument */ err |= pushl(&usp, (uint32_t)context); /* We end it with the call frame as seen from the signal handler, a single argument and a return address */ err |= pushl(&usp, sig); err |= pushl(&usp, udata.u_codebase + 0x04); set_usp(usp); if (err) { doexit(dump_core(SIGSTKFLT)); panic("exret2"); } /* Once built clear the restart state */ udata.u_sigvec[sig] = SIG_DFL; /* Return, RTE and end up on the signal frame */ return 1; }