diff options
author | Roland McGrath <roland@redhat.com> | 2008-01-30 07:30:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:46 -0500 |
commit | efd1ca52d04d2f6df337a3332cee56cd60e6d4c4 (patch) | |
tree | cf1e630d25cc45f399388f5fc996d86cf3bcf9ff /arch/x86/kernel/process_32.c | |
parent | 13abd0e50433092c41551bc13c32268028b6d663 (diff) |
x86: TLS cleanup
This consolidates the four different places that implemented the same
encoding magic for the GDT-slot 32-bit TLS support. The old tls32.c was
renamed and is now only slightly modified to be the shared implementation.
Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Zachary Amsden <zach@vmware.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/process_32.c')
-rw-r--r-- | arch/x86/kernel/process_32.c | 141 |
1 files changed, 5 insertions, 136 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 631af167bc51..4d66a56280d3 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -501,32 +501,15 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | |||
501 | set_tsk_thread_flag(p, TIF_IO_BITMAP); | 501 | set_tsk_thread_flag(p, TIF_IO_BITMAP); |
502 | } | 502 | } |
503 | 503 | ||
504 | err = 0; | ||
505 | |||
504 | /* | 506 | /* |
505 | * Set a new TLS for the child thread? | 507 | * Set a new TLS for the child thread? |
506 | */ | 508 | */ |
507 | if (clone_flags & CLONE_SETTLS) { | 509 | if (clone_flags & CLONE_SETTLS) |
508 | struct desc_struct *desc; | 510 | err = do_set_thread_area(p, -1, |
509 | struct user_desc info; | 511 | (struct user_desc __user *)childregs->esi, 0); |
510 | int idx; | ||
511 | |||
512 | err = -EFAULT; | ||
513 | if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) | ||
514 | goto out; | ||
515 | err = -EINVAL; | ||
516 | if (LDT_empty(&info)) | ||
517 | goto out; | ||
518 | |||
519 | idx = info.entry_number; | ||
520 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
521 | goto out; | ||
522 | |||
523 | desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | ||
524 | desc->a = LDT_entry_a(&info); | ||
525 | desc->b = LDT_entry_b(&info); | ||
526 | } | ||
527 | 512 | ||
528 | err = 0; | ||
529 | out: | ||
530 | if (err && p->thread.io_bitmap_ptr) { | 513 | if (err && p->thread.io_bitmap_ptr) { |
531 | kfree(p->thread.io_bitmap_ptr); | 514 | kfree(p->thread.io_bitmap_ptr); |
532 | p->thread.io_bitmap_max = 0; | 515 | p->thread.io_bitmap_max = 0; |
@@ -872,120 +855,6 @@ unsigned long get_wchan(struct task_struct *p) | |||
872 | return 0; | 855 | return 0; |
873 | } | 856 | } |
874 | 857 | ||
875 | /* | ||
876 | * sys_alloc_thread_area: get a yet unused TLS descriptor index. | ||
877 | */ | ||
878 | static int get_free_idx(void) | ||
879 | { | ||
880 | struct thread_struct *t = ¤t->thread; | ||
881 | int idx; | ||
882 | |||
883 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) | ||
884 | if (desc_empty(t->tls_array + idx)) | ||
885 | return idx + GDT_ENTRY_TLS_MIN; | ||
886 | return -ESRCH; | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | * Set a given TLS descriptor: | ||
891 | */ | ||
892 | asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) | ||
893 | { | ||
894 | struct thread_struct *t = ¤t->thread; | ||
895 | struct user_desc info; | ||
896 | struct desc_struct *desc; | ||
897 | int cpu, idx; | ||
898 | |||
899 | if (copy_from_user(&info, u_info, sizeof(info))) | ||
900 | return -EFAULT; | ||
901 | idx = info.entry_number; | ||
902 | |||
903 | /* | ||
904 | * index -1 means the kernel should try to find and | ||
905 | * allocate an empty descriptor: | ||
906 | */ | ||
907 | if (idx == -1) { | ||
908 | idx = get_free_idx(); | ||
909 | if (idx < 0) | ||
910 | return idx; | ||
911 | if (put_user(idx, &u_info->entry_number)) | ||
912 | return -EFAULT; | ||
913 | } | ||
914 | |||
915 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
916 | return -EINVAL; | ||
917 | |||
918 | desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; | ||
919 | |||
920 | /* | ||
921 | * We must not get preempted while modifying the TLS. | ||
922 | */ | ||
923 | cpu = get_cpu(); | ||
924 | |||
925 | if (LDT_empty(&info)) { | ||
926 | desc->a = 0; | ||
927 | desc->b = 0; | ||
928 | } else { | ||
929 | desc->a = LDT_entry_a(&info); | ||
930 | desc->b = LDT_entry_b(&info); | ||
931 | } | ||
932 | load_TLS(t, cpu); | ||
933 | |||
934 | put_cpu(); | ||
935 | |||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | /* | ||
940 | * Get the current Thread-Local Storage area: | ||
941 | */ | ||
942 | |||
943 | #define GET_BASE(desc) ( \ | ||
944 | (((desc)->a >> 16) & 0x0000ffff) | \ | ||
945 | (((desc)->b << 16) & 0x00ff0000) | \ | ||
946 | ( (desc)->b & 0xff000000) ) | ||
947 | |||
948 | #define GET_LIMIT(desc) ( \ | ||
949 | ((desc)->a & 0x0ffff) | \ | ||
950 | ((desc)->b & 0xf0000) ) | ||
951 | |||
952 | #define GET_32BIT(desc) (((desc)->b >> 22) & 1) | ||
953 | #define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) | ||
954 | #define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) | ||
955 | #define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) | ||
956 | #define GET_PRESENT(desc) (((desc)->b >> 15) & 1) | ||
957 | #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) | ||
958 | |||
959 | asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) | ||
960 | { | ||
961 | struct user_desc info; | ||
962 | struct desc_struct *desc; | ||
963 | int idx; | ||
964 | |||
965 | if (get_user(idx, &u_info->entry_number)) | ||
966 | return -EFAULT; | ||
967 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
968 | return -EINVAL; | ||
969 | |||
970 | memset(&info, 0, sizeof(info)); | ||
971 | |||
972 | desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | ||
973 | |||
974 | info.entry_number = idx; | ||
975 | info.base_addr = GET_BASE(desc); | ||
976 | info.limit = GET_LIMIT(desc); | ||
977 | info.seg_32bit = GET_32BIT(desc); | ||
978 | info.contents = GET_CONTENTS(desc); | ||
979 | info.read_exec_only = !GET_WRITABLE(desc); | ||
980 | info.limit_in_pages = GET_LIMIT_PAGES(desc); | ||
981 | info.seg_not_present = !GET_PRESENT(desc); | ||
982 | info.useable = GET_USEABLE(desc); | ||
983 | |||
984 | if (copy_to_user(u_info, &info, sizeof(info))) | ||
985 | return -EFAULT; | ||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | unsigned long arch_align_stack(unsigned long sp) | 858 | unsigned long arch_align_stack(unsigned long sp) |
990 | { | 859 | { |
991 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) | 860 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) |