Pull thermal into release branch
[sfrench/cifs-2.6.git] / arch / ia64 / ia32 / ia32_ldt.c
1 /*
2  * Copyright (C) 2001, 2004 Hewlett-Packard Co
3  *      David Mosberger-Tang <davidm@hpl.hp.com>
4  *
5  * Adapted from arch/i386/kernel/ldt.c
6  */
7
8 #include <linux/errno.h>
9 #include <linux/sched.h>
10 #include <linux/string.h>
11 #include <linux/mm.h>
12 #include <linux/smp.h>
13 #include <linux/vmalloc.h>
14
15 #include <asm/uaccess.h>
16
17 #include "ia32priv.h"
18
19 /*
20  * read_ldt() is not really atomic - this is not a problem since synchronization of reads
21  * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
22  * to protect the security checks done on new descriptors.
23  */
24 static int
25 read_ldt (void __user *ptr, unsigned long bytecount)
26 {
27         unsigned long bytes_left, n;
28         char __user *src, *dst;
29         char buf[256];  /* temporary buffer (don't overflow kernel stack!) */
30
31         if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
32                 bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
33
34         bytes_left = bytecount;
35
36         src = (void __user *) IA32_LDT_OFFSET;
37         dst = ptr;
38
39         while (bytes_left) {
40                 n = sizeof(buf);
41                 if (n > bytes_left)
42                         n = bytes_left;
43
44                 /*
45                  * We know we're reading valid memory, but we still must guard against
46                  * running out of memory.
47                  */
48                 if (__copy_from_user(buf, src, n))
49                         return -EFAULT;
50
51                 if (copy_to_user(dst, buf, n))
52                         return -EFAULT;
53
54                 src += n;
55                 dst += n;
56                 bytes_left -= n;
57         }
58         return bytecount;
59 }
60
61 static int
62 read_default_ldt (void __user * ptr, unsigned long bytecount)
63 {
64         unsigned long size;
65         int err;
66
67         /* XXX fix me: should return equivalent of default_ldt[0] */
68         err = 0;
69         size = 8;
70         if (size > bytecount)
71                 size = bytecount;
72
73         err = size;
74         if (clear_user(ptr, size))
75                 err = -EFAULT;
76
77         return err;
78 }
79
80 static int
81 write_ldt (void __user * ptr, unsigned long bytecount, int oldmode)
82 {
83         struct ia32_user_desc ldt_info;
84         __u64 entry;
85         int ret;
86
87         if (bytecount != sizeof(ldt_info))
88                 return -EINVAL;
89         if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
90                 return -EFAULT;
91
92         if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
93                 return -EINVAL;
94         if (ldt_info.contents == 3) {
95                 if (oldmode)
96                         return -EINVAL;
97                 if (ldt_info.seg_not_present == 0)
98                         return -EINVAL;
99         }
100
101         if (ldt_info.base_addr == 0 && ldt_info.limit == 0
102             && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
103                             && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
104                             && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
105                 /* allow LDTs to be cleared by the user */
106                 entry = 0;
107         else
108                 /* we must set the "Accessed" bit as IVE doesn't emulate it */
109                 entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
110                                             (((ldt_info.read_exec_only ^ 1) << 1)
111                                              | (ldt_info.contents << 2)) | 1,
112                                             1, 3, ldt_info.seg_not_present ^ 1,
113                                             (oldmode ? 0 : ldt_info.useable),
114                                             ldt_info.seg_32bit,
115                                             ldt_info.limit_in_pages);
116         /*
117          * Install the new entry.  We know we're accessing valid (mapped) user-level
118          * memory, but we still need to guard against out-of-memory, hence we must use
119          * put_user().
120          */
121         ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number);
122         ia32_load_segment_descriptors(current);
123         return ret;
124 }
125
126 asmlinkage int
127 sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
128 {
129         int ret = -ENOSYS;
130
131         switch (func) {
132               case 0:
133                 ret = read_ldt(compat_ptr(ptr), bytecount);
134                 break;
135               case 1:
136                 ret = write_ldt(compat_ptr(ptr), bytecount, 1);
137                 break;
138               case 2:
139                 ret = read_default_ldt(compat_ptr(ptr), bytecount);
140                 break;
141               case 0x11:
142                 ret = write_ldt(compat_ptr(ptr), bytecount, 0);
143                 break;
144         }
145         return ret;
146 }