int vt_ioctl(uint8_t minor, uarg_t request, char *data) { /* FIXME: need to address the multiple vt switching case here.. probably need to switch vt */ if (minor <= MAX_VT) { switch(request) { #ifdef KEY_ROWS case KBMAPSIZE: return KEY_ROWS << 8 | KEY_COLS; case KBMAPGET: return uput(keymap, data, sizeof(keymap)); case KBSETTRANS: if (esuper()) return -1; if (uget(keyboard, data, sizeof(keyboard)) == -1) return -1; return uget(shiftkeyboard, data + sizeof(keyboard), sizeof(shiftkeyboard)); #endif case VTSIZE: return VT_HEIGHT << 8 | VT_WIDTH; case VTATTRS: return vtattr_cap; } } return tty_ioctl(minor, request, data); }
main(int argc, char *argv[]) { clock_t tv1, tv2; double time; int i, ndev, status; DEV_NAME devnames[N_MAX]; float setp[N_MAX], rdbk[N_MAX], val; char read = 0; if (read) { if( argc <= 1 ) printf("*** command line error\n"); else { ndev = argc - 1; for(i = 0; i < ndev; i++) strcpy(devnames[i], argv[i+1]); tv1 = clock(); status = uget(ndev, devnames, setp, rdbk); tv2 = clock(); time = (tv2-tv1)/(CLOCKS_PER_SEC/(double)1000.0); printf("execution time = %5.3f sec\n", 1e-3*time); if (status == 0) for (i = 0; i < ndev; i++) { printf("%d %s %e %e\n", status, devnames[i], setp[i], rdbk[i]) ; } else printf("%d\n", status); } } else { if((argc < 2) || (argc % 2 == 0)) { printf("*** Incorrect number of args\n"); exit(0); } else { ndev = argc/2; for (i = 0; i < ndev; i++) { sscanf(argv[2*i+1], "%s", devnames[i]); sscanf(argv[2*i+2], "%f", &setp[i]); } tv1 = clock(); status = uputsp(ndev, devnames, setp); tv2 = clock(); time = (tv2-tv1)/(CLOCKS_PER_SEC/(double)1000.0); printf("execution time = %5.3f sec\n", 1e-3*time); printf("%d\n", status); status = uget(ndev, devnames, setp, rdbk); if (status == 0) for (i = 0; i < ndev; i++) { printf("%d %s %e %e\n", status, devnames[i], setp[i], rdbk[i]) ; } else printf("%d\n", status); } } }
arg_t _setrlimit(void) { staticfast struct rlimit r; struct rlimit *o; if (res < 0 || res >= NRLIMIT) goto bad; if (uget(rlim, &r, sizeof(struct rlimit))) return -1; o = udata.u_rlimit + res; if (r.rlim_cur > r.rlim_max) goto bad; /* Securit check */ if ((r.rlim_cur > o->rlim_max || r.rlim_max > o->rlim_max) && esuper()) return -1; o->rlim_cur = r.rlim_cur; o->rlim_max = r.rlim_max; return 0; bad: udata.u_error = EINVAL; return -1; }
unsigned int ugetsys(unsigned char *to, unsigned int size) { if (udata.u_sysio) memcpy(to, udata.u_base, size); else uget(udata.u_base, to, size); return size; }
static int sa_get(struct sockaddr_in *u, struct sockaddr_in *k) { if (uget(u, k, sizeof(struct sockaddr_in))) return -1; if (k->sin_family != AF_INET) { udata.u_error = EINVAL; return -1; } return 0; }
arg_t _stime(void) { time_t t; if (type != 0) { udata.u_error = EINVAL; return -1; } if (uget(&t, tvec, sizeof(t)) || esuper()) return -1; wrtime(&t); return (-1); }
arg_t _setgroups(void) { if (esuper()) return -1; if (ngroup < 0 || ngroup > NGROUP) { udata.u_error = EINVAL; return -1; } if (ngroup && uget(groups, udata.u_groups, ngroup * sizeof(uint16_t))) return -1; udata.u_ngroup = ngroup; return 0; }
int gfx_draw_op(uarg_t arg, char *ptr) { int err=0; int l; int c = 8; /* 4 x uint16_t */ uint16_t *p = (uint16_t *)(char *)0x5e00; map_for_video(); l = ugetw(ptr); if (l < 6 || l > 512){ err = EINVAL; goto ret; } if (arg != GFXIOC_READ) c = l; if (uget(ptr + 2, (char *)0x5e00, c)){ err = EFAULT; goto ret; } switch(arg) { case GFXIOC_DRAW: /* TODO if (draw_validate(ptr, l, 256, 192)) - or 128! return EINVAL */ video_cmd( ( char *)0x5e00 ); break; case GFXIOC_WRITE: case GFXIOC_READ: if (l < 8){ err= EINVAL; break; } l -= 8; if (p[0] > 191 || p[1] > 31 || p[2] > 191 || p[3] > 31 || p[0] + p[2] > 192 || p[1] + p[3] > 32 || (p[2] * p[3]) > l) { err = -EFAULT; break; } if (arg == GFXIOC_READ) { video_read( (char *)0x5e00 ); if (uput( (char *)0x5e00 + 8, ptr+10, l-2)) err = EFAULT; break; } video_write( (char *)0x5e00 ); } ret: map_for_kernel(); return err; }
/* We copy the 32bit offset in and out rather than passing it as a 32bit OS might */ arg_t _lseek(void) { inoptr ino; struct oft *o; off_t p; off_t n; if (uget(offset, &n, sizeof(n))) return -1; if ((ino = getinode(file)) == NULLINODE) return (-1); if (getmode(ino) == MODE_R(F_PIPE)) { udata.u_error = ESPIPE; return (-1); } o = &of_tab[udata.u_files[file]]; p = o->o_ptr; switch (flag) { case 0: p = n; break; case 1: p += n; break; case 2: p = ino->c_node.i_size + n; break; default: goto bad; } if (p < 0) goto bad; o->o_ptr = p; uput(&p, offset, sizeof(n)); return 0; bad: udata.u_error = EINVAL; return (-1); }
int tty_ioctl(uint8_t minor, uint16_t request, char *data) { /* Data in User Space */ if (!minor) minor = udata.u_ptab->p_tty; if (minor < 1 || minor > NUM_DEV_TTY + 1) { udata.u_error = ENODEV; return -1; } if (deadflag[minor]) { udata.u_error = ENXIO; return -1; } switch (request) { case TCGETS: uput(&ttydata[minor], data, sizeof(struct termios)); break; case TCSETSW: /* We don't have an output queue really so for now drop through */ case TCSETS: case TCSETSF: uget(data, &ttydata[minor], sizeof(struct termios)); if (request == TCSETSF) clrq(&ttyinq[minor]); tty_setup(minor); break; case TIOCINQ: uput(&ttyinq[minor].q_count, data, 2); break; case TIOCFLUSH: clrq(&ttyinq[minor]); break; case TIOCHANGUP: tty_hangup(minor); return 0; default: udata.u_error = ENOTTY; return (-1); } return (0); }
int16_t _utime(void) { inoptr ino; time_t t[2]; if (!valaddr(buf, 2 * sizeof(time_t))) return (-1); if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } uget(buf, t, 2 * sizeof(time_t)); /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0]; ino->c_node.i_mtime = t[1]; setftime(ino, C_TIME); i_deref(ino); return (0); }
arg_t _utime(void) { inoptr ino; time_t t[2]; if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; goto out2; } /* Special case in the Unix API - NULL means now */ if (buf) { if (ino->c_node.i_uid != udata.u_euid && esuper()) goto out; if (!valaddr(buf, 2 * sizeof(time_t))) goto out2; uget(buf, t, 2 * sizeof(time_t)); } else { if (!(getperm(ino) & OTH_WR)) goto out; rdtime(&t[0]); memcpy(&t[1], &t[0], sizeof(t[1])); } /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0].low; ino->c_node.i_mtime = t[1].low; setftime(ino, C_TIME); i_deref(ino); return (0); out: udata.u_error = EPERM; out2: i_deref(ino); return -1; }
// Get copy user buffer to video mem // static void video_get( char *usrptr ){ map_for_video(); uget( usrptr, (char *)0x2000, 512); map_for_kernel(); }
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 blkfromu(void *uaddr, struct blkbuf *buf, uint16_t off, uint16_t len) { uget(uaddr, buf->__bf_data + off , len); }
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); }
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; }