From b13538a92755a4e3394476c53f84fd5c86dd1b55 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 11 Nov 2014 11:53:09 +0000 Subject: [PATCH] fuzix: break out execve() We need to split this into pieces and also allow some of it to be cpu specific --- Kernel/Makefile | 10 +- Kernel/platform-micropack/uzi.lnk | 1 + Kernel/platform-msx1/uzi.lnk | 1 + Kernel/platform-msx2/uzi.lnk | 1 + Kernel/platform-nc100/uzi.lnk | 1 + Kernel/platform-pcw8256/uzi.lnk | 1 + Kernel/platform-px4plus/uzi.lnk | 1 + Kernel/platform-trs80/uzi.lnk | 1 + Kernel/platform-z80pack-lite/uzi.lnk | 1 + Kernel/platform-z80pack/uzi.lnk | 1 + Kernel/platform-zx128/uzi.lnk | 1 + Kernel/syscall_exec.c | 321 +++++++++++++++++++++++++++ Kernel/syscall_other.c | 314 -------------------------- 13 files changed, 336 insertions(+), 319 deletions(-) create mode 100644 Kernel/syscall_exec.c diff --git a/Kernel/Makefile b/Kernel/Makefile index 145ea389..9689a4a1 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,9 +1,9 @@ TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite -#export TARGET= zx128 -#export CPU = z80 -export TARGET = 6809test -export CPU = 6809 +export TARGET= msx1 +export CPU = z80 +#export TARGET = 6809test +#export CPU = 6809 #export TARGET = 6502test #export CPU = 6502 export VERSION = "0.1" @@ -73,7 +73,7 @@ CDSRCS = start.c C1SRCS = version.c kdata.c filesys.c C1SRCS += inode.c syscall_fs.c process.c usermem.c timer.c C2SRCS = devio.c syscall_proc.c -C2SRCS += syscall_fs2.c syscall_other.c +C2SRCS += syscall_fs2.c syscall_other.c syscall_exec.c C2SRCS += bank16k.c bank32k.c bankfixed.c single.c simple.c C2SRCS += tty.c devsys.c C2SRCS += mm.c swap.c diff --git a/Kernel/platform-micropack/uzi.lnk b/Kernel/platform-micropack/uzi.lnk index f60fd672..5388962f 100644 --- a/Kernel/platform-micropack/uzi.lnk +++ b/Kernel/platform-micropack/uzi.lnk @@ -21,6 +21,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-msx1/uzi.lnk b/Kernel/platform-msx1/uzi.lnk index 1b01d6c6..020641cb 100644 --- a/Kernel/platform-msx1/uzi.lnk +++ b/Kernel/platform-msx1/uzi.lnk @@ -24,6 +24,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-msx2/uzi.lnk b/Kernel/platform-msx2/uzi.lnk index d5c5a4f5..c5c74c83 100644 --- a/Kernel/platform-msx2/uzi.lnk +++ b/Kernel/platform-msx2/uzi.lnk @@ -24,6 +24,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-nc100/uzi.lnk b/Kernel/platform-nc100/uzi.lnk index 3f1a0b0f..359b0585 100644 --- a/Kernel/platform-nc100/uzi.lnk +++ b/Kernel/platform-nc100/uzi.lnk @@ -19,6 +19,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_proc.rel syscall_fs2.rel diff --git a/Kernel/platform-pcw8256/uzi.lnk b/Kernel/platform-pcw8256/uzi.lnk index fc57c9e1..ad871b8e 100644 --- a/Kernel/platform-pcw8256/uzi.lnk +++ b/Kernel/platform-pcw8256/uzi.lnk @@ -22,6 +22,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-px4plus/uzi.lnk b/Kernel/platform-px4plus/uzi.lnk index ed8313ae..3d084584 100644 --- a/Kernel/platform-px4plus/uzi.lnk +++ b/Kernel/platform-px4plus/uzi.lnk @@ -24,6 +24,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-trs80/uzi.lnk b/Kernel/platform-trs80/uzi.lnk index a61ac508..6176ff65 100644 --- a/Kernel/platform-trs80/uzi.lnk +++ b/Kernel/platform-trs80/uzi.lnk @@ -21,6 +21,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-z80pack-lite/uzi.lnk b/Kernel/platform-z80pack-lite/uzi.lnk index 4554f44d..dd10bb53 100644 --- a/Kernel/platform-z80pack-lite/uzi.lnk +++ b/Kernel/platform-z80pack-lite/uzi.lnk @@ -20,6 +20,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_proc.rel syscall_other.rel diff --git a/Kernel/platform-z80pack/uzi.lnk b/Kernel/platform-z80pack/uzi.lnk index 4d7e312e..37f7c208 100644 --- a/Kernel/platform-z80pack/uzi.lnk +++ b/Kernel/platform-z80pack/uzi.lnk @@ -21,6 +21,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/platform-zx128/uzi.lnk b/Kernel/platform-zx128/uzi.lnk index a56d60d3..506980d0 100644 --- a/Kernel/platform-zx128/uzi.lnk +++ b/Kernel/platform-zx128/uzi.lnk @@ -22,6 +22,7 @@ devio.rel filesys.rel process.rel inode.rel +syscall_exec.rel syscall_fs.rel syscall_fs2.rel syscall_proc.rel diff --git a/Kernel/syscall_exec.c b/Kernel/syscall_exec.c new file mode 100644 index 00000000..b6e352ae --- /dev/null +++ b/Kernel/syscall_exec.c @@ -0,0 +1,321 @@ +#include +#include +#include +#include +#include + + +/* User's execve() call. All other flavors are library routines. */ +/******************************************* +execve (name, argv, envp) Function 23 +char *name; +char *argv[]; +char *envp[]; +********************************************/ +#define name (char *)udata.u_argn +#define argv (char **)udata.u_argn1 +#define envp (char **)udata.u_argn2 + +int16_t _execve(void) +{ + inoptr ino, emu_ino; + unsigned char *buf; + blkno_t blk; + char **nargv; /* In user space */ + char **nenvp; /* In user space */ + struct s_argblk *abuf, *ebuf; + int16_t (**sigp) (); + int argc; + uint16_t emu_size, emu_copy; + uint8_t *progptr, *emu_ptr, *emu_base; + int j; + uint16_t top = (uint16_t)ramtop; + uint8_t c; + uint16_t blocks; + + kputs("execve\n"); + + if (!(ino = n_open(name, NULLINOPTR))) + return (-1); + + kputs("Found it\n"); + 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); + + /* Read in the first block of the new program */ + buf = bread(ino->c_dev, bmap(ino, 0, 1), 0); + + /**************************************** + * Get magic number into var magic + * C3 : executable file no C/D sep. + * 00FF : " " with C/D sep. (not supported in FUZIX) + * other : maybe shell script (nogood2) + ****************************************/ + if ((*buf & 0xff) != EMAGIC) { + udata.u_error = ENOEXEC; + goto nogood2; + } + kputs("Magic\n"); + + /* + * Executables might be CP/M or Fuzix (we don't support legacy + * UZI binaries). + */ + if (buf[3] == 'F' && buf[4] == 'Z' && buf[5] == 'X' && buf[6] == '1') { + top = buf[7] | ((unsigned int)buf[8] << 8); + if (top == 0) /* Legacy 'all space' binary */ + top = (uint16_t)ramtop; + emu_ino = 0; // no emulation, thanks + } else { +#ifdef CONFIG_CPM_EMU + // open the emulator code on disk + emu_ino = kn_open(CPM_EMULATOR_FILENAME, NULLINOPTR); + if (!emu_ino) { + kprintf("Cannot load emulator: %s\n", + CPM_EMULATOR_FILENAME); + udata.u_error = ENOEXEC; + goto nogood2; + } + top = (uint16_t)ramtop; +#else + emu_size; + emu_copy; + emu_ptr; + udata.u_error = ENOEXEC; + goto nogood2; +#endif + } + + /* Binary doesn't fit */ + if (top < ino->c_node.i_size + 1024) { + udata.u_error = ENOMEM; + 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; /* SN */ + + /* This must be the last test as it makes changes if it works */ + if (pagemap_realloc(top)) + goto nogood3; + + /* From this point on we are commmited to the exec() completing */ + udata.u_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; + + /* We are definitely going to succeed with the exec, + * so we can start writing over the old program + */ + uput(buf, PROGBASE, 512); /* Move 1st Block to user bank */ + brelse(buf); + + c = ugetc(PROGBASE); + if (c != 0xC3) + kprintf("Botched uput\n"); + + /* At this point, we are committed to reading in and + * executing the program. */ + + for (j = 0; j < UFTSIZE; ++j) { + if (udata.u_cloexec & (1 << j)) + doclose(j); + } + udata.u_cloexec = 0; + +#ifdef CONFIG_CPM_EMU + // Load the CP/M emulator if it is required + if (emu_ino) { + emu_size = emu_ino->c_node.i_size; + // round up to nearest multiple of 256 bytes, fit it in below ramtop + emu_ptr = + (char *) (udata.u_top - ((emu_size + 255) & 0xff00)); + emu_base = emu_ptr; + blk = 0; + + while (emu_size) { + buf = bread(emu_ino->c_dev, bmap(emu_ino, blk, 1), 0); // read block + emu_copy = min(512, emu_size); + uput(buf, emu_ptr, emu_copy); // copy to userspace + bufdiscard((bufptr) buf); + brelse((bufptr) buf); // release block + // adjust pointers + emu_ptr += emu_copy; + emu_size -= emu_copy; + blk++; + } + // close emulator file + i_deref(emu_ino); + + /* + * zero out the remainder of memory between the top of the emulator and top + * of process memory + */ + + uzero(emu_ptr, top - emu_ptr); + } else +#endif + { + emu_base = (uint8_t *)top; + } + + /* emu_base now points at the byte after the last byte the program can occupy */ + + /* + * Read in the rest of the program, block by block + * We use bufdiscard so that we load the entire app through the + * same buffer to avoid cycling our small cache on this. Indirect blocks + * will still be cached. - Hat tip to Steve Hosgood's OMU for that trick + */ + progptr = PROGBASE + 512; // we copied the first block already + + /* Compute this once otherwise each loop we must recalculate this + as the compiler isn't entitled to assume the loop didn't change it */ + blocks = ino->c_node.i_size >> 9; + + for (blk = 1; blk <= blocks; ++blk) { + buf = bread(ino->c_dev, bmap(ino, blk, 1), 0); + uput(buf, progptr, 512); + bufdiscard((bufptr) buf); + brelse((bufptr) buf); + progptr += 512; + } + i_deref(ino); + udata.u_break = (int) progptr; // Set initial break for program + + // zero all remaining process memory above the last block loaded. + uzero(progptr, emu_base - progptr); + + // Turn off caught signals + for (sigp = udata.u_sigvec; sigp < udata.u_sigvec + NSIGS; ++sigp) + *sigp = SIG_DFL; + + // place the arguments, environment and stack at the top of userspace memory, + + // Write back the arguments and the environment + nargv = wargs(((char *) emu_base - 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); + + brelse(abuf); + brelse(ebuf); + + // Shove argc and the address of argv just below envp + uputw((uint16_t) nargv, nenvp - 1); + uputw((uint16_t) argc, nenvp - 2); + + // Set stack pointer for the program + udata.u_isp = nenvp - 2; + + // Start execution (never returns) +#ifdef CONFIG_CPM_EMU + if (emu_ino) + doexec(emu_base); + else +#endif + doexec(PROGBASE); + + // tidy up in various failure modes: + nogood3: + brelse(abuf); + brelse(ebuf); +#ifdef CONFIG_CPM_EMU + if (emu_ino) + i_deref(emu_ino); +#endif + nogood2: + brelse(buf); + nogood: + i_deref(ino); + return (-1); +} + +#undef name +#undef argv +#undef envp + +/* SN TODO max (1024) 512 bytes for argv + and max 512 bytes for environ +*/ + +bool rargs(char **userspace_argv, struct s_argblk * argbuf) +{ + char *ptr; /* Address of base of arg strings in user space */ + uint8_t c; + uint8_t *bufp; + + argbuf->a_argc = 0; /* Store argc in argbuf */ + bufp = argbuf->a_buf; + + while ((ptr = (char *) ugetw(userspace_argv++)) != NULL) { + ++(argbuf->a_argc); /* Store argc in argbuf. */ + do { + *bufp++ = c = ugetc(ptr++); + if (bufp > argbuf->a_buf + 500) { + udata.u_error = E2BIG; + return true; // failed + } + } + while (c); + } + argbuf->a_arglen = bufp - (uint8_t *)argbuf->a_buf; /*Store total string size. */ + return false; // success +} + + +char **wargs(char *ptr, struct s_argblk *argbuf, int *cnt) // ptr is in userspace +{ + char **argv; /* Address of users argv[], just below ptr */ + int argc, arglen; + char **argbase; + uint8_t *sptr; + + sptr = argbuf->a_buf; + + /* Move them into the users address space, at the very top */ + ptr -= (arglen = argbuf->a_arglen); + + if (arglen) { + uput(sptr, ptr, arglen); + } + + /* Set argv to point below the argument strings */ + argc = argbuf->a_argc; + argbase = argv = (char **) ptr - (argc + 1); + + if (cnt) { + *cnt = argc; + } + + /* Set each element of argv[] to point to its argument string */ + while (argc--) { + uputw((uint16_t) ptr, argv++); + if (argc) { + do + ++ptr; + while (*sptr++); + } + } + uputw(0, argv); /*;;26Feb- Add Null Pointer to end of array */ + return ((char **) argbase); +} diff --git a/Kernel/syscall_other.c b/Kernel/syscall_other.c index b14276ac..44133851 100644 --- a/Kernel/syscall_other.c +++ b/Kernel/syscall_other.c @@ -368,320 +368,6 @@ int16_t _umount(void) #undef spec -/* User's execve() call. All other flavors are library routines. */ -/******************************************* -execve (name, argv, envp) Function 23 -char *name; -char *argv[]; -char *envp[]; -********************************************/ -#define name (char *)udata.u_argn -#define argv (char **)udata.u_argn1 -#define envp (char **)udata.u_argn2 - -int16_t _execve(void) -{ - inoptr ino, emu_ino; - unsigned char *buf; - blkno_t blk; - char **nargv; /* In user space */ - char **nenvp; /* In user space */ - struct s_argblk *abuf, *ebuf; - int16_t (**sigp) (); - int argc; - uint16_t emu_size, emu_copy; - uint8_t *progptr, *emu_ptr, *emu_base; - int j; - uint16_t top = (uint16_t)ramtop; - uint8_t c; - uint16_t blocks; - - kputs("execve\n"); - - if (!(ino = n_open(name, NULLINOPTR))) - return (-1); - - kputs("Found it\n"); - 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); - - /* Read in the first block of the new program */ - buf = bread(ino->c_dev, bmap(ino, 0, 1), 0); - - /**************************************** - * Get magic number into var magic - * C3 : executable file no C/D sep. - * 00FF : " " with C/D sep. (not supported in FUZIX) - * other : maybe shell script (nogood2) - ****************************************/ - if ((*buf & 0xff) != EMAGIC) { - udata.u_error = ENOEXEC; - goto nogood2; - } - kputs("Magic\n"); - - /* - * Executables might be CP/M or Fuzix (we don't support legacy - * UZI binaries). - */ - if (buf[3] == 'F' && buf[4] == 'Z' && buf[5] == 'X' && buf[6] == '1') { - top = buf[7] | ((unsigned int)buf[8] << 8); - if (top == 0) /* Legacy 'all space' binary */ - top = (uint16_t)ramtop; - emu_ino = 0; // no emulation, thanks - } else { -#ifdef CONFIG_CPM_EMU - // open the emulator code on disk - emu_ino = kn_open(CPM_EMULATOR_FILENAME, NULLINOPTR); - if (!emu_ino) { - kprintf("Cannot load emulator: %s\n", - CPM_EMULATOR_FILENAME); - udata.u_error = ENOEXEC; - goto nogood2; - } - top = (uint16_t)ramtop; -#else - emu_size; - emu_copy; - emu_ptr; - udata.u_error = ENOEXEC; - goto nogood2; -#endif - } - - /* Binary doesn't fit */ - if (top < ino->c_node.i_size + 1024) { - udata.u_error = ENOMEM; - 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; /* SN */ - - /* This must be the last test as it makes changes if it works */ - if (pagemap_realloc(top)) - goto nogood3; - - /* From this point on we are commmited to the exec() completing */ - udata.u_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; - - /* We are definitely going to succeed with the exec, - * so we can start writing over the old program - */ - uput(buf, PROGBASE, 512); /* Move 1st Block to user bank */ - brelse(buf); - - c = ugetc(PROGBASE); - if (c != 0xC3) - kprintf("Botched uput\n"); - - /* At this point, we are committed to reading in and - * executing the program. */ - - for (j = 0; j < UFTSIZE; ++j) { - if (udata.u_cloexec & (1 << j)) - doclose(j); - } - udata.u_cloexec = 0; - -#ifdef CONFIG_CPM_EMU - // Load the CP/M emulator if it is required - if (emu_ino) { - emu_size = emu_ino->c_node.i_size; - // round up to nearest multiple of 256 bytes, fit it in below ramtop - emu_ptr = - (char *) (udata.u_top - ((emu_size + 255) & 0xff00)); - emu_base = emu_ptr; - blk = 0; - - while (emu_size) { - buf = bread(emu_ino->c_dev, bmap(emu_ino, blk, 1), 0); // read block - emu_copy = min(512, emu_size); - uput(buf, emu_ptr, emu_copy); // copy to userspace - bufdiscard((bufptr) buf); - brelse((bufptr) buf); // release block - // adjust pointers - emu_ptr += emu_copy; - emu_size -= emu_copy; - blk++; - } - // close emulator file - i_deref(emu_ino); - - /* - * zero out the remainder of memory between the top of the emulator and top - * of process memory - */ - - uzero(emu_ptr, top - emu_ptr); - } else -#endif - { - emu_base = (uint8_t *)top; - } - - /* emu_base now points at the byte after the last byte the program can occupy */ - - /* - * Read in the rest of the program, block by block - * We use bufdiscard so that we load the entire app through the - * same buffer to avoid cycling our small cache on this. Indirect blocks - * will still be cached. - Hat tip to Steve Hosgood's OMU for that trick - */ - progptr = PROGBASE + 512; // we copied the first block already - - /* Compute this once otherwise each loop we must recalculate this - as the compiler isn't entitled to assume the loop didn't change it */ - blocks = ino->c_node.i_size >> 9; - - for (blk = 1; blk <= blocks; ++blk) { - buf = bread(ino->c_dev, bmap(ino, blk, 1), 0); - uput(buf, progptr, 512); - bufdiscard((bufptr) buf); - brelse((bufptr) buf); - progptr += 512; - } - i_deref(ino); - udata.u_break = (int) progptr; // Set initial break for program - - // zero all remaining process memory above the last block loaded. - uzero(progptr, emu_base - progptr); - - // Turn off caught signals - for (sigp = udata.u_sigvec; sigp < udata.u_sigvec + NSIGS; ++sigp) - *sigp = SIG_DFL; - - // place the arguments, environment and stack at the top of userspace memory, - - // Write back the arguments and the environment - nargv = wargs(((char *) emu_base - 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); - - brelse(abuf); - brelse(ebuf); - - // Shove argc and the address of argv just below envp - uputw((uint16_t) nargv, nenvp - 1); - uputw((uint16_t) argc, nenvp - 2); - - // Set stack pointer for the program - udata.u_isp = nenvp - 2; - - // Start execution (never returns) -#ifdef CONFIG_CPM_EMU - if (emu_ino) - doexec(emu_base); - else -#endif - doexec(PROGBASE); - - // tidy up in various failure modes: - nogood3: - brelse(abuf); - brelse(ebuf); -#ifdef CONFIG_CPM_EMU - if (emu_ino) - i_deref(emu_ino); -#endif - nogood2: - brelse(buf); - nogood: - i_deref(ino); - return (-1); -} - -#undef name -#undef argv -#undef envp - -/* SN TODO max (1024) 512 bytes for argv - and max 512 bytes for environ -*/ - -bool rargs(char **userspace_argv, struct s_argblk * argbuf) -{ - char *ptr; /* Address of base of arg strings in user space */ - uint8_t c; - uint8_t *bufp; - - argbuf->a_argc = 0; /* Store argc in argbuf */ - bufp = argbuf->a_buf; - - while ((ptr = (char *) ugetw(userspace_argv++)) != NULL) { - ++(argbuf->a_argc); /* Store argc in argbuf. */ - do { - *bufp++ = c = ugetc(ptr++); - if (bufp > argbuf->a_buf + 500) { - udata.u_error = E2BIG; - return true; // failed - } - } - while (c); - } - argbuf->a_arglen = bufp - (uint8_t *)argbuf->a_buf; /*Store total string size. */ - return false; // success -} - - -char **wargs(char *ptr, struct s_argblk *argbuf, int *cnt) // ptr is in userspace -{ - char **argv; /* Address of users argv[], just below ptr */ - int argc, arglen; - char **argbase; - uint8_t *sptr; - - sptr = argbuf->a_buf; - - /* Move them into the users address space, at the very top */ - ptr -= (arglen = argbuf->a_arglen); - - if (arglen) { - uput(sptr, ptr, arglen); - } - - /* Set argv to point below the argument strings */ - argc = argbuf->a_argc; - argbase = argv = (char **) ptr - (argc + 1); - - if (cnt) { - *cnt = argc; - } - - /* Set each element of argv[] to point to its argument string */ - while (argc--) { - uputw((uint16_t) ptr, argv++); - if (argc) { - do - ++ptr; - while (*sptr++); - } - } - uputw(0, argv); /*;;26Feb- Add Null Pointer to end of array */ - return ((char **) argbase); -} /******************************************* profil (samples, size, offset, scale) Function 56 -- 2.34.1