Commit 3feb88562d149f078319e5a1b2f7acaa10251a5c
Committed by
Linus Torvalds
1 parent
54d8d3b5a0
Exists in
master
and in
7 other branches
[PATCH] uml: check for differences in host support
If running on a host not supporting TLS (for instance 2.4) we should report that cleanly to the user, instead of printing not comprehensible "error 5" for that. Additionally, i386 and x86_64 support different ranges for user_desc->entry_number, and we must account for that; we couldn't pass ourselves -1 because we need to override previously existing TLS descriptors which glibc has possibly set, so test at startup the range to use. x86 and x86_64 existing ranges are hardcoded. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Acked-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 8 changed files with 102 additions and 6 deletions Side-by-side Diff
arch/um/include/os.h
... | ... | @@ -173,6 +173,7 @@ |
173 | 173 | extern void os_early_checks(void); |
174 | 174 | extern int can_do_skas(void); |
175 | 175 | extern void os_check_bugs(void); |
176 | +extern void check_host_supports_tls(int *supports_tls, int *tls_min); | |
176 | 177 | |
177 | 178 | /* Make sure they are clear when running in TT mode. Required by |
178 | 179 | * SEGV_MAYBE_FIXABLE */ |
arch/um/include/sysdep-i386/tls.h
arch/um/include/user_util.h
arch/um/os-Linux/sys-i386/Makefile
arch/um/os-Linux/sys-i386/tls.c
1 | +#include <linux/unistd.h> | |
2 | +#include "sysdep/tls.h" | |
3 | +#include "user_util.h" | |
4 | + | |
5 | +static _syscall1(int, get_thread_area, user_desc_t *, u_info); | |
6 | + | |
7 | +/* Checks whether host supports TLS, and sets *tls_min according to the value | |
8 | + * valid on the host. | |
9 | + * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ | |
10 | +void check_host_supports_tls(int *supports_tls, int *tls_min) { | |
11 | + /* Values for x86 and x86_64.*/ | |
12 | + int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; | |
13 | + int i; | |
14 | + | |
15 | + for (i = 0; i < ARRAY_SIZE(val); i++) { | |
16 | + user_desc_t info; | |
17 | + info.entry_number = val[i]; | |
18 | + | |
19 | + if (get_thread_area(&info) == 0) { | |
20 | + *tls_min = val[i]; | |
21 | + *supports_tls = 1; | |
22 | + return; | |
23 | + } else { | |
24 | + if (errno == EINVAL) | |
25 | + continue; | |
26 | + else if (errno == ENOSYS) | |
27 | + *supports_tls = 0; | |
28 | + return; | |
29 | + } | |
30 | + } | |
31 | + | |
32 | + *supports_tls = 0; | |
33 | +} |
arch/um/os-Linux/tls.c
... | ... | @@ -48,8 +48,8 @@ |
48 | 48 | #ifdef UML_CONFIG_MODE_TT |
49 | 49 | #include "linux/unistd.h" |
50 | 50 | |
51 | -_syscall1(int, get_thread_area, user_desc_t *, u_info); | |
52 | -_syscall1(int, set_thread_area, user_desc_t *, u_info); | |
51 | +static _syscall1(int, get_thread_area, user_desc_t *, u_info); | |
52 | +static _syscall1(int, set_thread_area, user_desc_t *, u_info); | |
53 | 53 | |
54 | 54 | int do_set_thread_area_tt(user_desc_t *info) |
55 | 55 | { |
arch/um/sys-i386/tls.c
... | ... | @@ -24,6 +24,10 @@ |
24 | 24 | #include "skas.h" |
25 | 25 | #endif |
26 | 26 | |
27 | +/* If needed we can detect when it's uninitialized. */ | |
28 | +static int host_supports_tls = -1; | |
29 | +int host_gdt_entry_tls_min = -1; | |
30 | + | |
27 | 31 | #ifdef CONFIG_MODE_SKAS |
28 | 32 | int do_set_thread_area_skas(struct user_desc *info) |
29 | 33 | { |
30 | 34 | |
31 | 35 | |
... | ... | @@ -157,11 +161,20 @@ |
157 | 161 | } |
158 | 162 | } |
159 | 163 | |
160 | -/* This in SKAS0 does not need to be used, since we have different host | |
161 | - * processes. Nor will this need to be used when we'll add support to the host | |
164 | +/* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a | |
165 | + * common host process. So this is needed in SKAS0 too. | |
166 | + * | |
167 | + * However, if each thread had a different host process (and this was discussed | |
168 | + * for SMP support) this won't be needed. | |
169 | + * | |
170 | + * And this will not need be used when (and if) we'll add support to the host | |
162 | 171 | * SKAS patch. */ |
172 | + | |
163 | 173 | int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) |
164 | 174 | { |
175 | + if (!host_supports_tls) | |
176 | + return 0; | |
177 | + | |
165 | 178 | /* We have no need whatsoever to switch TLS for kernel threads; beyond |
166 | 179 | * that, that would also result in us calling os_set_thread_area with |
167 | 180 | * userspace_pid[cpu] == 0, which gives an error. */ |
... | ... | @@ -173,6 +186,9 @@ |
173 | 186 | |
174 | 187 | int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) |
175 | 188 | { |
189 | + if (!host_supports_tls) | |
190 | + return 0; | |
191 | + | |
176 | 192 | if (needs_TLS_update(to)) |
177 | 193 | return load_TLS(0, to); |
178 | 194 | |
... | ... | @@ -256,6 +272,9 @@ |
256 | 272 | struct user_desc info; |
257 | 273 | int idx, ret; |
258 | 274 | |
275 | + if (!host_supports_tls) | |
276 | + return -ENOSYS; | |
277 | + | |
259 | 278 | if (copy_from_user(&info, user_desc, sizeof(info))) |
260 | 279 | return -EFAULT; |
261 | 280 | |
... | ... | @@ -287,6 +306,9 @@ |
287 | 306 | { |
288 | 307 | struct user_desc info; |
289 | 308 | |
309 | + if (!host_supports_tls) | |
310 | + return -EIO; | |
311 | + | |
290 | 312 | if (copy_from_user(&info, user_desc, sizeof(info))) |
291 | 313 | return -EFAULT; |
292 | 314 | |
... | ... | @@ -298,6 +320,9 @@ |
298 | 320 | struct user_desc info; |
299 | 321 | int idx, ret; |
300 | 322 | |
323 | + if (!host_supports_tls) | |
324 | + return -ENOSYS; | |
325 | + | |
301 | 326 | if (get_user(idx, &user_desc->entry_number)) |
302 | 327 | return -EFAULT; |
303 | 328 | |
... | ... | @@ -321,6 +346,9 @@ |
321 | 346 | struct user_desc info; |
322 | 347 | int ret; |
323 | 348 | |
349 | + if (!host_supports_tls) | |
350 | + return -EIO; | |
351 | + | |
324 | 352 | ret = get_tls_entry(child, &info, idx); |
325 | 353 | if (ret < 0) |
326 | 354 | goto out; |
... | ... | @@ -330,4 +358,28 @@ |
330 | 358 | out: |
331 | 359 | return ret; |
332 | 360 | } |
361 | + | |
362 | + | |
363 | +/* XXX: This part is probably common to i386 and x86-64. Don't create a common | |
364 | + * file for now, do that when implementing x86-64 support.*/ | |
365 | +static int __init __setup_host_supports_tls(void) { | |
366 | + check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); | |
367 | + if (host_supports_tls) { | |
368 | + printk(KERN_INFO "Host TLS support detected\n"); | |
369 | + printk(KERN_INFO "Detected host type: "); | |
370 | + switch (host_gdt_entry_tls_min) { | |
371 | + case GDT_ENTRY_TLS_MIN_I386: | |
372 | + printk("i386\n"); | |
373 | + break; | |
374 | + case GDT_ENTRY_TLS_MIN_X86_64: | |
375 | + printk("x86_64\n"); | |
376 | + break; | |
377 | + } | |
378 | + } else | |
379 | + printk(KERN_ERR " Host TLS support NOT detected! " | |
380 | + "TLS support inside UML will not work\n"); | |
381 | + return 1; | |
382 | +} | |
383 | + | |
384 | +__initcall(__setup_host_supports_tls); |
include/asm-um/segment.h
1 | 1 | #ifndef __UM_SEGMENT_H |
2 | 2 | #define __UM_SEGMENT_H |
3 | 3 | |
4 | -#include "asm/arch/segment.h" | |
4 | +extern int host_gdt_entry_tls_min; | |
5 | + | |
6 | +#define GDT_ENTRY_TLS_ENTRIES 3 | |
7 | +#define GDT_ENTRY_TLS_MIN host_gdt_entry_tls_min | |
8 | +#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) | |
5 | 9 | |
6 | 10 | #endif |