minix/lib/libexec/exec_general.c
Ben Gras 2d72cbec41 SYSENTER/SYSCALL support
. add cpufeature detection of both
	. use it for both ipc and kernelcall traps, using a register
	  for call number
	. SYSENTER/SYSCALL does not save any context, therefore userland
	  has to save it
	. to accomodate multiple kernel entry/exit types, the entry
	  type is recorded in the process struct. hitherto all types
	  were interrupt (soft int, exception, hard int); now SYSENTER/SYSCALL
	  is new, with the difference that context is not fully restored
	  from proc struct when running the process again. this can't be
	  done as some information is missing.
	. complication: cases in which the kernel has to fully change
	  process context (i.e. sigreturn). in that case the exit type
	  is changed from SYSENTER/SYSEXIT to soft-int (i.e. iret) and
	  context is fully restored from the proc struct. this does mean
	  the PC and SP must change, as the sysenter/sysexit userland code
	  will otherwise try to restore its own context. this is true in the
	  sigreturn case.
	. override all usage by setting libc_ipc=1
2012-09-24 15:53:43 +02:00

107 lines
2.7 KiB
C

#define _SYSTEM 1
#include <minix/type.h>
#include <minix/const.h>
#include <sys/param.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <libexec.h>
#include <string.h>
#include <assert.h>
#include <minix/ipc.h>
#include <minix/com.h>
#include <minix/callnr.h>
#include <minix/vm.h>
#include <minix/ipc.h>
#include <minix/syslib.h>
#include <sys/mman.h>
#include <machine/elf.h>
int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len)
{
if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANON|MAP_PREALLOC|MAP_UNINITIALIZED|MAP_FIXED, -1, 0) == MAP_FAILED) {
return ENOMEM;
}
return OK;
}
int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len)
{
if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED) {
return ENOMEM;
}
return OK;
}
int libexec_clearproc_vm_procctl(struct exec_info *execi)
{
return vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
}
int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len)
{
return sys_memset(execi->proc_e, 0, vaddr, len);
}
int libexec_copy_memcpy(struct exec_info *execi,
off_t off, off_t vaddr, size_t len)
{
assert(off + len <= execi->hdr_len);
memcpy((char *) vaddr, (char *) execi->hdr + off, len);
return OK;
}
int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len)
{
memset((char *) vaddr, 0, 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;
message m;
m.m_type = PM_NEWEXEC;
m.EXC_NM_PROC = proc_e;
m.EXC_NM_PTR = (char *)e;
if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r);
e->allow_setuid = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
return(m.m_type);
}