summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2011-01-08 16:13:44 +0000
committerkib <kib@FreeBSD.org>2011-01-08 16:13:44 +0000
commit06eb8de1e11605ee7d4ae2e5c58cdadccc659f0d (patch)
tree89f01dcb94af1295c1d16e6a0cf6aa53ea8dcefc
parent12d561f88acf9296f4d7f1ba98ad4d9a8da70bf3 (diff)
downloadFreeBSD-src-06eb8de1e11605ee7d4ae2e5c58cdadccc659f0d.zip
FreeBSD-src-06eb8de1e11605ee7d4ae2e5c58cdadccc659f0d.tar.gz
Create shared (readonly) page. Each ABI may specify the use of page by
setting SV_SHP flag and providing pointer to the vm object and mapping address. Provide simple allocator to carve space in the page, tailored to put the code with alignment restrictions. Enable shared page use for amd64, both native and 32bit FreeBSD binaries. Page is private mapped at the top of the user address space, moving a start of the stack one page down. Move signal trampoline code from the top of the stack to the shared page. Reviewed by: alc
-rw-r--r--sys/amd64/amd64/elf_machdep.c6
-rw-r--r--sys/amd64/amd64/machdep.c2
-rw-r--r--sys/amd64/ia32/ia32_signal.c5
-rw-r--r--sys/amd64/include/vmparam.h3
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c7
-rw-r--r--sys/compat/ia32/ia32_sysvec.c15
-rw-r--r--sys/compat/ia32/ia32_util.h8
-rw-r--r--sys/kern/kern_exec.c89
-rw-r--r--sys/sys/imgact.h3
-rw-r--r--sys/sys/sysent.h12
10 files changed, 132 insertions, 18 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index 6472d55..4344731 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -75,11 +75,14 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
- .sv_flags = SV_ABI_FREEBSD | SV_LP64,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
+ .sv_shared_page_base = SHAREDPAGE,
+ .sv_shared_page_len = PAGE_SIZE,
};
+INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
static Elf64_Brandinfo freebsd_brand_info = {
.brand = ELFOSABI_FREEBSD,
@@ -129,7 +132,6 @@ SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf64_insert_brand_entry,
&kfreebsd_brand_info);
-
void
elf64_dump_thread(struct thread *td __unused, void *dst __unused,
size_t *off __unused)
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 6c946e6..72e0fd7 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -386,7 +386,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (long)sfp;
- regs->tf_rip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
+ regs->tf_rip = p->p_sysent->sv_sigcode_base;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 808790b..91884d2 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -393,7 +393,8 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (uintptr_t)sfp;
- regs->tf_rip = p->p_sysent->sv_psstrings - sz_freebsd4_ia32_sigcode;
+ regs->tf_rip = p->p_sysent->sv_sigcode_base + sz_ia32_sigcode -
+ sz_freebsd4_ia32_sigcode;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ss = _udatasel;
@@ -514,7 +515,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (uintptr_t)sfp;
- regs->tf_rip = p->p_sysent->sv_psstrings - *(p->p_sysent->sv_szsigcode);
+ regs->tf_rip = p->p_sysent->sv_sigcode_base;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ss = _udatasel;
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
index 7a50c59..88d68b9 100644
--- a/sys/amd64/include/vmparam.h
+++ b/sys/amd64/include/vmparam.h
@@ -186,7 +186,8 @@
#define VM_MAXUSER_ADDRESS UVADDR(NUPML4E, 0, 0, 0)
-#define USRSTACK VM_MAXUSER_ADDRESS
+#define SHAREDPAGE (VM_MAXUSER_ADDRESS - PAGE_SIZE)
+#define USRSTACK SHAREDPAGE
#define VM_MAX_ADDRESS UPT_MAX_ADDRESS
#define VM_MIN_ADDRESS (0)
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 326cf03..cf3af87 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2546,7 +2546,10 @@ freebsd32_copyout_strings(struct image_params *imgp)
execpath_len = 0;
arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent->
sv_psstrings;
- szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
+ if (imgp->proc->p_sysent->sv_sigcode_base == 0)
+ szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
+ else
+ szsigcode = 0;
destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
roundup(execpath_len, sizeof(char *)) -
roundup(sizeof(canary), sizeof(char *)) -
@@ -2556,7 +2559,7 @@ freebsd32_copyout_strings(struct image_params *imgp)
/*
* install sigcode
*/
- if (szsigcode)
+ if (szsigcode != 0)
copyout(imgp->proc->p_sysent->sv_sigcode,
((caddr_t)arginfo - szsigcode), szsigcode);
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index d7ac5d0..058e739 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -129,7 +129,7 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_minsigstksz = MINSIGSTKSZ,
.sv_pagesize = IA32_PAGE_SIZE,
.sv_minuser = 0,
- .sv_maxuser = FREEBSD32_USRSTACK,
+ .sv_maxuser = FREEBSD32_MAXUSER,
.sv_usrstack = FREEBSD32_USRSTACK,
.sv_psstrings = FREEBSD32_PS_STRINGS,
.sv_stackprot = VM_PROT_ALL,
@@ -137,12 +137,20 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_setregs = ia32_setregs,
.sv_fixlimit = ia32_fixlimit,
.sv_maxssiz = &ia32_maxssiz,
- .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32,
+ .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 |
+#ifdef __amd64__
+ SV_SHP
+#else
+ 0
+#endif
+ ,
.sv_set_syscall_retval = ia32_set_syscall_retval,
.sv_fetch_syscall_args = ia32_fetch_syscall_args,
.sv_syscallnames = freebsd32_syscallnames,
+ .sv_shared_page_base = FREEBSD32_SHAREDPAGE,
+ .sv_shared_page_len = PAGE_SIZE,
};
-
+INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);
static Elf32_Brandinfo ia32_brand_info = {
.brand = ELFOSABI_FREEBSD,
@@ -191,7 +199,6 @@ SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf32_insert_brand_entry,
&kia32_brand_info);
-
void
elf32_dump_thread(struct thread *td __unused, void *dst __unused,
size_t *off __unused)
diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h
index f1cc6ed..4355daa 100644
--- a/sys/compat/ia32/ia32_util.h
+++ b/sys/compat/ia32/ia32_util.h
@@ -41,9 +41,13 @@
#include <sys/cdefs.h>
#ifdef __ia64__
-#define FREEBSD32_USRSTACK ((1ul << 32) - IA32_PAGE_SIZE * 2)
+#define FREEBSD32_MAXUSER ((1ul << 32) - IA32_PAGE_SIZE * 2)
+#define FREEBSD32_SHAREDPAGE 0
+#define FREEBSD32_USRSTACK FREEBSD32_MAXUSER
#else
-#define FREEBSD32_USRSTACK ((1ul << 32) - IA32_PAGE_SIZE)
+#define FREEBSD32_MAXUSER ((1ul << 32) - IA32_PAGE_SIZE)
+#define FREEBSD32_SHAREDPAGE (FREEBSD32_MAXUSER - IA32_PAGE_SIZE)
+#define FREEBSD32_USRSTACK FREEBSD32_SHAREDPAGE
#endif
#define IA32_PAGE_SIZE 4096
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 1e4d690..6cf77f7 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -389,6 +389,7 @@ do_execve(td, args, mac_p)
imgp->canarylen = 0;
imgp->pagesizes = 0;
imgp->pagesizeslen = 0;
+ imgp->stack_prot = 0;
#ifdef MAC
error = mac_execve_enter(imgp, mac_p);
@@ -996,6 +997,7 @@ exec_new_vmspace(imgp, sv)
int error;
struct proc *p = imgp->proc;
struct vmspace *vmspace = p->p_vmspace;
+ vm_object_t obj;
vm_offset_t sv_minuser, stack_addr;
vm_map_t map;
u_long ssiz;
@@ -1029,6 +1031,20 @@ exec_new_vmspace(imgp, sv)
map = &vmspace->vm_map;
}
+ /* Map a shared page */
+ obj = sv->sv_shared_page_obj;
+ if (obj != NULL) {
+ vm_object_reference(obj);
+ error = vm_map_fixed(map, obj, 0,
+ sv->sv_shared_page_base, sv->sv_shared_page_len,
+ VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
+ MAP_COPY_ON_WRITE | MAP_ACC_NO_CHARGE);
+ if (error) {
+ vm_object_deallocate(obj);
+ return (error);
+ }
+ }
+
/* Allocate a new stack */
if (sv->sv_maxssiz != NULL)
ssiz = *sv->sv_maxssiz;
@@ -1036,7 +1052,9 @@ exec_new_vmspace(imgp, sv)
ssiz = maxssiz;
stack_addr = sv->sv_usrstack - ssiz;
error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz,
- sv->sv_stackprot, VM_PROT_ALL, MAP_STACK_GROWS_DOWN);
+ obj != NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
+ sv->sv_stackprot,
+ VM_PROT_ALL, MAP_STACK_GROWS_DOWN);
if (error)
return (error);
@@ -1208,8 +1226,10 @@ exec_copyout_strings(imgp)
p = imgp->proc;
szsigcode = 0;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
- if (p->p_sysent->sv_szsigcode != NULL)
- szsigcode = *(p->p_sysent->sv_szsigcode);
+ if (p->p_sysent->sv_sigcode_base == 0) {
+ if (p->p_sysent->sv_szsigcode != NULL)
+ szsigcode = *(p->p_sysent->sv_szsigcode);
+ }
destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
roundup(execpath_len, sizeof(char *)) -
roundup(sizeof(canary), sizeof(char *)) -
@@ -1219,7 +1239,7 @@ exec_copyout_strings(imgp)
/*
* install sigcode
*/
- if (szsigcode)
+ if (szsigcode != 0)
copyout(p->p_sysent->sv_sigcode, ((caddr_t)arginfo -
szsigcode), szsigcode);
@@ -1459,3 +1479,64 @@ exec_unregister(execsw_arg)
execsw = newexecsw;
return (0);
}
+
+static vm_object_t shared_page_obj;
+static int shared_page_free;
+
+int
+shared_page_fill(int size, int align, const char *data)
+{
+ vm_page_t m;
+ struct sf_buf *s;
+ vm_offset_t sk;
+ int res;
+
+ VM_OBJECT_LOCK(shared_page_obj);
+ m = vm_page_grab(shared_page_obj, 0, VM_ALLOC_RETRY);
+ res = roundup(shared_page_free, align);
+ if (res + size >= IDX_TO_OFF(shared_page_obj->size))
+ res = -1;
+ else {
+ VM_OBJECT_UNLOCK(shared_page_obj);
+ s = sf_buf_alloc(m, SFB_DEFAULT);
+ sk = sf_buf_kva(s);
+ bcopy(data, (void *)(sk + res), size);
+ shared_page_free = res + size;
+ sf_buf_free(s);
+ VM_OBJECT_LOCK(shared_page_obj);
+ }
+ vm_page_wakeup(m);
+ VM_OBJECT_UNLOCK(shared_page_obj);
+ return (res);
+}
+
+static void
+shared_page_init(void *dummy __unused)
+{
+ vm_page_t m;
+
+ shared_page_obj = vm_pager_allocate(OBJT_PHYS, 0, PAGE_SIZE,
+ VM_PROT_DEFAULT, 0, NULL);
+ VM_OBJECT_LOCK(shared_page_obj);
+ m = vm_page_grab(shared_page_obj, 0, VM_ALLOC_RETRY | VM_ALLOC_NOBUSY |
+ VM_ALLOC_ZERO);
+ m->valid = VM_PAGE_BITS_ALL;
+ VM_OBJECT_UNLOCK(shared_page_obj);
+}
+
+SYSINIT(shp, SI_SUB_EXEC, SI_ORDER_FIRST, (sysinit_cfunc_t)shared_page_init,
+ NULL);
+
+void
+exec_sysvec_init(void *param)
+{
+ struct sysentvec *sv;
+
+ sv = (struct sysentvec *)param;
+
+ if ((sv->sv_flags & SV_SHP) == 0)
+ return;
+ sv->sv_shared_page_obj = shared_page_obj;
+ sv->sv_sigcode_base = sv->sv_shared_page_base +
+ shared_page_fill(*(sv->sv_szsigcode), 16, sv->sv_sigcode);
+}
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
index b54815f..17cfcc2 100644
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -34,6 +34,8 @@
#include <sys/uio.h>
+#include <vm/vm.h>
+
#define MAXSHELLCMDLEN PAGE_SIZE
struct image_args {
@@ -75,6 +77,7 @@ struct image_params {
int canarylen;
unsigned long pagesizes;
int pagesizeslen;
+ vm_prot_t stack_prot;
};
#ifdef _KERNEL
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index e726fce..55cac2b 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -116,12 +116,17 @@ struct sysentvec {
int (*sv_fetch_syscall_args)(struct thread *, struct
syscall_args *);
const char **sv_syscallnames;
+ vm_offset_t sv_shared_page_base;
+ vm_offset_t sv_shared_page_len;
+ vm_offset_t sv_sigcode_base;
+ void *sv_shared_page_obj;
};
#define SV_ILP32 0x000100
#define SV_LP64 0x000200
#define SV_IA32 0x004000
#define SV_AOUT 0x008000
+#define SV_SHP 0x010000
#define SV_ABI_MASK 0xff
#define SV_CURPROC_FLAG(x) (curproc->p_sysent->sv_flags & (x))
@@ -222,6 +227,13 @@ int lkmressys(struct thread *, struct nosys_args *);
int syscall_thread_enter(struct thread *td, struct sysent *se);
void syscall_thread_exit(struct thread *td, struct sysent *se);
+int shared_page_fill(int size, int align, const char *data);
+void exec_sysvec_init(void *param);
+
+#define INIT_SYSENTVEC(name, sv) \
+ SYSINIT(name, SI_SUB_EXEC, SI_ORDER_ANY, \
+ (sysinit_cfunc_t)exec_sysvec_init, sv);
+
#endif /* _KERNEL */
#endif /* !_SYS_SYSENT_H_ */
OpenPOWER on IntegriCloud