summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2009-03-04 12:14:33 +0000
committerdchagin <dchagin@FreeBSD.org>2009-03-04 12:14:33 +0000
commit45cda70b8f7151a76c1a1bc83aaa3acc0f361054 (patch)
tree62f76cca88478d27784a620e697797cefd2ec667
parente609fbb43b577bbe85d61ed52b9fcec80adeb290 (diff)
downloadFreeBSD-src-45cda70b8f7151a76c1a1bc83aaa3acc0f361054.zip
FreeBSD-src-45cda70b8f7151a76c1a1bc83aaa3acc0f361054.tar.gz
Add AT_PLATFORM, AT_HWCAP and AT_CLKTCK auxiliary vector entries which
are used by glibc. This silents the message "2.4+ kernel w/o ELF notes?" from some programs at start, among them are top and pkill. Do the assignment of the vector entries in elf_linux_fixup() as it is done in glibc. Fix some minor style issues. Submitted by: Marcin Cieslak <saper at SYSTEM PL> Approved by: kib (mentor) MFC after: 1 week
-rw-r--r--sys/amd64/linux32/linux.h4
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c48
-rw-r--r--sys/compat/linux/linux_misc.c32
-rw-r--r--sys/compat/linux/linux_misc.h15
-rw-r--r--sys/i386/linux/linux.h4
-rw-r--r--sys/i386/linux/linux_sysvec.c166
6 files changed, 218 insertions, 51 deletions
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h
index e0ffcdf..94372d6 100644
--- a/sys/amd64/linux32/linux.h
+++ b/sys/amd64/linux32/linux.h
@@ -108,6 +108,10 @@ typedef struct {
#define LINUX_CTL_MAXNAME 10
+#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
+ * Keep this synchronized with
+ * elf_linux_fixup() code.
+ */
struct l___sysctl_args
{
l_uintptr_t name;
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index bcb6069..312687a 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux32/linux32_proto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
@@ -106,6 +107,8 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
#define LINUX_SYS_linux_rt_sendsig 0
#define LINUX_SYS_linux_sendsig 0
+const char *linux_platform = "i686";
+static int linux_szplatform;
extern char linux_sigcode[];
extern int linux_szsigcode;
@@ -246,7 +249,12 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
{
Elf32_Auxargs *args;
Elf32_Addr *base;
- Elf32_Addr *pos;
+ Elf32_Addr *pos, *uplatform;
+ struct linux32_ps_strings *arginfo;
+
+ arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
+ uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
+ linux_szplatform);
KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
@@ -254,8 +262,8 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
args = (Elf32_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
- if (args->execfd != -1)
- AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
+ AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
+ AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, hz);
AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
@@ -263,10 +271,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
+ AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
+ AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
+ if (args->execfd != -1)
+ AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY_32(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
@@ -857,23 +869,27 @@ linux_copyout_strings(struct image_params *imgp)
char *stringp, *destp;
u_int32_t *stack_base;
struct linux32_ps_strings *arginfo;
- int sigcodesz;
/*
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
- sigcodesz = *(imgp->proc->p_sysent->sv_szsigcode);
- destp = (caddr_t)arginfo - sigcodesz - SPARE_USRSPACE -
- roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
+ destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
+ linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
+ sizeof(char *));
/*
* install sigcode
*/
- if (sigcodesz)
- copyout(imgp->proc->p_sysent->sv_sigcode,
- ((caddr_t)arginfo - sigcodesz), sigcodesz);
+ copyout(imgp->proc->p_sysent->sv_sigcode,
+ ((caddr_t)arginfo - linux_szsigcode), linux_szsigcode);
+
+ /*
+ * Install LINUX_PLATFORM
+ */
+ copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
+ linux_szplatform), linux_szplatform);
/*
* If we have a valid auxargs ptr, prepare some room
@@ -885,7 +901,7 @@ linux_copyout_strings(struct image_params *imgp)
* lower compatibility.
*/
imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
- (AT_COUNT * 2);
+ (LINUX_AT_COUNT * 2);
/*
* The '+ 2' is for the null pointers at the end of each of
* the arg and env vector sets,and imgp->auxarg_size is room
@@ -919,14 +935,14 @@ linux_copyout_strings(struct image_params *imgp)
/*
* Fill in "ps_strings" struct for ps, w, etc.
*/
- suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp);
+ suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
suword32(&arginfo->ps_nargvstr, argc);
/*
* Fill in argument portion of vector table.
*/
for (; argc > 0; --argc) {
- suword32(vectp++, (u_int32_t)(intptr_t)destp);
+ suword32(vectp++, (uint32_t)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
@@ -935,14 +951,14 @@ linux_copyout_strings(struct image_params *imgp)
/* a null vector table pointer separates the argp's from the envp's */
suword32(vectp++, 0);
- suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp);
+ suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
suword32(&arginfo->ps_nenvstr, envc);
/*
* Fill in environment portion of vector table.
*/
for (; envc > 0; --envc) {
- suword32(vectp++, (u_int32_t)(intptr_t)destp);
+ suword32(vectp++, (uint32_t)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
@@ -1089,6 +1105,8 @@ linux_elf_modevent(module_t mod, int type, void *data)
linux_schedtail, NULL, 1000);
linux_exec_tag = EVENTHANDLER_REGISTER(process_exec,
linux_proc_exec, NULL, 1000);
+ linux_szplatform = roundup(strlen(linux_platform) + 1,
+ sizeof(char *));
if (bootverbose)
printf("Linux ELF exec handler installed\n");
} else
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index bdbb5dd..82bd7b9 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -92,10 +92,6 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.h>
-#ifdef __i386__
-#include <machine/cputypes.h>
-#endif
-
#define BSD_TO_LINUX_SIGNAL(sig) \
(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
@@ -731,34 +727,8 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args)
*p = '\0';
break;
}
-#ifdef __i386__
- {
- const char *class;
+ strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME);
- switch (cpu_class) {
- case CPUCLASS_686:
- class = "i686";
- break;
- case CPUCLASS_586:
- class = "i586";
- break;
- case CPUCLASS_486:
- class = "i486";
- break;
- default:
- class = "i386";
- }
- strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
- }
-#elif defined(__amd64__) /* XXX: Linux can change 'personality'. */
-#ifdef COMPAT_LINUX32
- strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
-#else
- strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
-#endif /* COMPAT_LINUX32 */
-#else /* something other than i386 or amd64 - assume we and Linux agree */
- strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
-#endif /* __i386__ */
mtx_lock(&hostname_mtx);
strlcpy(utsname.domainname, V_domainname, LINUX_MAX_UTSNAME);
mtx_unlock(&hostname_mtx);
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index c80a432..37991f3 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -45,4 +45,19 @@
#define LINUX_MREMAP_MAYMOVE 1
#define LINUX_MREMAP_FIXED 2
+extern const char *linux_platform;
+
+/*
+ * Non-standard aux entry types used in Linux ELF binaries.
+ */
+
+#define LINUX_AT_PLATFORM 15 /* String identifying CPU */
+#define LINUX_AT_HWCAP 16 /* CPU capabilities */
+#define LINUX_AT_CLKTCK 17 /* frequency at which times() increments */
+#define LINUX_AT_SECURE 23 /* secure mode boolean */
+#define LINUX_AT_BASE_PLATFORM 24 /* string identifying real platform, may
+ * differ from AT_PLATFORM.
+ */
+#define LINUX_AT_EXECFN 31 /* filename of program */
+
#endif /* _LINUX_MISC_H_ */
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h
index f9c7ee5..ca01c89 100644
--- a/sys/i386/linux/linux.h
+++ b/sys/i386/linux/linux.h
@@ -102,6 +102,10 @@ typedef struct {
#define LINUX_CTL_MAXNAME 10
+#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
+ * Keep this synchronized with
+ * elf_linux_fixup() code.
+ */
struct l___sysctl_args
{
l_int *name;
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 42365fb..c98fe14 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_param.h>
#include <machine/cpu.h>
+#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
@@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <i386/linux/linux_proto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
@@ -107,6 +109,10 @@ static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
static void exec_linux_setregs(struct thread *td, u_long entry,
u_long stack, u_long ps_strings);
+static register_t *linux_copyout_strings(struct image_params *imgp);
+
+static int linux_szplatform;
+const char *linux_platform;
extern LIST_HEAD(futex_list, futex) futex_list;
extern struct sx futex_sx;
@@ -231,22 +237,30 @@ linux_fixup(register_t **stack_base, struct image_params *imgp)
**stack_base = (intptr_t)(void *)argv;
(*stack_base)--;
**stack_base = imgp->args->argc;
- return 0;
+ return (0);
}
static int
elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
{
+ struct proc *p;
Elf32_Auxargs *args;
+ Elf32_Addr *uplatform;
+ struct ps_strings *arginfo;
register_t *pos;
KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
+
+ p = imgp->proc;
+ arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
+ linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
- if (args->execfd != -1)
- AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
+ AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
+ AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, hz);
AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
@@ -254,10 +268,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY(pos, AT_BASE, args->base);
+ AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0);
AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
+ AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
+ if (args->execfd != -1)
+ AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
@@ -265,9 +283,125 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
(*stack_base)--;
**stack_base = (register_t)imgp->args->argc;
- return 0;
+ return (0);
}
+/*
+ * Copied from kern/kern_exec.c
+ */
+static register_t *
+linux_copyout_strings(struct image_params *imgp)
+{
+ int argc, envc;
+ char **vectp;
+ char *stringp, *destp;
+ register_t *stack_base;
+ struct ps_strings *arginfo;
+ struct proc *p;
+
+ /*
+ * Calculate string base and vector table pointers.
+ * Also deal with signal trampoline code for this exec type.
+ */
+ p = imgp->proc;
+ arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
+ linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
+ sizeof(char *));
+
+ /*
+ * install sigcode
+ */
+ copyout(p->p_sysent->sv_sigcode, ((caddr_t)arginfo -
+ linux_szsigcode), linux_szsigcode);
+
+ /*
+ * install LINUX_PLATFORM
+ */
+ copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
+ linux_szplatform), linux_szplatform);
+
+ /*
+ * If we have a valid auxargs ptr, prepare some room
+ * on the stack.
+ */
+ if (imgp->auxargs) {
+ /*
+ * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
+ * lower compatibility.
+ */
+ imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
+ (LINUX_AT_COUNT * 2);
+ /*
+ * The '+ 2' is for the null pointers at the end of each of
+ * the arg and env vector sets,and imgp->auxarg_size is room
+ * for argument of Runtime loader.
+ */
+ vectp = (char **)(destp - (imgp->args->argc +
+ imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));
+ } else {
+ /*
+ * The '+ 2' is for the null pointers at the end of each of
+ * the arg and env vector sets
+ */
+ vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) *
+ sizeof(char *));
+ }
+
+ /*
+ * vectp also becomes our initial stack base
+ */
+ stack_base = (register_t *)vectp;
+
+ stringp = imgp->args->begin_argv;
+ argc = imgp->args->argc;
+ envc = imgp->args->envc;
+
+ /*
+ * Copy out strings - arguments and environment.
+ */
+ copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
+
+ /*
+ * Fill in "ps_strings" struct for ps, w, etc.
+ */
+ suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
+ suword(&arginfo->ps_nargvstr, argc);
+
+ /*
+ * Fill in argument portion of vector table.
+ */
+ for (; argc > 0; --argc) {
+ suword(vectp++, (long)(intptr_t)destp);
+ while (*stringp++ != 0)
+ destp++;
+ destp++;
+ }
+
+ /* a null vector table pointer separates the argp's from the envp's */
+ suword(vectp++, 0);
+
+ suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
+ suword(&arginfo->ps_nenvstr, envc);
+
+ /*
+ * Fill in environment portion of vector table.
+ */
+ for (; envc > 0; --envc) {
+ suword(vectp++, (long)(intptr_t)destp);
+ while (*stringp++ != 0)
+ destp++;
+ destp++;
+ }
+
+ /* end of vector table is a null pointer */
+ suword(vectp, 0);
+
+ return (stack_base);
+}
+
+
+
extern int _ucodesel, _udatasel;
extern unsigned long linux_sznonrtsigcode;
@@ -808,6 +942,25 @@ exec_linux_setregs(struct thread *td, u_long entry,
fldcw(&control);
}
+static void
+linux_get_machine(const char **dst)
+{
+
+ switch (cpu_class) {
+ case CPUCLASS_686:
+ *dst = "i686";
+ break;
+ case CPUCLASS_586:
+ *dst = "i586";
+ break;
+ case CPUCLASS_486:
+ *dst = "i486";
+ break;
+ default:
+ *dst = "i386";
+ }
+}
+
struct sysentvec linux_sysvec = {
.sv_size = LINUX_SYS_MAXSYSCALL,
.sv_table = linux_sysent,
@@ -863,7 +1016,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
.sv_stackprot = VM_PROT_ALL,
- .sv_copyout_strings = exec_copyout_strings,
+ .sv_copyout_strings = linux_copyout_strings,
.sv_setregs = exec_linux_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
@@ -929,6 +1082,9 @@ linux_elf_modevent(module_t mod, int type, void *data)
NULL, 1000);
linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
NULL, 1000);
+ linux_get_machine(&linux_platform);
+ linux_szplatform = roundup(strlen(linux_platform) + 1,
+ sizeof(char *));
if (bootverbose)
printf("Linux ELF exec handler installed\n");
} else
OpenPOWER on IntegriCloud