diff options
author | Nathan Lynch <ntl@pobox.com> | 2008-07-21 14:48:46 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-25 01:44:39 -0400 |
commit | 483fad1c3fa1060d7e6710e84a065ad514571739 (patch) | |
tree | 98c2da31a58c71d1ae9c808bdf232cbbbe060550 | |
parent | e9f76354ce83a20c7768ad37caa033f6506b4f96 (diff) |
ELF loader support for auxvec base platform string
Some IBM POWER-based platforms have the ability to run in a
mode which mostly appears to the OS as a different processor from the
actual hardware. For example, a Power6 system may appear to be a
Power5+, which makes the AT_PLATFORM value "power5+". This means that
programs are restricted to the ISA supported by Power5+;
Power6-specific instructions are treated as illegal.
However, some applications (virtual machines, optimized libraries) can
benefit from knowledge of the underlying CPU model. A new aux vector
entry, AT_BASE_PLATFORM, will denote the actual hardware. For
example, on a Power6 system in Power5+ compatibility mode, AT_PLATFORM
will be "power5+" and AT_BASE_PLATFORM will be "power6". The idea is
that AT_PLATFORM indicates the instruction set supported, while
AT_BASE_PLATFORM indicates the underlying microarchitecture.
If the architecture has defined ELF_BASE_PLATFORM, copy that value to
the user stack in the same manner as ELF_PLATFORM.
Signed-off-by: Nathan Lynch <ntl@pobox.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | fs/binfmt_elf.c | 28 | ||||
-rw-r--r-- | include/linux/auxvec.h | 6 |
2 files changed, 33 insertions, 1 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 639d2d8b5710..742c8f530481 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -131,6 +131,15 @@ static int padzero(unsigned long elf_bss) | |||
131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) | 131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) |
132 | #endif | 132 | #endif |
133 | 133 | ||
134 | #ifndef ELF_BASE_PLATFORM | ||
135 | /* | ||
136 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. | ||
137 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value | ||
138 | * will be copied to the user stack in the same manner as AT_PLATFORM. | ||
139 | */ | ||
140 | #define ELF_BASE_PLATFORM NULL | ||
141 | #endif | ||
142 | |||
134 | static int | 143 | static int |
135 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | 144 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, |
136 | unsigned long load_addr, unsigned long interp_load_addr) | 145 | unsigned long load_addr, unsigned long interp_load_addr) |
@@ -142,7 +151,9 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
142 | elf_addr_t __user *envp; | 151 | elf_addr_t __user *envp; |
143 | elf_addr_t __user *sp; | 152 | elf_addr_t __user *sp; |
144 | elf_addr_t __user *u_platform; | 153 | elf_addr_t __user *u_platform; |
154 | elf_addr_t __user *u_base_platform; | ||
145 | const char *k_platform = ELF_PLATFORM; | 155 | const char *k_platform = ELF_PLATFORM; |
156 | const char *k_base_platform = ELF_BASE_PLATFORM; | ||
146 | int items; | 157 | int items; |
147 | elf_addr_t *elf_info; | 158 | elf_addr_t *elf_info; |
148 | int ei_index = 0; | 159 | int ei_index = 0; |
@@ -172,6 +183,19 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
172 | return -EFAULT; | 183 | return -EFAULT; |
173 | } | 184 | } |
174 | 185 | ||
186 | /* | ||
187 | * If this architecture has a "base" platform capability | ||
188 | * string, copy it to userspace. | ||
189 | */ | ||
190 | u_base_platform = NULL; | ||
191 | if (k_base_platform) { | ||
192 | size_t len = strlen(k_base_platform) + 1; | ||
193 | |||
194 | u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); | ||
195 | if (__copy_to_user(u_base_platform, k_base_platform, len)) | ||
196 | return -EFAULT; | ||
197 | } | ||
198 | |||
175 | /* Create the ELF interpreter info */ | 199 | /* Create the ELF interpreter info */ |
176 | elf_info = (elf_addr_t *)current->mm->saved_auxv; | 200 | elf_info = (elf_addr_t *)current->mm->saved_auxv; |
177 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ | 201 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ |
@@ -209,6 +233,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
209 | NEW_AUX_ENT(AT_PLATFORM, | 233 | NEW_AUX_ENT(AT_PLATFORM, |
210 | (elf_addr_t)(unsigned long)u_platform); | 234 | (elf_addr_t)(unsigned long)u_platform); |
211 | } | 235 | } |
236 | if (k_base_platform) { | ||
237 | NEW_AUX_ENT(AT_BASE_PLATFORM, | ||
238 | (elf_addr_t)(unsigned long)u_base_platform); | ||
239 | } | ||
212 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { | 240 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
213 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); | 241 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
214 | } | 242 | } |
diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h index 0da17d14fd13..d7afa9dd6635 100644 --- a/include/linux/auxvec.h +++ b/include/linux/auxvec.h | |||
@@ -26,9 +26,13 @@ | |||
26 | 26 | ||
27 | #define AT_SECURE 23 /* secure mode boolean */ | 27 | #define AT_SECURE 23 /* secure mode boolean */ |
28 | 28 | ||
29 | #define AT_BASE_PLATFORM 24 /* string identifying real platform, may | ||
30 | * differ from AT_PLATFORM. */ | ||
31 | |||
29 | #define AT_EXECFN 31 /* filename of program */ | 32 | #define AT_EXECFN 31 /* filename of program */ |
33 | |||
30 | #ifdef __KERNEL__ | 34 | #ifdef __KERNEL__ |
31 | #define AT_VECTOR_SIZE_BASE 17 /* NEW_AUX_ENT entries in auxiliary table */ | 35 | #define AT_VECTOR_SIZE_BASE 18 /* NEW_AUX_ENT entries in auxiliary table */ |
32 | /* number of "#define AT_.*" above, minus {AT_NULL, AT_IGNORE, AT_NOTELF} */ | 36 | /* number of "#define AT_.*" above, minus {AT_NULL, AT_IGNORE, AT_NOTELF} */ |
33 | #endif | 37 | #endif |
34 | 38 | ||