Removing CSU patches

* Removed startup code patches in lib/csu regarding kernel to userland
   ABI.

 * Aligned stack layout on NetBSD stack layout.

 * Generate valid stack pointers instead of offsets by taking into account
   _minix_kerninfo->kinfo->user_sp.

 * Refactored stack generation, by moving part of execve in two
   functions {minix_stack_params(), minix_stack_fill()} and using them
   in execve(), rs and vm.

 * Changed load offset of rtld (ld.so) to:
      execi.args.stack_high - execi.args.stack_size - 0xa00000
   which is 10MB below the main executable stack.

Change-Id: I839daf3de43321cded44105634102d419cb36cec
This commit is contained in:
Lionel Sambuc 2013-09-13 20:12:22 +02:00
parent 5d04b92e06
commit cfd3379bb1
29 changed files with 608 additions and 485 deletions

View file

@ -21,6 +21,14 @@
#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);

View file

@ -549,6 +549,7 @@
#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 */
@ -557,9 +558,7 @@
#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. */
@ -811,11 +810,13 @@
# 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 */
@ -848,6 +849,7 @@
#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 *

View file

@ -15,7 +15,7 @@
#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;
@ -84,6 +84,7 @@ typedef struct {
#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

View file

@ -30,8 +30,8 @@ int _sendcall(endpoint_t who, int type, message *msgptr);
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);

View file

@ -672,7 +672,8 @@ void memory_init(void)
/*===========================================================================*
* 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);
@ -680,6 +681,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *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

View file

@ -3,16 +3,17 @@
* 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];
@ -114,6 +115,8 @@ static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len
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;
@ -134,24 +137,41 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
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");
/* 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);

View file

@ -770,7 +770,8 @@ void memory_init(void)
/*===========================================================================*
* 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));
@ -778,6 +779,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *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,

View file

@ -3,16 +3,17 @@
* 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)
@ -388,6 +389,8 @@ static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len
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;
@ -404,7 +407,7 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
/* 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;
@ -423,14 +426,30 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
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;

View file

@ -192,7 +192,7 @@ void do_ser_debug(void);
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);

View file

@ -41,7 +41,8 @@ int do_exec(struct proc * caller, message * m_ptr)
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);

View file

@ -36,33 +36,16 @@ RCSID("$NetBSD: crt0.S,v 1.1 2012/08/13 02:49:04 matt Exp $")
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,

View file

@ -46,12 +46,4 @@ _ENTRY(__start)
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

View file

@ -80,15 +80,12 @@ struct ps_strings *__ps_strings = 0;
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
@ -129,30 +126,11 @@ _fini(void)
#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;

View file

@ -23,6 +23,6 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
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"

View file

@ -1,6 +1,4 @@
/* execve() - basic program execution call Author: Kees J. Bot
* 21 Jan 1994
*/
/* execve() - basic program execution call */
#include <sys/cdefs.h>
#include "namespace.h"
@ -9,7 +7,9 @@
#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)
@ -17,62 +17,21 @@ __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;
}
@ -82,31 +41,8 @@ int execve(const char *path, char * const *argv, char * const *envp)
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));
@ -116,15 +52,12 @@ int execve(const char *path, char * const *argv, char * const *envp)
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;
}

View file

@ -0,0 +1,177 @@
/* 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;
}

View file

@ -75,33 +75,6 @@ int libexec_clear_memset(struct exec_info *execi, vir_bytes vaddr, size_t len)
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;

View file

@ -55,7 +55,6 @@ struct exec_info {
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);

View file

@ -146,8 +146,8 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale
.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

View file

@ -1,18 +1,17 @@
#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);
}

View file

@ -48,6 +48,7 @@ int do_exec()
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);
@ -59,7 +60,7 @@ int do_exec()
/*===========================================================================*
* do_newexec *
*===========================================================================*/
int do_newexec()
int do_newexec(void)
{
int proc_e, proc_n, allow_setuid;
char *ptr;
@ -127,24 +128,25 @@ int do_newexec()
/*===========================================================================*
* 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;
}
@ -153,11 +155,8 @@ int do_execrestart()
/*===========================================================================*
* 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;
@ -199,7 +198,7 @@ vir_bytes vfs_newsp;
#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);
}

View file

@ -434,7 +434,7 @@ static void handle_vfs_reply()
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;

View file

@ -20,7 +20,8 @@ int do_brk(void);
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);

View file

@ -1,14 +1,15 @@
#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 {
@ -19,98 +20,51 @@ 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;
struct ps_strings *psp;
int vsp = 0; /* (virtual) Stack pointer in new address space. */
char *progname;
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. */
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);
/* 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;
return -1;
}
/* Allocate space for the stack frame. */
frame = (char *) malloc(frame_size);
if (!frame) {
if (overflow) {
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;
/* Allocate space for the stack frame. */
if ((frame = (char *) sbrk(frame_size)) == (char *) -1) {
errno = E2BIG;
return -1;
}
*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;
@ -153,35 +107,36 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
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;
}

View file

@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/exec.h>
#include <sys/param.h>
#include "fproc.h"
#include "path.h"
@ -56,13 +57,13 @@ struct vfs_exec_info {
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);
@ -71,7 +72,7 @@ static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size
/* 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 */
@ -214,16 +215,19 @@ static int vfs_memmap(struct exec_info *execi,
*===========================================================================*/
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;
@ -234,8 +238,6 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
struct lookup resolve;
struct fproc *vmfp = &fproc[VM_PROC_NR];
stackhook_t makestack = NULL;
static int n;
n++;
struct filp *newfilp = NULL;
lock_exec();
@ -271,6 +273,10 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
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;
@ -297,7 +303,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
* 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);
@ -324,8 +331,10 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
/* 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);
@ -389,11 +398,9 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
*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));
@ -433,102 +440,118 @@ pm_execfinal:
return(r);
}
static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *framelen,
vir_bytes *newsp, int *extrabase)
{
AuxInfo *a, *term;
Elf_Ehdr *elf_header;
int nulls;
char **mysp = (char **) frame,
**mysp_end = (char **) ((char *)frame + *framelen);
/* 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) \
)
if(!execi->is_dyn)
static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *frame_size,
vir_bytes *vsp)
{
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)));
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++; }
#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)
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(AT_PHENT, elf_header->e_phentsize);
AUXINFO(AT_PHNUM, elf_header->e_phnum);
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);
AUXINFO(aux_vec, AT_RUID, XXX);
AUXINFO(aux_vec, AT_RGID, XXX);
#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);
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);
/* This is where we add the AT_NULL */
term = a;
/* Always terminate with AT_NULL */
AUXINFO(AT_NULL, 0);
/* 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;
}
@ -547,11 +570,12 @@ static int is_script(struct vfs_exec_info *execi)
/*===========================================================================*
* 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
@ -565,13 +589,14 @@ char path[PATH_MAX]; /* path to script file */
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;
@ -600,7 +625,7 @@ char path[PATH_MAX]; /* path to script file */
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);
}
@ -609,71 +634,91 @@ char path[PATH_MAX]; /* path to script file */
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;
/* 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;
/* Prepending arg adds at least one string and a zero byte. */
offset = strlen(arg) + 1;
int const arg_len = strlen(arg) + 1;
a0 = (int) ((char **) stack)[1]; /* argv[0] */
if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE);
/* Offset to argv[0][0] in the stack frame. */
int const a0 = (int)(((char **)stack)[1] - *vsp);
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][]. */
}
/* 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;
}
/* stack will grow by offset bytes (or shrink by -offset bytes) */
if ((*stk_bytes += offset) > ARG_MAX) return(FALSE);
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);
}
/* Reposition the strings by offset bytes */
memmove(stack + a1 + offset, stack + a1, old_bytes - a1);
/* As ps_strings follows the strings, ensure the offset is word aligned. */
offset = offset + (PTRSIZE - ((PTRSIZE + offset) % PTRSIZE));
strlcpy(stack + a0, arg, PATH_MAX); /* Put arg in the new space. */
/* 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;
}
if (!replace) {
/* Make space for a new argv[0]. */
memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
/* Reposition the strings by offset bytes */
memmove(stack + a0 + offset, stack + a0, old_bytes - a0);
((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);
/* 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;
}
/*===========================================================================*

View file

@ -845,24 +845,27 @@ static void service_pm_postponed(void)
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;

View file

@ -78,7 +78,8 @@ void write_elf_core_file(struct filp *f, int csig, char *exe_name);
/* 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);

View file

@ -17,6 +17,8 @@
#include <minix/bitmap.h>
#include <minix/rs.h>
#include <sys/exec.h>
#include <libexec.h>
#include <ctype.h>
#include <errno.h>
@ -41,6 +43,7 @@ extern int missing_spares;
#include "kernel/proc.h"
#include <signal.h>
#include <lib.h>
/* Table of calls and a macro to test for being in range. */
struct {
@ -214,13 +217,13 @@ struct vm_exec_info {
};
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);
}
@ -256,6 +259,18 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
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)
@ -268,34 +283,55 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
(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);
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",
/* Setup a minimal stack. */
minix_stack_params(path, argv, envp, &frame_size, &overflow, &argc,
&envc);
/* 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 */
@ -352,6 +388,11 @@ void init_vm(void)
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.
*/
@ -450,15 +491,10 @@ void init_vm(void)
/* 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)
{
@ -482,7 +518,7 @@ static void sef_cb_signal_handler(int signo)
}
/*===========================================================================*
* map_service *
* map_service *
*===========================================================================*/
static int map_service(struct rprocpub *rpub)
{

View file

@ -61,12 +61,6 @@ MINIX_TESTS+= \
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