#include <minix/ipc.h>
+struct ps_strings; /* forward declaration for minix_stack_fill. */
+
+void minix_stack_params(const char *path, char * const *argv, char * const *envp,
+ size_t *stack_size, char *overflow, int *argc, int *envc);
+void minix_stack_fill(const char *path, int argc, char * const *argv,
+ int envc, char * const *envp, size_t stack_size, char *frame,
+ int *vsp, struct ps_strings **psp);
+
int __execve(const char *_path, char *const _argv[], char *const
_envp[], int _nargs, int _nenvps);
int _syscall(endpoint_t _who, int _syscallnr, message *_msgptr);
#define PR_STACK_PTR m1_p1 /* used for stack ptr in sys_exec, sys_getsp */
#define PR_NAME_PTR m1_p2 /* tells where program name is for dmp */
#define PR_IP_PTR m1_p3 /* initial value for ip after exec */
+#define PR_PS_STR_PTR m1_p4 /* pointer to ps_strings, expected by __start */
#define PR_FORK_FLAGS m1_i3 /* optional flags for fork operation */
#define PR_FORK_MSGADDR m1_p1 /* reply message address of forked child */
#define PR_CTX_PTR m1_p1 /* pointer to mcontext_t structure */
#define PMEXEC_FLAGS m1_i3 /* PMEF_* */
#define PMEF_AUXVECTORS 20
-#define PMEF_EXECNAMELEN1 256
-#define PMEF_AUXVECTORSPACE 0x01 /* space for PMEF_AUXVECTORS on stack */
-#define PMEF_EXECNAMESPACE1 0x02 /* space for PMEF_EXECNAMELEN1 execname */
+#define PMEF_EXECNAMELEN1 PATH_MAX
/* Flags for PR_FORK_FLAGS. */
#define PFF_VMINHIBIT 0x01 /* Don't schedule until release by VM. */
# define PM_FRAME m7_p2 /* arguments and environment */
# define PM_FRAME_LEN m7_i3 /* size of frame */
# define PM_EXECFLAGS m7_i4 /* PMEXEC_FLAGS */
+# define PM_PS_STR m7_i5 /* ps_strings pointer */
/* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */
# define PM_STATUS m7_i2 /* OK or failure */
# define PM_PC m7_p1 /* program counter */
# define PM_NEWSP m7_p2 /* possibly-changed stack ptr */
+# define PM_NEWPS_STR m7_i5 /* possibly-changed ps_strings ptr */
/* Additional parameters for PM_FORK and PM_SRV_FORK */
# define PM_PPROC m7_i2 /* parent process endpoint */
#define EXC_RS_PROC m1_i1 /* process that needs to be restarted */
#define EXC_RS_RESULT m1_i2 /* result of the exec */
#define EXC_RS_PC m1_p1 /* program counter */
+#define EXC_RS_PS_STR m1_p2 /* ps_strings pointer */
/*===========================================================================*
* Messages used from VFS to file servers *
#define M3_STRING 16 /* legacy m3_ca1 size (must not be changed) */
#define M3_LONG_STRING 16 /* current m3_ca1 size (may be increased) */
-typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
+typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3, *m1p4;} mess_1;
typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;
short m2s1;} mess_2;
typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_LONG_STRING];} mess_3;
#define m1_p1 m_u.m_m1.m1p1
#define m1_p2 m_u.m_m1.m1p2
#define m1_p3 m_u.m_m1.m1p3
+#define m1_p4 m_u.m_m1.m1p4
#define m2_i1 m_u.m_m2.m2i1
#define m2_i2 m_u.m_m2.m2i2
int sys_abort(int how);
int sys_enable_iop(endpoint_t proc_ep);
-int sys_exec(endpoint_t proc_ep, char *ptr, char *aout, vir_bytes
- initpc);
+int sys_exec(endpoint_t proc_ep, char *stack_ptr, char *progname,
+ vir_bytes pc, vir_bytes ps_str);
int sys_fork(endpoint_t parent, endpoint_t child, endpoint_t *,
u32_t vm, vir_bytes *);
int sys_clear(endpoint_t proc_ep);
/*===========================================================================*
* arch_proc_init *
*===========================================================================*/
-void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name)
+void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp,
+ const u32_t ps_str, char *name)
{
arch_proc_reset(pr);
strcpy(pr->p_name, name);
/* set custom state we know */
pr->p_reg.pc = ip;
pr->p_reg.sp = sp;
+ pr->p_reg.retreg = ps_str; /* a.k.a r0*/
}
/* TODO keesj: rewrite the free running clock to use callbacks
* for local descriptors in the process table.
*/
-#include <string.h>
#include <assert.h>
+#include <string.h>
+
#include <machine/multiboot.h>
#include "kernel/kernel.h"
-#include "kernel/proc.h"
-#include "archconst.h"
+#include "archconst.h"
#include "arch_proto.h"
+#include <sys/exec.h>
#include <libexec.h>
struct tss_s tss[CONFIG_MAX_CPUS];
void arch_boot_proc(struct boot_image *ip, struct proc *rp)
{
multiboot_module_t *mod;
+ struct ps_strings *psp;
+ char *sp;
if(rp->p_nr < 0) return;
execi.proc_e = ip->endpoint;
execi.hdr = (char *) mod->mod_start; /* phys mem direct */
execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start;
- strcpy(execi.progname, ip->proc_name);
+ strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname));
execi.frame_len = 0;
/* callbacks for use in the kernel */
execi.copymem = libexec_copy_memcpy;
execi.clearmem = libexec_clear_memset;
- execi.allocmem_prealloc_cleared = libexec_pg_alloc;
execi.allocmem_prealloc_junk = libexec_pg_alloc;
+ execi.allocmem_prealloc_cleared = libexec_pg_alloc;
execi.allocmem_ondemand = libexec_pg_alloc;
execi.clearproc = NULL;
/* parse VM ELF binary and alloc/map it into bootstrap pagetable */
- libexec_load_elf(&execi);
+ if(libexec_load_elf(&execi) != OK)
+ panic("VM loading failed");
+
+ /* Setup a ps_strings struct on the stack, pointing to the
+ * following argv, envp. */
+ sp = (char *)execi.stack_high;
+ sp -= sizeof(struct ps_strings);
+ psp = (struct ps_strings *) sp;
- /* Initialize the server stack pointer. Take it down three words
- * to give startup code something to use as "argc", "argv" and "envp".
+ /* Take the stack pointer down three words to give startup code
+ * something to use as "argc", "argv" and "envp".
*/
- arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name);
+ sp -= (sizeof(void *) + sizeof(void *) + sizeof(int));
+
+ // linear address space, so it is available.
+ psp->ps_argvstr = (char **)(sp + sizeof(int));
+ psp->ps_nargvstr = 0;
+ psp->ps_envstr = psp->ps_argvstr + sizeof(void *);
+ psp->ps_nenvstr = 0;
+
+ arch_proc_init(rp, execi.pc, (vir_bytes)sp,
+ execi.stack_high - sizeof(struct ps_strings),
+ ip->proc_name);
/* Free VM blob that was just copied into existence. */
add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start);
/*===========================================================================*
* arch_proc_init *
*===========================================================================*/
-void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name)
+void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp,
+ const u32_t ps_str, char *name)
{
arch_proc_reset(pr);
strlcpy(pr->p_name, name, sizeof(pr->p_name));
/* set custom state we know */
pr->p_reg.pc = ip;
pr->p_reg.sp = sp;
+ pr->p_reg.bx = ps_str;
}
static int oxpcie_mapping_index = -1,
* for local descriptors in the process table.
*/
-#include <string.h>
#include <assert.h>
+#include <string.h>
+
#include <minix/cpufeature.h>
#include <machine/multiboot.h>
-
#include "kernel/kernel.h"
-#include "archconst.h"
+#include "archconst.h"
#include "arch_proto.h"
+#include <sys/exec.h>
#include <libexec.h>
#define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
void arch_boot_proc(struct boot_image *ip, struct proc *rp)
{
multiboot_module_t *mod;
+ struct ps_strings *psp;
+ char *sp;
if(rp->p_nr < 0) return;
/* exec parameters */
execi.stack_high = kinfo.user_sp;
- execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */
+ execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */
execi.proc_e = ip->endpoint;
execi.hdr = (char *) mod->mod_start; /* phys mem direct */
execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start;
if(libexec_load_elf(&execi) != OK)
panic("VM loading failed");
- /* Initialize the server stack pointer. Take it down three words
- * to give startup code something to use as "argc", "argv" and "envp".
+ /* Setup a ps_strings struct on the stack, pointing to the
+ * following argv, envp. */
+ sp = (char *)execi.stack_high;
+ sp -= sizeof(struct ps_strings);
+ psp = (struct ps_strings *) sp;
+
+ /* Take the stack pointer down three words to give startup code
+ * something to use as "argc", "argv" and "envp".
*/
- arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name);
+ sp -= (sizeof(void *) + sizeof(void *) + sizeof(int));
+
+ // linear address space, so it is available.
+ psp->ps_argvstr = (char **)(sp + sizeof(int));
+ psp->ps_nargvstr = 0;
+ psp->ps_envstr = psp->ps_argvstr + sizeof(void *);
+ psp->ps_nenvstr = 0;
+
+ arch_proc_init(rp, execi.pc, (vir_bytes)sp,
+ execi.stack_high - sizeof(struct ps_strings),
+ ip->proc_name);
/* Free VM blob that was just copied into existence. */
add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start);
- mod->mod_end = mod->mod_start = 0;
+ mod->mod_end = mod->mod_start = 0;
/* Remember them */
kinfo.vm_allocated_bytes = alloc_for_vm;
int arch_get_params(char *parm, int max);
void memory_init(void);
void mem_clear_mapcache(void);
-void arch_proc_init(struct proc *pr, u32_t, u32_t, char *);
+void arch_proc_init(struct proc *pr, u32_t, u32_t, u32_t, char *);
int arch_do_vmctl(message *m_ptr, struct proc *p);
int vm_contiguous(const struct proc *targetproc, vir_bytes vir_buf,
size_t count);
name[sizeof(name)-1] = '\0';
/* Set process state. */
- arch_proc_init(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR, name);
+ arch_proc_init(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR,
+ (u32_t) m_ptr->PR_PS_STR_PTR, name);
/* No reply to EXEC call */
RTS_UNSET(rp, RTS_RECEIVING);
STRONG_ALIAS(_start,__start)
_ENTRY(__start)
-#ifdef __minix
- mov r3, r2 /* cleanup */
- mov r4, r1 /* obj_main */
- and r5, r5, #0 /* ps_strings, always NULL on MINIX */
-
- /* Get argc, argv, and envp from stack */
- ldr r0, [sp, #0] /* get argc */
- add r1, sp, #4 /* argv = sp + 4 */
- add r2, r1, r0, lsl #2 /* envp = argv + argc*4 */
- add r2, r2, #4 /* skip NULL terminator */
-#else
/*
* We need to swap ps_strings and cleanup
*/
mov ip, r0 /* ps_strings -> tmp */
mov r0, r2 /* cleanup -> ps_strings */
mov r2, ip /* tmp -> ps_strings */
-#endif /* __minix */
+
/* Ensure the stack is properly aligned before calling C code. */
bic sp, sp, #7
-#ifdef __minix
- /* Store obj and ps_strings on the stack */
- sub sp, sp, #8
- str r5, [sp, #4]
- str r4, [sp, #0]
-#endif
/*
* void ___start(void (*cleanup)(void),
* const Obj_Entry *obj,
pushl %ebx
pushl %ecx
pushl %edx
-#ifdef __minix
- movl 12(%esp),%eax
- leal 16(%esp),%edx
- leal 20(%esp,%eax,4),%ecx
- pushl %ecx
- pushl %edx
- pushl %eax
-#endif /* __minix */
call ___start
static char empty_string[] = "";
char *__progname = empty_string;
-#ifndef __minix
__dead __dso_hidden void ___start(void (*)(void), const Obj_Entry *,
struct ps_strings *);
+#ifndef __minix
#define write(fd, s, n) __syscall(SYS_write, (fd), (s), (n))
#else
-__dead __dso_hidden void ___start(int, char **, char **, void (*)(void),
- const Obj_Entry *, struct ps_strings *);
-
#define write(fd, s, n) /* NO write() from here on minix */
#endif
#endif /* HAVE_INITFINI_ARRAY */
void
-#ifdef __minix
-___start(int argc, char **argv, char **envp,
- void (*cleanup)(void), /* from shared loader */
-#else
___start(void (*cleanup)(void), /* from shared loader */
-#endif /* __minix */
const Obj_Entry *obj, /* from shared loader */
struct ps_strings *ps_strings)
{
-#ifdef __minix
- /* LSC: We have not yet updated the way we pass arguments to
- the userspace, so here some code to adapt this to the new
- ways. */
- struct ps_strings minix_ps_strings;
-
- if (ps_strings == NULL) {
- memset(&minix_ps_strings, 0, sizeof(minix_ps_strings));
-
- minix_ps_strings.ps_envstr = envp;
- minix_ps_strings.ps_argvstr = argv;
- minix_ps_strings.ps_nargvstr = argc;
- ps_strings = &minix_ps_strings;
- }
-#endif /* __minix */
+
if (ps_strings == NULL)
_FATAL("ps_strings missing\n");
__ps_strings = ps_strings;
getrusage.c
# Minix specific syscalls.
-SRCS+= cprofile.c lseek64.c sprofile.c _mcontext.c
+SRCS+= cprofile.c lseek64.c sprofile.c stack_utils.c _mcontext.c
.include "${ARCHDIR}/sys-minix/Makefile.inc"
-/* execve() - basic program execution call Author: Kees J. Bot
- * 21 Jan 1994
- */
+/* execve() - basic program execution call */
#include <sys/cdefs.h>
#include "namespace.h"
#include <unistd.h>
#include <string.h>
#include <stddef.h>
+#include <minix/param.h>
#include <sys/exec_elf.h>
+#include <sys/exec.h>
#ifdef __weak_alias
__weak_alias(execve, _execve)
int execve(const char *path, char * const *argv, char * const *envp)
{
- char * const *ap;
- char * const *ep;
- char *frame;
- char **vp;
- char *sp;
- size_t argc;
- int extra;
- int vectors;
- size_t frame_size;
- size_t string_off;
- size_t n;
- int ov;
message m;
+ size_t frame_size = 0; /* Size of the new initial stack. */
+ int argc = 0; /* Argument count. */
+ int envc = 0; /* Environment count */
+ char overflow = 0; /* No overflow yet. */
+ char *frame;
+ struct ps_strings *psp;
+ int vsp = 0; /* (virtual) Stack pointer in new address space. */
- /* Assumptions: size_t and char *, it's all the same thing. */
-
- /* Create a stack image that only needs to be patched up slightly
- * by the kernel to be used for the process to be executed.
- */
-
- ov= 0; /* No overflow yet. */
- frame_size= 0; /* Size of the new initial stack. */
- string_off= 0; /* Offset to start of the strings. */
- argc= 0; /* Argument count. */
-
- for (ap= argv; *ap != NULL; ap++) {
- n = sizeof(*ap) + strlen(*ap) + 1;
- frame_size+= n;
- if (frame_size < n) ov= 1;
- string_off+= sizeof(*ap);
- argc++;
- }
-
- for (ep= envp; *ep != NULL; ep++) {
- n = sizeof(*ep) + strlen(*ep) + 1;
- frame_size+= n;
- if (frame_size < n) ov= 1;
- string_off+= sizeof(*ap);
- }
-
- /* Add an argument count, two terminating nulls and
- * space for the ELF aux vectors, that must come before
- * (i.e. at a higher address) then the strings.
- */
- vectors = sizeof(argc) + sizeof(*ap) + sizeof(*ep) +
- sizeof(AuxInfo) * PMEF_AUXVECTORS;
- extra = vectors + PMEF_EXECNAMELEN1;
- frame_size+= extra;
- string_off+= extra;
-
- /* Align. */
- frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
+ minix_stack_params(path, argv, envp, &frame_size, &overflow,
+ &argc, &envc);
/* The party is off if there is an overflow. */
- if (ov || frame_size < 3 * sizeof(char *)) {
- errno= E2BIG;
+ if (overflow) {
+ errno = E2BIG;
return -1;
}
return -1;
}
- /* Set arg count, init pointers to vector and string tables. */
- * (size_t *) frame = argc;
- vp = (char **) (frame + sizeof(argc));
- sp = frame + string_off;
-
- /* Load the argument vector and strings. */
- for (ap= argv; *ap != NULL; ap++) {
- *vp++= (char *) (sp - frame);
- n= strlen(*ap) + 1;
- memcpy(sp, *ap, n);
- sp+= n;
- }
- *vp++= NULL;
-
- /* Load the environment vector and strings. */
- for (ep= envp; *ep != NULL; ep++) {
- *vp++= (char *) (sp - frame);
- n= strlen(*ep) + 1;
- memcpy(sp, *ep, n);
- sp+= n;
- }
- *vp++= NULL;
-
- /* Padding. */
- while (sp < frame + frame_size) *sp++= 0;
+ minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame,
+ &vsp, &psp);
/* Clear unused message fields */
memset(&m, 0, sizeof(m));
m.m1_i2 = frame_size;
m.m1_p1 = (char *) __UNCONST(path);
m.m1_p2 = frame;
-
- /* Tell PM/VFS we have left space for the aux vectors
- * and executable name
- */
- m.PMEXEC_FLAGS = PMEF_AUXVECTORSPACE | PMEF_EXECNAMESPACE1;
+ m.m1_p4 = (char *)(vsp + ((char *)psp - frame));
(void) _syscall(PM_PROC_NR, EXEC, &m);
/* Failure, return the memory used for the frame and exit. */
(void) sbrk(-frame_size);
+
return -1;
}
--- /dev/null
+/* Utilities to generate a proper C stack.
+ *
+ * Author: Lionel A. Sambuc.
+ */
+
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include <minix/param.h>
+#include <sys/exec_elf.h>
+#include <sys/exec.h>
+
+#ifdef __weak_alias
+__weak_alias(execve, _execve)
+#endif
+
+extern struct minix_kerninfo *_minix_kerninfo;
+
+/* Create a stack image that only needs to be patched up slightly by
+ * the kernel to be used for the process to be executed.
+ *
+ * Every pointers are stored here as offset from the frame base, and
+ * will be adapted as required for the new process address space.
+ *
+ * The following parameters are passed by register to either __start
+ * for static binaries, or _rtld_start for dynamic ones:
+ * *fct, *ObjEntry, *ps_string
+ *
+ * The following stack layout is expected by _rtld():
+ *
+ * | XXXXXXXXXX | 0x0000_00000
+ * | ... |
+ * | ... | Top of the stack
+ * | argc |
+ * | *argv1 | points to the first char of the argv1
+ * | ... |
+ * | *argvN |
+ * | NULL |
+ * | *env1 |
+ * | ... |
+ * | *envN |
+ * | NULL |
+ * | ElfAuxV1 |
+ * | ... |
+ * | ElfAuxVX |
+ * | AuxExecName| fully resolve executable name, as an ASCIIZ string,
+ * at most PMEF_EXECNAMELEN1 long.
+ *
+ * Here we put first the strings, then word-align, then ps_strings, to
+ * comply with the expected layout of NetBSD. This seems to matter for
+ * the NetBSD ps command, so let's make sure we are compatible...
+ *
+ * | strings | Maybe followed by some padding to word-align.
+ * | **argv | \
+ * | argc | +---> ps_string structure content.
+ * | **env | |
+ * | envc | /
+ * | sigcode | On NetBSD, there may be a compatibility stub here,
+ * +------------+ for native code, it is not present.
+ * Stack Base , 0xF000_0000, descending stack.
+ */
+
+/* The minimum size of the frame is composed of:
+ * argc, the NULL terminator for argv as well as one for
+ * environ, the ELF Aux vectors, executable name and the
+ * ps_strings struct. */
+#define STACK_MIN_SZ \
+( \
+ sizeof(int) + sizeof(void *) * 2 + \
+ sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
+ sizeof(struct ps_strings) \
+)
+
+/*****************************************************************************
+ * Computes stack size, argc, envc, for a given set of path, argv, envp. *
+ *****************************************************************************/
+void minix_stack_params(const char *path, char * const *argv, char * const *envp,
+ size_t *stack_size, char *overflow, int *argc, int *envc)
+{
+ char * const *p;
+ size_t const min_size = STACK_MIN_SZ;
+
+ *stack_size = min_size; /* Size of the new initial stack. */
+ *overflow = 0; /* No overflow yet. */
+ *argc = 0; /* Argument count. */
+ *envc = 0; /* Environment count */
+
+ /* Compute and add the size required to store argv and env. */
+ for (p = argv; *p != NULL; p++) {
+ size_t const n = sizeof(*p) + strlen(*p) + 1;
+ *stack_size += n;
+ if (*stack_size < n) {
+ *overflow = 1;
+ }
+ (*argc)++;
+ }
+
+ for (p = envp; *p != NULL; p++) {
+ size_t const n = sizeof(*p) + strlen(*p) + 1;
+ *stack_size += n;
+ if (*stack_size < n) {
+ *overflow = 1;
+ }
+ (*envc)++;
+ }
+
+ /* Compute the aligned frame size. */
+ *stack_size = (*stack_size + sizeof(void *) - 1) &
+ ~(sizeof(void *) - 1);
+
+ if (*stack_size < min_size) {
+ /* This is possible only in case of overflow. */
+ *overflow = 1;
+ }
+}
+
+/*****************************************************************************
+ * Generate a stack in the buffer frame, ready to be used. *
+ *****************************************************************************/
+void minix_stack_fill(const char *path, int argc, char * const *argv,
+ int envc, char * const *envp, size_t stack_size, char *frame,
+ int *vsp, struct ps_strings **psp)
+{
+ char * const *p;
+
+ /* Frame pointers (a.k.a stack pointer within the buffer in current
+ * address space.) */
+ char *fp; /* byte aligned */
+ char **fpw; /* word aligned */
+
+ size_t const min_size = STACK_MIN_SZ;
+
+ /* Virtual address of the stack pointer, in new memory space. */
+ *vsp = _minix_kerninfo->kinfo->user_sp - stack_size;
+
+ /* Fill in the frame now. */
+ fpw = (char **) frame;
+ *fpw++ = (char *) argc;
+
+ /* The strings themselves are stored after the aux vectors,
+ * cf. top comment. */
+ fp = frame + (min_size - sizeof(struct ps_strings)) +
+ (envc + argc) * sizeof(char *);
+
+ /* Fill in argv and the environment, as well as copy the strings
+ * themselves. */
+ for (p = argv; *p != NULL; p++) {
+ size_t const n = strlen(*p) + 1;
+ *fpw++= (char *)(*vsp + (fp - frame));
+ memcpy(fp, *p, n);
+ fp += n;
+ }
+ *fpw++ = NULL;
+
+ for (p = envp; *p != NULL; p++) {
+ size_t const n = strlen(*p) + 1;
+ *fpw++= (char *)(*vsp + (fp - frame));
+ memcpy(fp, *p, n);
+ fp += n;
+ }
+ *fpw++ = NULL;
+
+ /* Padding, because of the stack alignement. */
+ while ((size_t)fp % sizeof(void *)) *fp++= 0;
+
+ /* Fill in the ps_string struct*/
+ *psp = (struct ps_strings *) fp;
+
+ (*psp)->ps_argvstr = (char **)(*vsp + sizeof(argc));
+ (*psp)->ps_nargvstr = argc;
+ (*psp)->ps_envstr = (*psp)->ps_argvstr + argc + 1;
+ (*psp)->ps_nenvstr = envc;
+}
return OK;
}
-void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base)
-{
-/* When doing an exec(name, argv, envp) call, the user builds up a stack
- * image with arg and env pointers relative to the start of the stack. Now
- * these pointers must be relocated, since the stack is not positioned at
- * address 0 in the user's address space.
- */
-
- char **ap, flag;
- vir_bytes v;
-
- flag = 0; /* counts number of 0-pointers seen */
- ap = (char **) stack; /* points initially to 'nargs' */
- ap++; /* now points to argv[0] */
- while (flag < 2) {
- if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
- if (*ap != NULL) {
- v = (vir_bytes) *ap; /* v is relative pointer */
- v += base; /* relocate it */
- *ap = (char *) v; /* put it back */
- } else {
- flag++;
- }
- ap++;
- }
-}
-
int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *e)
{
int r;
int elf_has_interpreter(char *exec_hdr, int hdr_len, char *interp, int maxsz);
int elf_phdr(char *exec_hdr, int hdr_len, vir_bytes *phdr);
-void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base);
int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *execi);
typedef int (*libexec_exec_loadfunc_t)(struct exec_info *execi);
.for i in access.c brk.c close.c environ.c execve.c fork.c \
getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \
link.c loadname.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
- read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stat.c \
- stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
+ read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stack_utils.c \
+ stat.c stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
brksize.S _ipc.S _senda.S ucontext.S mmap.c init.c
.PATH.c: ${LIBCDIR}/sys-minix
.PATH.S: ${ARCHDIR}/sys-minix
#include "syslib.h"
-int sys_exec(proc_ep, ptr, prog_name, initpc)
-endpoint_t proc_ep; /* process that did exec */
-char *ptr; /* new stack pointer */
-char *prog_name; /* name of the new program */
-vir_bytes initpc;
+int sys_exec(endpoint_t proc_ep, char *stack_ptr, char *progname,
+ vir_bytes pc, vir_bytes ps_str)
{
/* A process has exec'd. Tell the kernel. */
- message m;
+ message m;
- m.PR_ENDPT = proc_ep;
- m.PR_STACK_PTR = ptr;
- m.PR_NAME_PTR = prog_name;
- m.PR_IP_PTR = (char *)initpc;
- return(_kernel_call(SYS_EXEC, &m));
+ m.PR_ENDPT = proc_ep;
+ m.PR_STACK_PTR = stack_ptr;
+ m.PR_NAME_PTR = progname;
+ m.PR_IP_PTR = (char *)pc;
+ m.PR_PS_STR_PTR = (char *)ps_str;
+
+ return _kernel_call(SYS_EXEC, &m);
}
m.PM_FRAME = m_in.frame_ptr;
m.PM_FRAME_LEN = m_in.msg_frame_len;
m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS;
+ m.PM_PS_STR = (vir_bytes)m_in.m1_p4; /* ps_strings pointer into the frame. */
tell_vfs(mp, &m);
/*===========================================================================*
* do_newexec *
*===========================================================================*/
-int do_newexec()
+int do_newexec(void)
{
int proc_e, proc_n, allow_setuid;
char *ptr;
/*===========================================================================*
* do_execrestart *
*===========================================================================*/
-int do_execrestart()
+int do_execrestart(void)
{
int proc_e, proc_n, result;
struct mproc *rmp;
- vir_bytes pc;
+ vir_bytes pc, ps_str;
if (who_e != RS_PROC_NR)
return EPERM;
- proc_e= m_in.EXC_RS_PROC;
+ proc_e = m_in.EXC_RS_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK) {
panic("do_execrestart: got bad endpoint: %d", proc_e);
}
- rmp= &mproc[proc_n];
- result= m_in.EXC_RS_RESULT;
- pc= (vir_bytes)m_in.EXC_RS_PC;
+ rmp = &mproc[proc_n];
+ result = m_in.EXC_RS_RESULT;
+ pc = (vir_bytes)m_in.EXC_RS_PC;
+ ps_str = (vir_bytes)m_in.EXC_RS_PS_STR;
- exec_restart(rmp, result, pc, rmp->mp_frame_addr);
+ exec_restart(rmp, result, pc, rmp->mp_frame_addr, ps_str);
return OK;
}
/*===========================================================================*
* exec_restart *
*===========================================================================*/
-void exec_restart(rmp, result, pc, vfs_newsp)
-struct mproc *rmp;
-int result;
-vir_bytes pc;
-vir_bytes vfs_newsp;
+void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp,
+ vir_bytes ps_str)
{
int r, sn;
#endif /* USE_TRACE */
/* Call kernel to exec with SP and PC set by VFS. */
- r= sys_exec(rmp->mp_endpoint, (char *) vfs_newsp, rmp->mp_name, pc);
+ r = sys_exec(rmp->mp_endpoint, (char *) sp, rmp->mp_name, pc, ps_str);
if (r != OK) panic("sys_exec failed: %d", r);
}
case PM_EXEC_REPLY:
exec_restart(rmp, m_in.PM_STATUS, (vir_bytes)m_in.PM_PC,
- (vir_bytes)m_in.PM_NEWSP);
+ (vir_bytes)m_in.PM_NEWSP, (vir_bytes)m_in.PM_NEWPS_STR);
break;
int do_exec(void);
int do_newexec(void);
int do_execrestart(void);
-void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp);
+void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp,
+ vir_bytes ps_str);
/* forkexit.c */
int do_fork(void);
#include "inc.h"
#include <assert.h>
+#include <sys/exec.h>
#include <libexec.h>
+#include <minix/param.h>
#include <machine/vmparam.h>
static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
- char *frame, int frame_len);
-static int exec_restart(int proc_e, int result, vir_bytes pc);
+ char *frame, int frame_len, vir_bytes ps_str);
+static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str);
static int read_seg(struct exec_info *execi, off_t off,
vir_bytes seg_addr, size_t seg_bytes);
-static int exec_restart(int proc_e, int result, vir_bytes pc);
/* Array of loaders for different object formats */
static struct exec_loaders {
};
int srv_execve(int proc_e, char *exec, size_t exec_len, char **argv,
- char **UNUSED(Xenvp))
+ char **envp)
{
- char * const *ap;
- char * const *ep;
+ size_t frame_size = 0; /* Size of the new initial stack. */
+ int argc = 0; /* Argument count. */
+ int envc = 0; /* Environment count */
+ char overflow = 0; /* No overflow yet. */
char *frame;
- char **vp;
- char *sp, *progname;
- size_t argc;
- size_t frame_size;
- size_t string_off;
- size_t n;
- int ov;
- int r;
-
- /* Assumptions: size_t and char *, it's all the same thing. */
-
- /* Create a stack image that only needs to be patched up slightly
- * by the kernel to be used for the process to be executed.
- */
-
- ov= 0; /* No overflow yet. */
- frame_size= 0; /* Size of the new initial stack. */
- string_off= 0; /* Offset to start of the strings. */
- argc= 0; /* Argument count. */
+ struct ps_strings *psp;
+ int vsp = 0; /* (virtual) Stack pointer in new address space. */
- for (ap= argv; *ap != NULL; ap++) {
- n = sizeof(*ap) + strlen(*ap) + 1;
- frame_size+= n;
- if (frame_size < n) ov= 1;
- string_off+= sizeof(*ap);
- argc++;
- }
-
- /* Add an argument count and two terminating nulls. */
- frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
- string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
+ char *progname;
+ int r;
- /* Align. */
- frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
+ minix_stack_params(argv[0], argv, envp, &frame_size, &overflow,
+ &argc, &envc);
/* The party is off if there is an overflow. */
- if (ov || frame_size < 3 * sizeof(char *)) {
- errno= E2BIG;
+ if (overflow) {
+ errno = E2BIG;
return -1;
}
/* Allocate space for the stack frame. */
- frame = (char *) malloc(frame_size);
- if (!frame) {
+ if ((frame = (char *) sbrk(frame_size)) == (char *) -1) {
errno = E2BIG;
return -1;
}
- /* Set arg count, init pointers to vector and string tables. */
- * (size_t *) frame = argc;
- vp = (char **) (frame + sizeof(argc));
- sp = frame + string_off;
-
- /* Load the argument vector and strings. */
- for (ap= argv; *ap != NULL; ap++) {
- *vp++= (char *) (sp - frame);
- n= strlen(*ap) + 1;
- memcpy(sp, *ap, n);
- sp+= n;
- }
- *vp++= NULL;
-
-#if 0
- /* Load the environment vector and strings. */
- for (ep= envp; *ep != NULL; ep++) {
- *vp++= (char *) (sp - frame);
- n= strlen(*ep) + 1;
- memcpy(sp, *ep, n);
- sp+= n;
- }
-#endif
- *vp++= NULL;
-
- /* Padding. */
- while (sp < frame + frame_size) *sp++= 0;
+ minix_stack_fill(argv[0], argc, argv, envc, envp, frame_size, frame,
+ &vsp, &psp);
(progname=strrchr(argv[0], '/')) ? progname++ : (progname=argv[0]);
- r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size);
- /* Return the memory used for the frame and exit. */
- free(frame);
+ r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size,
+ vsp + ((char *)psp - frame));
+
+ /* Failure, return the memory used for the frame and exit. */
+ (void) sbrk(-frame_size);
+
return r;
}
static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
- char *frame, int frame_len)
+ char *frame, int frame_len, vir_bytes ps_str)
{
int r;
vir_bytes vsp;
return r;
/* Patch up stack and copy it from RS to new core image. */
- vsp = execi.stack_high;
- vsp -= frame_len;
- libexec_patch_ptr(frame, vsp);
+ vsp = execi.stack_high - frame_len;
r = sys_datacopy(SELF, (vir_bytes) frame,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) {
printf("do_exec: copying out new stack failed: %d\n", r);
- exec_restart(proc_e, r, execi.pc);
+ exec_restart(proc_e, r, execi.pc, ps_str);
return r;
}
- return exec_restart(proc_e, OK, execi.pc);
+ return exec_restart(proc_e, OK, execi.pc, ps_str);
}
/*===========================================================================*
* exec_restart *
*===========================================================================*/
-static int exec_restart(int proc_e, int result, vir_bytes pc)
+static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str)
{
int r;
message m;
- m.m_type= EXEC_RESTART;
- m.EXC_RS_PROC= proc_e;
- m.EXC_RS_RESULT= result;
- m.EXC_RS_PC= (void*)pc;
- r= sendrec(PM_PROC_NR, &m);
+ m.m_type = EXEC_RESTART;
+ m.EXC_RS_PROC = proc_e;
+ m.EXC_RS_RESULT = result;
+ m.EXC_RS_PC = (void *)pc;
+ m.EXC_RS_PS_STR = (void *)ps_str;
+
+ r = sendrec(PM_PROC_NR, &m);
if (r != OK)
return r;
+
return m.m_type;
}
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
+#include <sys/exec.h>
#include <sys/param.h>
#include "fproc.h"
#include "path.h"
static void lock_exec(void);
static void unlock_exec(void);
static int patch_stack(struct vnode *vp, char stack[ARG_MAX],
- size_t *stk_bytes, char path[PATH_MAX]);
+ size_t *stk_bytes, char path[PATH_MAX], vir_bytes *vsp);
static int is_script(struct vfs_exec_info *execi);
static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg,
- int replace);
+ vir_bytes *vsp, char replace);
static void clo_exec(struct fproc *rfp);
static int stack_prepare_elf(struct vfs_exec_info *execi,
- char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase);
+ char *curstack, size_t *frame_len, vir_bytes *vsp);
static int map_header(struct vfs_exec_info *execi);
static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size_t seg_bytes);
/* Array of loaders for different object file formats */
typedef int (*exechook_t)(struct vfs_exec_info *execpackage);
typedef int (*stackhook_t)(struct vfs_exec_info *execi, char *curstack,
- size_t *frame_len, vir_bytes *, int *extrabase);
+ size_t *frame_len, vir_bytes *vsp);
struct exec_loaders {
libexec_exec_loadfunc_t load_object; /* load executable into memory */
stackhook_t setup_stack; /* prepare stack before argc and argv push */
*===========================================================================*/
int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
vir_bytes frame, size_t frame_len, vir_bytes *pc,
- vir_bytes *newsp, int user_exec_flags)
+ vir_bytes *newsp, vir_bytes *UNUSED(ps_str), int user_exec_flags)
+ //vir_bytes *newsp, vir_bytes *ps_str, int user_exec_flags)
{
/* Perform the execve(name, argv, envp) call. The user library builds a
* complete stack image, including pointers, args, environ, etc. The stack
* is copied to a buffer inside VFS, and then to the new core image.
+ *
+ * ps_str is not currently used, but may be if the ps_strings structure has to
+ * be moved to another location.
*/
int r, slot;
vir_bytes vsp;
struct fproc *rfp;
- int extrabase = 0;
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
struct vfs_exec_info execi;
int i;
struct lookup resolve;
struct fproc *vmfp = &fproc[VM_PROC_NR];
stackhook_t makestack = NULL;
- static int n;
- n++;
struct filp *newfilp = NULL;
lock_exec();
FAILCHECK(r);
}
+ /* Compute the current virtual stack pointer, has to be done before calling
+ * patch_stack, which needs it, and will adapt as required. */
+ vsp = execi.args.stack_high - frame_len;
+
/* The default is to keep the original user and group IDs */
execi.args.new_uid = rfp->fp_effuid;
execi.args.new_gid = rfp->fp_effgid;
* name into fullpath.
*/
FAILCHECK(fetch_name(path, path_len, fullpath));
- FAILCHECK(patch_stack(execi.vp, mbuf, &frame_len, fullpath));
+ FAILCHECK(patch_stack(execi.vp, mbuf, &frame_len, fullpath, &vsp));
+
strlcpy(finalexec, fullpath, PATH_MAX);
strlcpy(firstexec, fullpath, PATH_MAX);
Get_read_vp(execi, fullpath, 1, 0, &resolve, fp);
/* ld.so is linked at 0, but it can relocate itself; we
* want it higher to trap NULL pointer dereferences.
+ * Let's put it below the stack, and reserve 10MB for ld.so.
*/
- execi.args.load_offset = 0x10000;
+ execi.args.load_offset =
+ execi.args.stack_high - execi.args.stack_size - 0xa00000;
/* Remember it */
strlcpy(execi.execname, finalexec, PATH_MAX);
*pc = execi.args.pc;
/* call a stack-setup function if this executable type wants it */
- vsp = execi.args.stack_high - frame_len;
- if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp, &extrabase));
+ if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp));
- /* Patch up stack and copy it from VFS to new core image. */
- libexec_patch_ptr(mbuf, vsp + extrabase);
+ /* Copy the stack from VFS to new core image. */
FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp,
(phys_bytes)frame_len));
return(r);
}
-static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *framelen,
- vir_bytes *newsp, int *extrabase)
+/* This is a copy-paste of the same macro in libc/sys-minix/stack_utils.c. Keep it
+ * synchronized. */
+#define STACK_MIN_SZ \
+( \
+ sizeof(int) + sizeof(void *) * 2 + \
+ sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
+ sizeof(struct ps_strings) \
+)
+
+static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *frame_size,
+ vir_bytes *vsp)
{
- AuxInfo *a, *term;
- Elf_Ehdr *elf_header;
- int nulls;
- char **mysp = (char **) frame,
- **mysp_end = (char **) ((char *)frame + *framelen);
+ AuxInfo *aux_vec, *aux_vec_end;
+ vir_bytes vap; /* Address in proc space of the first AuxVec. */
+ Elf_Ehdr const * const elf_header = (Elf_Ehdr *) execi->args.hdr;
+ struct ps_strings const * const psp = (struct ps_strings *)
+ (frame + (*frame_size - sizeof(struct ps_strings)));
- if(!execi->is_dyn)
+ size_t const execname_len = strlen(execi->execname);
+
+ if (!execi->is_dyn)
return OK;
- assert(execi->args.hdr_len >= sizeof(*elf_header));
- elf_header = (Elf_Ehdr *) execi->args.hdr;
+ if (execi->args.hdr_len < sizeof(*elf_header)) {
+ printf("VFS: malformed ELF headers for exec\n");
+ return ENOEXEC;
+ }
- /* exec() promises stack space. Now find it. */
- mysp++; /* skip argc */
+ if (*frame_size < STACK_MIN_SZ) {
+ printf("VFS: malformed stack for exec(), smaller than minimum"
+ " possible size.\n");
+ return ENOEXEC;
+ }
- /* find a terminating NULL entry twice: one for argv[], one for envp[]. */
- for(nulls = 0; nulls < 2; nulls++) {
- assert(mysp < mysp_end);
- while(*mysp && mysp < mysp_end) mysp++; /* find terminating NULL */
- if(mysp >= mysp_end) {
- printf("VFS: malformed stack for exec()\n");
- return ENOEXEC;
- }
- assert(!*mysp);
- mysp++;
+ /* Find first Aux vector in the stack frame. */
+ vap = (vir_bytes)(psp->ps_envstr + (psp->ps_nenvstr + 1));
+ aux_vec = (AuxInfo *) (frame + (vap - *vsp));
+ aux_vec_end = aux_vec + PMEF_AUXVECTORS;
+
+ if (((char *)aux_vec < frame) ||
+ ((char *)aux_vec > (frame + *frame_size))) {
+ printf("VFS: malformed stack for exec(), first AuxVector is"
+ " not on the stack.\n");
+ return ENOEXEC;
+ }
+
+ if (((char *)aux_vec_end < frame) ||
+ ((char *)aux_vec_end > (frame + *frame_size))) {
+ printf("VFS: malformed stack for exec(), last AuxVector is"
+ " not on the stack.\n");
+ return ENOEXEC;
}
/* Userland provides a fully filled stack frame, with argc, argv, envp
- * and then all the argv and envp strings; consistent with ELF ABI, except
- * for a list of Aux vectors that should be between envp points and the
- * start of the strings.
+ * and then all the argv and envp strings; consistent with ELF ABI,
+ * except for a list of Aux vectors that should be between envp points
+ * and the start of the strings.
*
- * It would take some very unpleasant hackery to insert the aux vectors before
- * the strings, and correct all the pointers, so the exec code in libc makes
- * space for us first and indicates the fact it did this with this flag.
+ * It would take some very unpleasant hackery to insert the aux vectors
+ * before the strings, and correct all the pointers, so the exec code
+ * in libc makes space for us.
*/
- if(!(execi->userflags & PMEF_AUXVECTORSPACE)) {
- char *f = (char *) mysp;
- int remain;
- vir_bytes extrabytes = sizeof(*a) * PMEF_AUXVECTORS;
-
- /* Create extrabytes more space */
- remain = *framelen - (int)(f - frame);
- if(*framelen + extrabytes >= ARG_MAX)
- return ENOMEM;
- *framelen += extrabytes;
- *newsp -= extrabytes;
- *extrabase += extrabytes;
- memmove(f+extrabytes, f, remain);
- memset(f, 0, extrabytes);
- }
- /* Ok, what mysp points to now we can use for the aux vectors. */
- a = (AuxInfo *) mysp;
-#define AUXINFO(type, value) \
- { assert((char *) a < (char *) mysp_end); a->a_type = type; a->a_v = value; a++; }
-#if 0
- AUXINFO(AT_PHENT, elf_header->e_phentsize);
- AUXINFO(AT_PHNUM, elf_header->e_phnum);
-#endif
- AUXINFO(AT_BASE, execi->args.load_base);
- AUXINFO(AT_ENTRY, execi->args.pc);
- AUXINFO(AT_PAGESZ, PAGE_SIZE);
- AUXINFO(AT_EXECFD, execi->elf_main_fd);
+#define AUXINFO(a, type, value) \
+ do { \
+ if (a < aux_vec_end) { \
+ a->a_type = type; \
+ a->a_v = value; \
+ a++; \
+ } else { \
+ printf("VFS: No more room for ELF AuxVec type %d, skipping it for %s\n", type, execi->execname); \
+ (aux_vec_end - 1)->a_type = AT_NULL; \
+ (aux_vec_end - 1)->a_v = 0; \
+ } \
+ } while(0)
- /* This is where we add the AT_NULL */
- term = a;
+ AUXINFO(aux_vec, AT_BASE, execi->args.load_base);
+ AUXINFO(aux_vec, AT_ENTRY, execi->args.pc);
+ AUXINFO(aux_vec, AT_EXECFD, execi->elf_main_fd);
+#if 0
+ AUXINFO(aux_vec, AT_PHDR, XXX ); /* should be &phdr[0] */
+ AUXINFO(aux_vec, AT_PHENT, elf_header->e_phentsize);
+ AUXINFO(aux_vec, AT_PHNUM, elf_header->e_phnum);
- /* Always terminate with AT_NULL */
- AUXINFO(AT_NULL, 0);
+ AUXINFO(aux_vec, AT_RUID, XXX);
+ AUXINFO(aux_vec, AT_RGID, XXX);
+#endif
+ AUXINFO(aux_vec, AT_EUID, execi->args.new_uid);
+ AUXINFO(aux_vec, AT_EGID, execi->args.new_gid);
+ AUXINFO(aux_vec, AT_PAGESZ, PAGE_SIZE);
- /* Empty space starts here, if any. */
- if((execi->userflags & PMEF_EXECNAMESPACE1)
- && strlen(execi->execname) < PMEF_EXECNAMELEN1) {
+ if(execname_len < PMEF_EXECNAMELEN1) {
char *spacestart;
vir_bytes userp;
- /* Make space for the real closing AT_NULL entry. */
- AUXINFO(AT_NULL, 0);
-
- /* Empty space starts here; we can put the name here. */
- spacestart = (char *) a;
- strlcpy(spacestart, execi->execname, PATH_MAX);
+ /* Empty space starts after aux_vec table; we can put the name
+ * here. */
+ spacestart = (char *) aux_vec + 2 * sizeof(AuxInfo);
+ strlcpy(spacestart, execi->execname, PMEF_EXECNAMELEN1);
+ memset(spacestart + execname_len, '\0',
+ PMEF_EXECNAMELEN1 - execname_len);
/* What will the address of the string for the user be */
- userp = *newsp + (spacestart-frame);
+ userp = *vsp + (spacestart - frame);
/* Move back to where the AT_NULL is */
- a = term;
- AUXINFO(AT_SUN_EXECNAME, userp);
- AUXINFO(AT_NULL, 0);
+ AUXINFO(aux_vec, AT_SUN_EXECNAME, userp);
}
+ /* Always terminate with AT_NULL */
+ AUXINFO(aux_vec, AT_NULL, 0);
+
return OK;
}
/*===========================================================================*
* patch_stack *
*===========================================================================*/
-static int patch_stack(vp, stack, stk_bytes, path)
+static int patch_stack(vp, stack, stk_bytes, path, vsp)
struct vnode *vp; /* pointer for open script file */
char stack[ARG_MAX]; /* pointer to stack image within VFS */
size_t *stk_bytes; /* size of initial stack */
char path[PATH_MAX]; /* path to script file */
+vir_bytes *vsp;
{
/* Patch the argument vector to include the path name of the script to be
* interpreted, and all strings on the #! line. Returns the path name of
char buf[_MAX_BLOCK_SIZE];
/* Make 'path' the new argv[0]. */
- if (!insert_arg(stack, stk_bytes, path, REPLACE)) return(ENOMEM);
+ if (!insert_arg(stack, stk_bytes, path, vsp, REPLACE)) return(ENOMEM);
pos = 0; /* Read from the start of the file */
/* Issue request */
r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, pos, READING, VFS_PROC_NR,
(vir_bytes) buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io);
+
if (r != OK) return(r);
n = vp->v_size;
while (sp > path && sp[-1] != ' ' && sp[-1] != '\t') --sp;
interp = sp;
- if (!insert_arg(stack, stk_bytes, sp, INSERT)) {
+ if (!insert_arg(stack, stk_bytes, sp, vsp, INSERT)) {
printf("VFS: patch_stack: insert_arg failed\n");
return(ENOMEM);
}
if(!interp)
return ENOEXEC;
- /* Round *stk_bytes up to the size of a pointer for alignment contraints. */
- *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE;
-
if (interp != path)
memmove(path, interp, strlen(interp)+1);
+
return(OK);
}
/*===========================================================================*
* insert_arg *
*===========================================================================*/
-static int insert_arg(
-char stack[ARG_MAX], /* pointer to stack image within PM */
-size_t *stk_bytes, /* size of initial stack */
-char *arg, /* argument to prepend/replace as new argv[0] */
-int replace
-)
+static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg,
+ vir_bytes *vsp, char replace)
{
-/* Patch the stack so that arg will become argv[0]. Be careful, the stack may
- * be filled with garbage, although it normally looks like this:
- * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
- * followed by the strings "pointed" to by the argv[i] and the envp[i]. The
- * pointers are really offsets from the start of stack.
- * Return true iff the operation succeeded.
- */
- int offset;
- vir_bytes a0, a1;
- size_t old_bytes = *stk_bytes;
-
- /* Prepending arg adds at least one string and a zero byte. */
- offset = strlen(arg) + 1;
-
- a0 = (int) ((char **) stack)[1]; /* argv[0] */
- if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE);
-
- a1 = a0; /* a1 will point to the strings to be moved */
- if (replace) {
- /* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */
- do {
- if (a1 == old_bytes) return(FALSE);
- --offset;
- } while (stack[a1++] != 0);
- } else {
- offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */
- a0 += PTRSIZE; /* location of new argv[0][]. */
- }
+ /* Patch the stack so that arg will become argv[0]. Be careful, the
+ * stack may be filled with garbage, although it normally looks like
+ * this:
+ * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
+ * followed by the strings "pointed" to by the argv[i] and the envp[i].
+ * The * pointers are in the new process address space.
+ *
+ * Return true iff the operation succeeded.
+ */
+ struct ps_strings *psp;
+ int offset;
+ size_t old_bytes = *stk_bytes;
+
+ int const arg_len = strlen(arg) + 1;
+
+ /* Offset to argv[0][0] in the stack frame. */
+ int const a0 = (int)(((char **)stack)[1] - *vsp);
- /* stack will grow by offset bytes (or shrink by -offset bytes) */
- if ((*stk_bytes += offset) > ARG_MAX) return(FALSE);
+ /* Check that argv[0] points within the stack frame. */
+ if ((a0 < 0) || (a0 >= old_bytes)) {
+ printf("vfs:: argv[0][] not within stack range!! %i\n", a0);
+ return FALSE;
+ }
- /* Reposition the strings by offset bytes */
- memmove(stack + a1 + offset, stack + a1, old_bytes - a1);
+ if (!replace) {
+ /* Prepending arg adds one pointer, one string and a zero byte. */
+ offset = arg_len + PTRSIZE;
+ } else {
+ /* replacing argv[0] with arg adds the difference in length of
+ * the two strings. Make sure we don't go beyond the stack size
+ * when computing the length of the current argv[0]. */
+ offset = arg_len - strnlen(stack + a0, ARG_MAX - a0 - 1);
+ }
- strlcpy(stack + a0, arg, PATH_MAX); /* Put arg in the new space. */
+ /* As ps_strings follows the strings, ensure the offset is word aligned. */
+ offset = offset + (PTRSIZE - ((PTRSIZE + offset) % PTRSIZE));
- if (!replace) {
- /* Make space for a new argv[0]. */
- memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
+ /* The stack will grow (or shrink) by offset bytes. */
+ if ((*stk_bytes += offset) > ARG_MAX) {
+ printf("vfs:: offset too big!! %d (max %d)\n", *stk_bytes,
+ ARG_MAX);
+ return FALSE;
+ }
- ((char **) stack)[0]++; /* nargs++; */
- }
- /* Now patch up argv[] and envp[] by offset. */
- libexec_patch_ptr(stack, (vir_bytes) offset);
- ((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */
- return(TRUE);
+ /* Reposition the strings by offset bytes */
+ memmove(stack + a0 + offset, stack + a0, old_bytes - a0);
+
+ /* Put arg in the new space, leaving padding in front of it. */
+ strlcpy(stack + a0 + offset - arg_len, arg, arg_len);
+
+ if (!replace) {
+ /* Make space for a new argv[0]. */
+ memmove(stack + 2 * PTRSIZE,
+ stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
+
+ ((char **) stack)[0]++; /* nargs++; */
+ }
+
+ /* set argv[0] correctly */
+ ((char **) stack)[1] = (char *) a0 - arg_len + *vsp;
+
+ /* Update stack pointer in the process address space. */
+ *vsp -= offset;
+
+ /* Update argv and envp in ps_strings */
+ psp = (struct ps_strings *) (stack + *stk_bytes - sizeof(struct ps_strings));
+ psp->ps_argvstr -= (offset / PTRSIZE);
+ if (!replace) {
+ psp->ps_nargvstr++;
+ }
+ psp->ps_envstr = psp->ps_argvstr + psp->ps_nargvstr + 1;
+
+ return TRUE;
}
/*===========================================================================*
case PM_EXEC:
{
endpoint_t proc_e;
- vir_bytes exec_path, stack_frame;
+ vir_bytes exec_path, stack_frame, ps_str;
size_t exec_path_len, stack_frame_len;
proc_e = job_m_in.PM_PROC;
- exec_path = (vir_bytes) job_m_in.PM_PATH;
- exec_path_len = (size_t) job_m_in.PM_PATH_LEN;
- stack_frame = (vir_bytes) job_m_in.PM_FRAME;
- stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN;
+ exec_path = (vir_bytes)job_m_in.PM_PATH;
+ exec_path_len = (size_t)job_m_in.PM_PATH_LEN;
+ stack_frame = (vir_bytes)job_m_in.PM_FRAME;
+ stack_frame_len = (size_t)job_m_in.PM_FRAME_LEN;
+ ps_str = (vir_bytes)job_m_in.PM_PS_STR;
r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame,
- stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS);
+ stack_frame_len, &pc, &newsp, &ps_str,
+ job_m_in.PM_EXECFLAGS);
/* Reply status to PM */
m_out.m_type = PM_EXEC_REPLY;
m_out.PM_PROC = proc_e;
- m_out.PM_PC = (void*) pc;
+ m_out.PM_PC = (void *)pc;
m_out.PM_STATUS = r;
- m_out.PM_NEWSP = (void *) newsp;
+ m_out.PM_NEWSP = (void *)newsp;
+ m_out.PM_NEWPS_STR = ps_str;
}
break;
/* exec.c */
int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, vir_bytes frame,
- size_t frame_len, vir_bytes *pc, vir_bytes *newsp, int flags);
+ size_t frame_len, vir_bytes *pc, vir_bytes *newsp, vir_bytes *ps_str,
+ int flags);
/* filedes.c */
void *do_filp_gc(void *arg);
#include <minix/bitmap.h>
#include <minix/rs.h>
+#include <sys/exec.h>
+
#include <libexec.h>
#include <ctype.h>
#include <errno.h>
#include "kernel/proc.h"
#include <signal.h>
+#include <lib.h>
/* Table of calls and a macro to test for being in range. */
struct {
};
static int libexec_copy_physcopy(struct exec_info *execi,
- off_t off, vir_bytes vaddr, size_t len)
+ off_t off, vir_bytes vaddr, size_t len)
{
vir_bytes end;
struct vm_exec_info *ei = execi->opaque;
end = ei->ip->start_addr + ei->ip->len;
- assert(ei->ip->start_addr + off + len <= end);
- return sys_physcopy(NONE, ei->ip->start_addr + off,
+ assert(ei->ip->start_addr + off + len <= end);
+ return sys_physcopy(NONE, ei->ip->start_addr + off,
execi->proc_e, vaddr, len);
}
struct exec_info *execi = &vmexeci.execi;
char hdr[VM_PAGE_SIZE];
+ size_t frame_size = 0; /* Size of the new initial stack. */
+ int argc = 0; /* Argument count. */
+ int envc = 0; /* Environment count */
+ char overflow = 0; /* No overflow yet. */
+ struct ps_strings *psp;
+
+ int vsp = 0; /* (virtual) Stack pointer in new address space. */
+ char *argv[] = { ip->proc_name, NULL };
+ char *envp[] = { NULL };
+ char *path = ip->proc_name;
+ char frame[VM_PAGE_SIZE];
+
memset(&vmexeci, 0, sizeof(vmexeci));
if(pt_new(&vmp->vm_pt) != OK)
(vir_bytes) hdr, sizeof(hdr)) != OK)
panic("can't look at boot proc header");
- execi->stack_high = kernel_boot_info.user_sp;
- execi->stack_size = DEFAULT_STACK_LIMIT;
- execi->proc_e = vmp->vm_endpoint;
- execi->hdr = hdr;
- execi->hdr_len = sizeof(hdr);
- strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname));
- execi->frame_len = 0;
+ execi->stack_high = kernel_boot_info.user_sp;
+ execi->stack_size = DEFAULT_STACK_LIMIT;
+ execi->proc_e = vmp->vm_endpoint;
+ execi->hdr = hdr;
+ execi->hdr_len = sizeof(hdr);
+ strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname));
+ execi->frame_len = 0;
execi->opaque = &vmexeci;
execi->filesize = ip->len;
vmexeci.ip = ip;
vmexeci.vmp = vmp;
- /* callback functions and data */
- execi->copymem = libexec_copy_physcopy;
- execi->clearproc = NULL;
- execi->clearmem = libexec_clear_sys_memset;
+ /* callback functions and data */
+ execi->copymem = libexec_copy_physcopy;
+ execi->clearproc = NULL;
+ execi->clearmem = libexec_clear_sys_memset;
execi->allocmem_prealloc_junk = libexec_alloc_vm_prealloc;
execi->allocmem_prealloc_cleared = libexec_alloc_vm_prealloc;
- execi->allocmem_ondemand = libexec_alloc_vm_ondemand;
+ execi->allocmem_ondemand = libexec_alloc_vm_ondemand;
- if(libexec_load_elf(execi) != OK)
+ if (libexec_load_elf(execi) != OK)
panic("vm: boot process load of process %s (ep=%d) failed\n",
- execi->progname,vmp->vm_endpoint);
+ execi->progname, vmp->vm_endpoint);
+
+ /* Setup a minimal stack. */
+ minix_stack_params(path, argv, envp, &frame_size, &overflow, &argc,
+ &envc);
- if(sys_exec(vmp->vm_endpoint, (char *) execi->stack_high - 12,
- (char *) ip->proc_name, execi->pc) != OK)
- panic("vm: boot process exec of process %s (ep=%d) failed\n",
+ /* The party is off if there is an overflow, or it is too big for our
+ * pre-allocated space. */
+ if(overflow || frame_size > sizeof(frame))
+ panic("vm: could not alloc stack for boot process %s (ep=%d)\n",
+ execi->progname, vmp->vm_endpoint);
+
+ minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame, &vsp,
+ &psp);
+
+ if(handle_memory(vmp, vsp, frame_size, 1, NULL, NULL, 0) != OK)
+ panic("vm: could not map stack for boot process %s (ep=%d)\n",
+ execi->progname, vmp->vm_endpoint);
+
+ if(sys_datacopy(SELF, (vir_bytes)frame, vmp->vm_endpoint, vsp, frame_size) != OK)
+ panic("vm: could not copy stack for boot process %s (ep=%d)\n",
+ execi->progname, vmp->vm_endpoint);
+
+ if(sys_exec(vmp->vm_endpoint, (char *)vsp, execi->progname, execi->pc,
+ vsp + ((int)psp - (int)frame)) != OK)
+ panic("vm: boot process exec of process %s (ep=%d) failed\n",
execi->progname,vmp->vm_endpoint);
/* make it runnable */
init_proc(VM_PROC_NR);
pt_init();
+ /* Acquire kernel ipc vectors that weren't available
+ * before VM had determined kernel mappings
+ */
+ __minix_init();
+
/* The kernel's freelist does not include boot-time modules; let
* the allocator know that the total memory is bigger.
*/
/* Initialize the structures for queryexit */
init_query_exit();
-
- /* Acquire kernel ipc vectors that weren't available
- * before VM had determined kernel mappings
- */
- __minix_init();
}
/*===========================================================================*
- * sef_cb_signal_handler *
+ * sef_cb_signal_handler *
*===========================================================================*/
static void sef_cb_signal_handler(int signo)
{
}
/*===========================================================================*
- * map_service *
+ * map_service *
*===========================================================================*/
static int map_service(struct rprocpub *rpub)
{
62
.endif # ${MACHINE_ARCH} == "i386"
-.if ${MACHINE_ARCH} == "earm"
-# LSC Not yet supported on ARM
-MKPIC:= no
-LDSTATIC:= -static
-.endif
-
.for t in ${MINIX_TESTS}
PROGS+= test${t}
.endfor