4 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
7 #include <linux/errno.h>
8 #include <linux/sched.h>
9 #include <linux/string.h>
11 #include <linux/smp.h>
12 #include <linux/smp_lock.h>
13 #include <linux/vmalloc.h>
15 #include <asm/uaccess.h>
16 #include <asm/system.h>
19 static int read_ldt(void * ptr
, unsigned long bytecount
)
21 void * address
= current
->mm
->segments
;
26 size
= LDT_ENTRIES
*LDT_ENTRY_SIZE
;
28 address
= &default_ldt
;
29 size
= sizeof(default_ldt
);
33 return copy_to_user(ptr
, address
, size
) ? -EFAULT
: size
;
36 static int write_ldt(void * ptr
, unsigned long bytecount
, int oldmode
)
38 struct mm_struct
* mm
= current
->mm
;
39 __u32 entry_1
, entry_2
, *lp
;
41 struct modify_ldt_ldt_s ldt_info
;
44 if (bytecount
!= sizeof(ldt_info
))
47 if (copy_from_user(&ldt_info
, ptr
, sizeof(ldt_info
)))
51 if (ldt_info
.entry_number
>= LDT_ENTRIES
)
53 if (ldt_info
.contents
== 3) {
56 if (ldt_info
.seg_not_present
== 0)
61 * Horrible dependencies! Try to get rid of this. This is wrong,
62 * as it only reloads the ldt for the first process with this
63 * mm. The implications are that you should really make sure that
64 * you have a ldt before you do the first clone(), otherwise
65 * you get strange behaviour (the kernel is safe, it's just user
68 * For no good reason except historical, the GDT index of the LDT
69 * is chosen to follow the index number in the task[] array.
74 ldt
= vmalloc(LDT_ENTRIES
*LDT_ENTRY_SIZE
);
77 memset(ldt
, 0, LDT_ENTRIES
*LDT_ENTRY_SIZE
);
79 * Make sure someone else hasn't allocated it for us ...
82 int i
= current
->tarray_ptr
- &task
[0];
84 set_ldt_desc(gdt
+(i
<<1)+FIRST_LDT_ENTRY
, ldt
, LDT_ENTRIES
);
86 if (atomic_read(&mm
->count
) > 1)
88 "LDT allocated for cloned task!\n");
94 lp
= (__u32
*) ((ldt_info
.entry_number
<< 3) + (char *) mm
->segments
);
96 /* Allow LDTs to be cleared by the user. */
97 if (ldt_info
.base_addr
== 0 && ldt_info
.limit
== 0) {
99 (ldt_info
.contents
== 0 &&
100 ldt_info
.read_exec_only
== 1 &&
101 ldt_info
.seg_32bit
== 0 &&
102 ldt_info
.limit_in_pages
== 0 &&
103 ldt_info
.seg_not_present
== 1 &&
104 ldt_info
.useable
== 0 )) {
111 entry_1
= ((ldt_info
.base_addr
& 0x0000ffff) << 16) |
112 (ldt_info
.limit
& 0x0ffff);
113 entry_2
= (ldt_info
.base_addr
& 0xff000000) |
114 ((ldt_info
.base_addr
& 0x00ff0000) >> 16) |
115 (ldt_info
.limit
& 0xf0000) |
116 ((ldt_info
.read_exec_only
^ 1) << 9) |
117 (ldt_info
.contents
<< 10) |
118 ((ldt_info
.seg_not_present
^ 1) << 15) |
119 (ldt_info
.seg_32bit
<< 22) |
120 (ldt_info
.limit_in_pages
<< 23) |
123 entry_2
|= (ldt_info
.useable
<< 20);
125 /* Install the new entry ... */
134 asmlinkage
int sys_modify_ldt(int func
, void *ptr
, unsigned long bytecount
)
141 ret
= read_ldt(ptr
, bytecount
);
144 ret
= write_ldt(ptr
, bytecount
, 1);
147 ret
= write_ldt(ptr
, bytecount
, 0);