[PATCH] some more av7110 dvb-driver updates
[linux-2.6/history.git] / arch / ia64 / ia32 / ia32_ldt.c
blob515503ae08350572b3e260de22af6bd956abe1ba
1 /*
2 * Copyright (C) 2001 Hewlett-Packard Co
3 * David Mosberger-Tang <davidm@hpl.hp.com>
5 * Adapted from arch/i386/kernel/ldt.c
6 */
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/smp_lock.h>
14 #include <linux/vmalloc.h>
16 #include <asm/uaccess.h>
18 #include "ia32priv.h"
20 #define P(p) ((void *) (unsigned long) (p))
23 * read_ldt() is not really atomic - this is not a problem since synchronization of reads
24 * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
25 * to protect the security checks done on new descriptors.
27 static int
28 read_ldt (void *ptr, unsigned long bytecount)
30 char *src, *dst, buf[256]; /* temporary buffer (don't overflow kernel stack!) */
31 unsigned long bytes_left, n;
33 if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
34 bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
36 bytes_left = bytecount;
38 src = (void *) IA32_LDT_OFFSET;
39 dst = ptr;
41 while (bytes_left) {
42 n = sizeof(buf);
43 if (n > bytes_left)
44 n = bytes_left;
47 * We know we're reading valid memory, but we still must guard against
48 * running out of memory.
50 if (__copy_from_user(buf, src, n))
51 return -EFAULT;
53 if (copy_to_user(dst, buf, n))
54 return -EFAULT;
56 src += n;
57 dst += n;
58 bytes_left -= n;
60 return bytecount;
63 static int
64 read_default_ldt (void * ptr, unsigned long bytecount)
66 unsigned long size;
67 int err;
69 /* XXX fix me: should return equivalent of default_ldt[0] */
70 err = 0;
71 size = 8;
72 if (size > bytecount)
73 size = bytecount;
75 err = size;
76 if (clear_user(ptr, size))
77 err = -EFAULT;
79 return err;
82 static int
83 write_ldt (void * ptr, unsigned long bytecount, int oldmode)
85 struct ia32_modify_ldt_ldt_s ldt_info;
86 __u64 entry;
87 int ret;
89 if (bytecount != sizeof(ldt_info))
90 return -EINVAL;
91 if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
92 return -EFAULT;
94 if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
95 return -EINVAL;
96 if (ldt_info.contents == 3) {
97 if (oldmode)
98 return -EINVAL;
99 if (ldt_info.seg_not_present == 0)
100 return -EINVAL;
103 if (ldt_info.base_addr == 0 && ldt_info.limit == 0
104 && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
105 && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
106 && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
107 /* allow LDTs to be cleared by the user */
108 entry = 0;
109 else
110 /* we must set the "Accessed" bit as IVE doesn't emulate it */
111 entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
112 (((ldt_info.read_exec_only ^ 1) << 1)
113 | (ldt_info.contents << 2)) | 1,
114 1, 3, ldt_info.seg_not_present ^ 1,
115 (oldmode ? 0 : ldt_info.useable),
116 ldt_info.seg_32bit,
117 ldt_info.limit_in_pages);
119 * Install the new entry. We know we're accessing valid (mapped) user-level
120 * memory, but we still need to guard against out-of-memory, hence we must use
121 * put_user().
123 ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
124 ia32_load_segment_descriptors(current);
125 return ret;
128 asmlinkage int
129 sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
131 int ret = -ENOSYS;
133 switch (func) {
134 case 0:
135 ret = read_ldt(P(ptr), bytecount);
136 break;
137 case 1:
138 ret = write_ldt(P(ptr), bytecount, 1);
139 break;
140 case 2:
141 ret = read_default_ldt(P(ptr), bytecount);
142 break;
143 case 0x11:
144 ret = write_ldt(P(ptr), bytecount, 0);
145 break;
147 return ret;