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:
parent
5d04b92e06
commit
cfd3379bb1
29 changed files with 608 additions and 485 deletions
|
@ -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);
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
177
lib/libc/sys-minix/stack_utils.c
Normal file
177
lib/libc/sys-minix/stack_utils.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue