Commit 3feb88562d149f078319e5a1b2f7acaa10251a5c

Authored by Paolo 'Blaisorblade' Giarrusso
Committed by Linus Torvalds
1 parent 54d8d3b5a0

[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
... ... @@ -25,5 +25,9 @@
25 25 typedef struct user_desc user_desc_t;
26 26  
27 27 # endif /* __KERNEL__ */
  28 +
  29 +#define GDT_ENTRY_TLS_MIN_I386 6
  30 +#define GDT_ENTRY_TLS_MIN_X86_64 12
  31 +
28 32 #endif /* _SYSDEP_TLS_H */
arch/um/include/user_util.h
... ... @@ -8,6 +8,9 @@
8 8  
9 9 #include "sysdep/ptrace.h"
10 10  
  11 +/* Copied from kernel.h */
  12 +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  13 +
11 14 #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
12 15  
13 16 extern int mode_tt;
arch/um/os-Linux/sys-i386/Makefile
... ... @@ -3,7 +3,7 @@
3 3 # Licensed under the GPL
4 4 #
5 5  
6   -obj-$(CONFIG_MODE_SKAS) = registers.o
  6 +obj-$(CONFIG_MODE_SKAS) = registers.o tls.o
7 7  
8 8 USER_OBJS := $(obj-y)
9 9  
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