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); }
void create_init(void) { uint8_t *j; /* userspace: 0x100+ 0 1 2 3 4 5 6 7 8 9 A B C */ const char arg[] = { '/', 'i', 'n', 'i', 't', 0, 0, 1, 1, 0, 0, 0, 0 }; init_process = ptab_alloc(); udata.u_ptab = init_process; udata.u_top = 4096; /* Plenty for the boot */ map_init(); newproc(init_process); init_process->p_status = P_RUNNING; /* wipe file table */ for (j = udata.u_files; j < (udata.u_files + UFTSIZE); ++j) { *j = NO_FILE; } /* Poke the execve arguments into user data space so _execve() can read them back */ uput(arg, PROGBASE, sizeof(arg)); /* Set up things to look like the process is calling _execve() */ udata.u_argn = (uint16_t) PROGBASE; /* FIXME - should be relative to PROGBASE... */ udata.u_argn1 = 0x107; /* Arguments (just "/init") */ udata.u_argn2 = 0x10b; /* Environment (none) */ }
int platform_rtc_read(void) { uint16_t len = sizeof(struct cmos_rtc); irqflags_t irqflags; struct cmos_rtc cmos; uint8_t *p; uint_fast8_t r, y; if (udata.u_count < len) len = udata.u_count; irqflags = di(); p = cmos.data.bytes; y = rtc_get(11); if (y >= 0x70) *p++ = 0x19; else *p++ = 0x20; *p++ = y; *p++ = rtc_get(9) & 0x1F; *p++ = rtc_get(7) & 0x3F; *p++ = rtc_get(4) & 0x3F; *p++ = rtc_get(2) & 0x7F; *p++ = rtc_get(0) & 0x7F; irqrestore(irqflags); cmos.type = CMOS_RTC_BCD; if (uput(&cmos, udata.u_base, len) == -1) return -1; return len; }
void add_argument(const char *s) { int l = strlen(s) + 1; uput(s, (void *)progptr, l); uputp(progptr, (void *)argptr); progptr += ((l + 3) & ~3); argptr += sizeof(uptr_t); }
arg_t _time(void) { time_t t; switch (type) { case 0: rdtime(&t); uput(&t, tvec, sizeof(t)); return (0); case 1: uput(&t.low, &ticks.full, sizeof(ticks)); uzero(&t.high, sizeof(t.high)); return 0; default: udata.u_error = EINVAL; return -1; } }
unsigned int uputsys(unsigned char *from, unsigned int size) { if (udata.u_sysio) memcpy(udata.u_base, from, size); else uput(from, udata.u_base, size); return size; }
arg_t _getrlimit(void) { if (res < 0 || res >= NRLIMIT) { udata.u_error = EINVAL; return -1; } return uput(rlim, udata.u_rlimit + res, sizeof(struct rlimit)); }
arg_t _getfsys(void) { struct mount *m = fs_tab_get(dev); if (m == NULL || m->m_dev == NO_DEVICE) { udata.u_error = ENXIO; return (-1); } return uput((char *) m->m_fs, (char *) buf, sizeof(struct filesys)); }
int16_t _uname(void) { uint16_t size = sizeof(sysinfo) + uname_len; if (size > len) size = len; sysinfo.memk = procmem; sysinfo.usedk = pagemap_mem_used(); uput(&sysinfo, buf, size); return size; }
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); }
static int sa_put(struct socket *s, int type, struct sockaddr_in *u) { struct sockaddrs *sa = &s->s_addr[type]; static struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_addr.s_addr = sa->addr; sin.sin_port = sa->port; sin.sin_family = AF_INET; if (u && uput(u, &sin, sizeof(sin)) == -1) return -1; return 0; }
arg_t _getgroups(void) { if (groups == 0) return udata.u_ngroup; if (ngroup < udata.u_ngroup) { udata.u_error = EINVAL; return -1; } if (uput(udata.u_groups, groups, udata.u_ngroup * sizeof(uint16_t)) < 0) return -1; return udata.u_ngroup; }
uint8_t write_core_image(void) { inoptr parent = NULLINODE; inoptr ino; udata.u_error = 0; /* FIXME: need to think more about the case sp is lala */ if (uput("core", (uint8_t *)udata.u_syscall_sp - 5, 5)) return 0; ino = n_open((char *)udata.u_syscall_sp - 5, &parent); if (ino) { i_deref(parent); return 0; } if (parent) { i_lock(parent); if ((ino = newfile(parent, "core")) != NULL) { ino->c_node.i_mode = F_REG | 0400; setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); f_trunc(ino); #if 0 /* FIXME address ranges for different models - move core writer for address spaces into helpers ? */ /* FIXME: need to add some arch specific header bits, and also pull stuff like the true sp and registers out of the return stack properly */ corehdr.ch_base = pagemap_base; corehdr.ch_break = udata.u_break; corehdr.ch_sp = udata.u_syscall_sp; corehdr.ch_top = PROGTOP; udata.u_offset = 0; udata.u_base = (uint8_t *)&corehdr; udata.u_sysio = true; udata.u_count = sizeof(corehdr); writei(ino, 0); udata.u_sysio = false; udata.u_base = (uint8_t *)pagemap_base; udata.u_count = udata.u_break - pagemap_base; writei(ino, 0); udata.u_base = udata.u_sp; udata.u_count = PROGTOP - (uint32_t)udata.u_sp; writei(ino, 0); #endif i_unlock_deref(ino); return W_COREDUMP; } } return 0; }
int fd_ioctl(uint8_t minor, uarg_t request, char *buffer) { switch(request) { case FDIO_GETCAP: return uput(&fdcap, buffer, sizeof(struct fdcinfo)); case FDIO_GETINFO: return uput(&fdcap, buffer, sizeof(struct fdcinfo)); case FDIO_SETINFO: /* Whatever - when they query to check they'll get no changes */ return 0; case FDIO_FMTTRK: /* Virtual fd has no format mechanism */ return 0; case FDIO_RESTORE: /* Virtual restore is meaningless */ return 0; case FDIO_SETSKEW: return uput(skewtab + minor, buffer, 32); default: return -1; } }
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; }
uint8_t write_core_image(void) { inoptr parent = NULLINODE; inoptr ino; udata.u_error = 0; /* FIXME: need to think more about the case sp is lala */ if (uput("core", udata.u_syscall_sp - 5, 5)) return 0; ino = n_open(udata.u_syscall_sp - 5, &parent); if (ino) { i_deref(parent); return 0; } if (parent) { i_lock(parent); if (ino = newfile(parent, "core")) { ino->c_node.i_mode = F_REG | 0400; setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); f_trunc(ino); /* FIXME: need to add some arch specific header bits, and also pull stuff like the true sp and registers out of the return stack properly */ corehdr.ch_base = MAPBASE; corehdr.ch_break = udata.u_break; corehdr.ch_sp = udata.u_syscall_sp; corehdr.ch_top = PROGTOP; udata.u_offset = 0; udata.u_base = (uint8_t *)&corehdr; udata.u_sysio = true; udata.u_count = sizeof(corehdr); writei(ino, 0); udata.u_sysio = false; udata.u_base = MAPBASE; udata.u_count = udata.u_break - MAPBASE; writei(ino, 0); udata.u_base = udata.u_sp; udata.u_count = PROGTOP - (uint16_t)udata.u_sp; writei(ino, 0); i_unlock_deref(ino); return W_COREDUMP; } } return 0; }
arg_t _uname(void) { uint16_t size = sizeof(sysinfo) + uname_len; if (size > len) size = len; sysinfo.memk = procmem; sysinfo.usedk = pagemap_mem_used(); sysinfo.nproc = PTABSIZE; sysinfo.ticks = ticks_per_dsecond * 10; sysinfo.loadavg[0] = loadavg[0].average; sysinfo.loadavg[1] = loadavg[1].average; sysinfo.loadavg[2] = loadavg[2].average; uput(&sysinfo, buf, size); return size; }
arg_t _time(void) { time_t t; switch (type) { case 0: rdtime(&t); break; case 1: t.low = ticks.full; t.high = 0; break; default: udata.u_error = EINVAL; return -1; } return uput(&t, tvec, sizeof(t)); }
/* 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 platform_rtc_read(void) { uint16_t len = sizeof(struct cmos_rtc); struct cmos_rtc cmos; uint8_t *p; uint8_t r, y; if (udata.u_count < len) len = udata.u_count; if (rtc_secl == 255) { udata.u_error = EOPNOTSUPP; return -1; } /* We do a full set of reads and if the seconds change retry - we need to retry the lost as we might read as the second changes for new year */ do { p = cmos.data.bytes; r = rtc_secl; y = (rtc_yearh << 4) | rtc_yearl; if (y >= 0x70) *p++ = 0x19; else *p++ = 0x20; *p++ = y; *p++ = ((rtc_monh & 1)<< 4) | rtc_monl; *p++ = ((rtc_dayh & 3) << 4) | rtc_dayl; *p++ = ((rtc_hourh & 3) << 4) | rtc_hourl; *p++ = ((rtc_minh & 7) << 4) | rtc_minl; *p++ = ((rtc_sech & 7) << 4) | rtc_secl; } while ((r ^ rtc_secl) & 0x0F); cmos.type = CMOS_RTC_BCD; if (uput(&cmos, udata.u_base, len) == -1) return -1; return len; }
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; }
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); }
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); }
/* * This works because our uput and uget (see trs80-bank.s) switch * to kernel logical bank 2 when copying, as kernel bank 1 is only * code so it knows that any copy must be to common or bank 2. Without * that this would need a double buffer. */ void blktou(void *uaddr, struct blkbuf *buf, uint16_t off, uint16_t len) { uput(buf->__bf_data + off, uaddr, len); }