arg_t _pipe(void) { int8_t u1, u2, oft1, oft2; inoptr ino; /* bug fix SN */ if ((u1 = uf_alloc()) == -1) goto nogood; if ((oft1 = oft_alloc()) == -1) goto nogood; udata.u_files[u1] = oft1; if ((u2 = uf_alloc()) == -1) goto nogood2; if ((oft2 = oft_alloc()) == -1) goto nogood2; if (!(ino = i_open(root_dev, 0))) { oft_deref(oft2); goto nogood2; } udata.u_files[u2] = oft2; of_tab[oft1].o_ptr = 0; of_tab[oft1].o_inode = ino; of_tab[oft1].o_access = O_RDONLY; of_tab[oft2].o_ptr = 0; of_tab[oft2].o_inode = ino; of_tab[oft2].o_access = O_WRONLY; ++ino->c_refs; ino->c_node.i_mode = F_PIPE | 0777; /* No permissions necessary on pipes */ ino->c_node.i_nlink = 0; /* a pipe is not in any directory */ // write results to userspace uputw(u1, fildes); uputw(u2, fildes + 1); return (0); nogood2: oft_deref(oft1); udata.u_files[u1] = NO_FILE; nogood: return (-1); }
arg_t _waitpid(void) { ptptr p; int retval; if (statloc && !valaddr((char *) statloc, sizeof(int))) { udata.u_error = EFAULT; return (-1); } /* FIXME: move this scan into the main loop and also error on a complete loop finding no matchi for pid */ /* See if we have any children. */ for (p = ptab; p < ptab_end; ++p) { if (p->p_status && p->p_pptr == udata.u_ptab && p != udata.u_ptab) goto ok; } udata.u_error = ECHILD; return (-1); ok: if (pid == 0) pid = -udata.u_ptab->p_pgrp; /* Search for an exited child; */ for (;;) { chksigs(); if (udata.u_cursig) { udata.u_error = EINTR; return -1; } for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_ZOMBIE && p->p_pptr == udata.u_ptab) { if (pid == -1 || p->p_pid == pid || p->p_pgrp == -pid) { if (statloc) uputw(p->p_exitval, statloc); retval = p->p_pid; p->p_status = P_EMPTY; /* Add in child's time info. It was stored on top */ /* of p_priority in the childs process table entry. */ udata.u_cutime += ((clock_t *)p->p_priority)[0]; udata.u_cstime += ((clock_t *)p->p_priority)[1]; return retval; } } } /* Nothing yet, so wait */ if (options & WNOHANG) break; psleep(udata.u_ptab); } udata.u_error = EINTR; return -1; }
int sys_ioctl(uint8_t minor, uint16_t request, char *data) { if (minor != 3) { udata.u_error = ENOTTY; return -1; } switch (request) { case PIO_TABSIZE: uputw(maxproc, data); break; case PIO_ENTRYSIZE: uputw(sizeof(struct p_tab), data); break; default: udata.u_error = EINVAL; return (-1); } return 0; }
void signal_frame(uint8_t *trapframe, uint32_t d0, uint32_t d1, uint32_t a0, uint32_t a1) { extern void *udata_shadow; uint8_t *usp = get_usp(); udata_ptr = udata_shadow; uint16_t ccr = *(uint16_t *)trapframe; uint32_t addr = *(uint32_t *)(trapframe + 2); int err = 0; /* Build the user stack frame */ /* FIXME: eventually we should put the trap frame details and trap info into the frame */ usp -= 4; err |= uputl(addr, usp); usp -= 4; err |= uputw(ccr, usp); usp -= 2; err |=uputl(a1, usp); usp -= 4; err |= uputl(a0, usp); usp -= 4; err |= uputl(d1, usp); usp -= 4; err |= uputl(d0, usp); usp -= 4; err |= uputl(udata.u_codebase + 4, usp); set_usp(usp); if (err) { kprintf("%d: stack fault\n", udata.u_ptab->p_pid); doexit(dump_core(SIGKILL)); } /* Now patch up the kernel frame */ *(uint16_t *)trapframe = 0; *(uint32_t *)(trapframe + 2) = (uint32_t)udata.u_sigvec[udata.u_cursig]; udata.u_sigvec[udata.u_cursig] = SIG_DFL; udata.u_cursig = 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); }
int tty_ioctl(uint8_t minor, uarg_t request, char *data) { /* Data in User Space */ struct tty *t; if (minor > NUM_DEV_TTY + 1) { udata.u_error = ENODEV; return -1; } t = &ttydata[minor]; if (t->flag & TTYF_DEAD) { udata.u_error = ENXIO; return -1; } jobcontrol_in(minor, t); switch (request) { case TCGETS: return uput(&t->termios, data, sizeof(struct termios)); break; case TCSETSF: clrq(&ttyinq[minor]); /* Fall through for now */ case TCSETSW: /* We don't have an output queue really so for now drop through */ case TCSETS: if (uget(data, &t->termios, sizeof(struct termios)) == -1) return -1; tty_setup(minor); break; case TIOCINQ: return uput(&ttyinq[minor].q_count, data, 2); case TIOCFLUSH: clrq(&ttyinq[minor]); break; case TIOCHANGUP: tty_hangup(minor); return 0; case TIOCOSTOP: t->flag |= TTYF_STOP; break; case TIOCOSTART: t->flag &= ~TTYF_STOP; break; case TIOCGWINSZ: return uput(&t->winsize, data, sizeof(struct winsize)); case TIOCSWINSZ: if (uget(&t->winsize, data, sizeof(struct winsize))) return -1; sgrpsig(t->pgrp, SIGWINCH); return 0; case TIOCGPGRP: return uputw(t->pgrp, data); #ifdef CONFIG_LEVEL_2 case TIOCSPGRP: /* Only applicable via controlling terminal */ if (minor != udata.u_ptab->p_tty) { udata.u_error = ENOTTY; return -1; } return tcsetpgrp(t, data); #endif default: udata.u_error = ENOTTY; return -1; } return 0; }
static uint8_t pushw(uint16_t **usp, uint16_t v) { (*usp)--; return uputw(v, *usp); }