1 /* 2 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds 3 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> 4 * Copyright (C) 2002 Andi Kleen 5 * 6 * This handles calls from both 32bit and 64bit mode. 7 */ 8 9 #include <linux/errno.h> 10 #include <linux/gfp.h> 11 #include <linux/sched.h> 12 #include <linux/string.h> 13 #include <linux/mm.h> 14 #include <linux/smp.h> 15 #include <linux/vmalloc.h> 16 #include <linux/uaccess.h> 17 18 #include <asm/system.h> 19 #include <asm/ldt.h> 20 #include <asm/desc.h> 21 #include <asm/mmu_context.h> 22 #include <asm/syscalls.h> 23 24 #ifdef CONFIG_SMP 25 static void flush_ldt(void *current_mm) 26 { 27 if (current->active_mm == current_mm) 28 load_LDT(¤t->active_mm->context); 29 } 30 #endif 31 32 static int alloc_ldt(mm_context_t *pc, int mincount, int reload) 33 { 34 void *oldldt, *newldt; 35 int oldsize; 36 37 if (mincount <= pc->size) 38 return 0; 39 oldsize = pc->size; 40 mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) & 41 (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1)); 42 if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE) 43 newldt = vmalloc(mincount * LDT_ENTRY_SIZE); 44 else 45 newldt = (void *)__get_free_page(GFP_KERNEL); 46 47 if (!newldt) 48 return -ENOMEM; 49 50 if (oldsize) 51 memcpy(newldt, pc->ldt, oldsize * LDT_ENTRY_SIZE); 52 oldldt = pc->ldt; 53 memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, 54 (mincount - oldsize) * LDT_ENTRY_SIZE); 55 56 paravirt_alloc_ldt(newldt, mincount); 57 58 #ifdef CONFIG_X86_64 59 /* CHECKME: Do we really need this ? */ 60 wmb(); 61 #endif 62 pc->ldt = newldt; 63 wmb(); 64 pc->size = mincount; 65 wmb(); 66 67 if (reload) { 68 #ifdef CONFIG_SMP 69 preempt_disable(); 70 load_LDT(pc); 71 if (!cpumask_equal(mm_cpumask(current->mm), 72 cpumask_of(smp_processor_id()))) 73 smp_call_function(flush_ldt, current->mm, 1); 74 preempt_enable(); 75 #else 76 load_LDT(pc); 77 #endif 78 } 79 if (oldsize) { 80 paravirt_free_ldt(oldldt, oldsize); 81 if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) 82 vfree(oldldt); 83 else 84 put_page(virt_to_page(oldldt)); 85 } 86 return 0; 87 } 88 89 static inline int copy_ldt(mm_context_t *new, mm_context_t *old) 90 { 91 int err = alloc_ldt(new, old->size, 0); 92 int i; 93 94 if (err < 0) 95 return err; 96 97 for (i = 0; i < old->size; i++) 98 write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE); 99 return 0; 100 } 101 102 /* 103 * we do not have to muck with descriptors here, that is 104 * done in switch_mm() as needed. 105 */ 106 int init_new_context(struct task_struct *tsk, struct mm_struct *mm) 107 { 108 struct mm_struct *old_mm; 109 int retval = 0; 110 111 mutex_init(&mm->context.lock); 112 mm->context.size = 0; 113 old_mm = current->mm; 114 if (old_mm && old_mm->context.size > 0) { 115 mutex_lock(&old_mm->context.lock); 116 retval = copy_ldt(&mm->context, &old_mm->context); 117 mutex_unlock(&old_mm->context.lock); 118 } 119 return retval; 120 } 121 122 /* 123 * No need to lock the MM as we are the last user 124 * 125 * 64bit: Don't touch the LDT register - we're already in the next thread. 126 */ 127 void destroy_context(struct mm_struct *mm) 128 { 129 if (mm->context.size) { 130 #ifdef CONFIG_X86_32 131 /* CHECKME: Can this ever happen ? */ 132 if (mm == current->active_mm) 133 clear_LDT(); 134 #endif 135 paravirt_free_ldt(mm->context.ldt, mm->context.size); 136 if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) 137 vfree(mm->context.ldt); 138 else 139 put_page(virt_to_page(mm->context.ldt)); 140 mm->context.size = 0; 141 } 142 } 143 144 static int read_ldt(void __user *ptr, unsigned long bytecount) 145 { 146 int err; 147 unsigned long size; 148 struct mm_struct *mm = current->mm; 149 150 if (!mm->context.size) 151 return 0; 152 if (bytecount > LDT_ENTRY_SIZE * LDT_ENTRIES) 153 bytecount = LDT_ENTRY_SIZE * LDT_ENTRIES; 154 155 mutex_lock(&mm->context.lock); 156 size = mm->context.size * LDT_ENTRY_SIZE; 157 if (size > bytecount) 158 size = bytecount; 159 160 err = 0; 161 if (copy_to_user(ptr, mm->context.ldt, size)) 162 err = -EFAULT; 163 mutex_unlock(&mm->context.lock); 164 if (err < 0) 165 goto error_return; 166 if (size != bytecount) { 167 /* zero-fill the rest */ 168 if (clear_user(ptr + size, bytecount - size) != 0) { 169 err = -EFAULT; 170 goto error_return; 171 } 172 } 173 return bytecount; 174 error_return: 175 return err; 176 } 177 178 static int read_default_ldt(void __user *ptr, unsigned long bytecount) 179 { 180 /* CHECKME: Can we use _one_ random number ? */ 181 #ifdef CONFIG_X86_32 182 unsigned long size = 5 * sizeof(struct desc_struct); 183 #else 184 unsigned long size = 128; 185 #endif 186 if (bytecount > size) 187 bytecount = size; 188 if (clear_user(ptr, bytecount)) 189 return -EFAULT; 190 return bytecount; 191 } 192 193 static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) 194 { 195 struct mm_struct *mm = current->mm; 196 struct desc_struct ldt; 197 int error; 198 struct user_desc ldt_info; 199 200 error = -EINVAL; 201 if (bytecount != sizeof(ldt_info)) 202 goto out; 203 error = -EFAULT; 204 if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) 205 goto out; 206 207 error = -EINVAL; 208 if (ldt_info.entry_number >= LDT_ENTRIES) 209 goto out; 210 if (ldt_info.contents == 3) { 211 if (oldmode) 212 goto out; 213 if (ldt_info.seg_not_present == 0) 214 goto out; 215 } 216 217 mutex_lock(&mm->context.lock); 218 if (ldt_info.entry_number >= mm->context.size) { 219 error = alloc_ldt(¤t->mm->context, 220 ldt_info.entry_number + 1, 1); 221 if (error < 0) 222 goto out_unlock; 223 } 224 225 /* Allow LDTs to be cleared by the user. */ 226 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { 227 if (oldmode || LDT_empty(&ldt_info)) { 228 memset(&ldt, 0, sizeof(ldt)); 229 goto install; 230 } 231 } 232 233 fill_ldt(&ldt, &ldt_info); 234 if (oldmode) 235 ldt.avl = 0; 236 237 /* Install the new entry ... */ 238 install: 239 write_ldt_entry(mm->context.ldt, ldt_info.entry_number, &ldt); 240 error = 0; 241 242 out_unlock: 243 mutex_unlock(&mm->context.lock); 244 out: 245 return error; 246 } 247 248 asmlinkage int sys_modify_ldt(int func, void __user *ptr, 249 unsigned long bytecount) 250 { 251 int ret = -ENOSYS; 252 253 switch (func) { 254 case 0: 255 ret = read_ldt(ptr, bytecount); 256 break; 257 case 1: 258 ret = write_ldt(ptr, bytecount, 1); 259 break; 260 case 2: 261 ret = read_default_ldt(ptr, bytecount); 262 break; 263 case 0x11: 264 ret = write_ldt(ptr, bytecount, 0); 265 break; 266 } 267 return ret; 268 } 269