Blame view

arch/um/sys-i386/ldt.c 11.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
ba180fd43   Jeff Dike   uml: style fixes ...
2
   * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Licensed under the GPL
   */
8192ab42b   Jeff Dike   uml: header untan...
5
6
  #include <linux/mm.h>
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
7
  #include <linux/slab.h>
8192ab42b   Jeff Dike   uml: header untan...
8
  #include <asm/unistd.h>
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
9
  #include "os.h"
ba180fd43   Jeff Dike   uml: style fixes ...
10
  #include "proc_mm.h"
858259cf7   Bodo Stroesser   [PATCH] uml: main...
11
12
  #include "skas.h"
  #include "skas_ptrace.h"
ba180fd43   Jeff Dike   uml: style fixes ...
13
14
15
  #include "sysdep/tls.h"
  
  extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
16

99764fa4c   WANG Cong   UML: make several...
17
18
  static long write_ldt_entry(struct mm_id *mm_idp, int func,
  		     struct user_desc *desc, void **addr, int done)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
19
20
  {
  	long res;
ba180fd43   Jeff Dike   uml: style fixes ...
21
22
23
  	if (proc_mm) {
  		/*
  		 * This is a special handling for the case, that the mm to
858259cf7   Bodo Stroesser   [PATCH] uml: main...
24
25
26
  		 * modify isn't current->active_mm.
  		 * If this is called directly by modify_ldt,
  		 *     (current->active_mm->context.skas.u == mm_idp)
77bf44003   Jeff Dike   uml: remove code ...
27
  		 * will be true. So no call to __switch_mm(mm_idp) is done.
858259cf7   Bodo Stroesser   [PATCH] uml: main...
28
29
30
31
32
  		 * If this is called in case of init_new_ldt or PTRACE_LDT,
  		 * mm_idp won't belong to current->active_mm, but child->mm.
  		 * So we need to switch child's mm into our userspace, then
  		 * later switch back.
  		 *
07f4e2c61   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: fix ...
33
  		 * Note: I'm unsure: should interrupts be disabled here?
858259cf7   Bodo Stroesser   [PATCH] uml: main...
34
  		 */
ba180fd43   Jeff Dike   uml: style fixes ...
35
  		if (!current->active_mm || current->active_mm == &init_mm ||
6c738ffa9   Jeff Dike   uml: fold mmu_con...
36
  		    mm_idp != &current->active_mm->context.id)
77bf44003   Jeff Dike   uml: remove code ...
37
  			__switch_mm(mm_idp);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
38
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
39
  	if (ptrace_ldt) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
40
41
42
43
44
45
  		struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
  			.func = func,
  			.ptr = desc,
  			.bytecount = sizeof(*desc)};
  		u32 cpu;
  		int pid;
ba180fd43   Jeff Dike   uml: style fixes ...
46
  		if (!proc_mm)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
47
48
49
50
51
  			pid = mm_idp->u.pid;
  		else {
  			cpu = get_cpu();
  			pid = userspace_pid[cpu];
  		}
07f4e2c61   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: fix ...
52
  		res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
53

ba180fd43   Jeff Dike   uml: style fixes ...
54
  		if (proc_mm)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
55
56
57
58
59
60
61
62
  			put_cpu();
  	}
  	else {
  		void *stub_addr;
  		res = syscall_stub_data(mm_idp, (unsigned long *)desc,
  					(sizeof(*desc) + sizeof(long) - 1) &
  					    ~(sizeof(long) - 1),
  					addr, &stub_addr);
ba180fd43   Jeff Dike   uml: style fixes ...
63
  		if (!res) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
64
65
66
67
68
69
70
71
  			unsigned long args[] = { func,
  						 (unsigned long)stub_addr,
  						 sizeof(*desc),
  						 0, 0, 0 };
  			res = run_syscall_stub(mm_idp, __NR_modify_ldt, args,
  					       0, addr, done);
  		}
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
72
73
74
  	if (proc_mm) {
  		/*
  		 * This is the second part of special handling, that makes
858259cf7   Bodo Stroesser   [PATCH] uml: main...
75
76
  		 * PTRACE_LDT possible to implement.
  		 */
ba180fd43   Jeff Dike   uml: style fixes ...
77
  		if (current->active_mm && current->active_mm != &init_mm &&
6c738ffa9   Jeff Dike   uml: fold mmu_con...
78
79
  		    mm_idp != &current->active_mm->context.id)
  			__switch_mm(&current->active_mm->context.id);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
80
81
82
83
84
85
86
87
88
89
90
  	}
  
  	return res;
  }
  
  static long read_ldt_from_host(void __user * ptr, unsigned long bytecount)
  {
  	int res, n;
  	struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) {
  			.func = 0,
  			.bytecount = bytecount,
5cbded585   Robert P. J. Day   [PATCH] getting r...
91
  			.ptr = kmalloc(bytecount, GFP_KERNEL)};
858259cf7   Bodo Stroesser   [PATCH] uml: main...
92
  	u32 cpu;
ba180fd43   Jeff Dike   uml: style fixes ...
93
  	if (ptrace_ldt.ptr == NULL)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
94
  		return -ENOMEM;
ba180fd43   Jeff Dike   uml: style fixes ...
95
96
  	/*
  	 * This is called from sys_modify_ldt only, so userspace_pid gives
858259cf7   Bodo Stroesser   [PATCH] uml: main...
97
98
99
100
  	 * us the right number
  	 */
  
  	cpu = get_cpu();
07f4e2c61   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: fix ...
101
  	res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
102
  	put_cpu();
ba180fd43   Jeff Dike   uml: style fixes ...
103
  	if (res < 0)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
104
105
106
  		goto out;
  
  	n = copy_to_user(ptr, ptrace_ldt.ptr, res);
ba180fd43   Jeff Dike   uml: style fixes ...
107
  	if (n != 0)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  		res = -EFAULT;
  
    out:
  	kfree(ptrace_ldt.ptr);
  
  	return res;
  }
  
  /*
   * In skas mode, we hold our own ldt data in UML.
   * Thus, the code implementing sys_modify_ldt_skas
   * is very similar to (and mostly stolen from) sys_modify_ldt
   * for arch/i386/kernel/ldt.c
   * The routines copied and modified in part are:
   * - read_ldt
   * - read_default_ldt
   * - write_ldt
   * - sys_modify_ldt_skas
   */
  
  static int read_ldt(void __user * ptr, unsigned long bytecount)
  {
  	int i, err = 0;
  	unsigned long size;
6c738ffa9   Jeff Dike   uml: fold mmu_con...
132
  	uml_ldt_t * ldt = &current->mm->context.ldt;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
133

ba180fd43   Jeff Dike   uml: style fixes ...
134
  	if (!ldt->entry_count)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
135
  		goto out;
ba180fd43   Jeff Dike   uml: style fixes ...
136
  	if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
137
138
  		bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
  	err = bytecount;
ba180fd43   Jeff Dike   uml: style fixes ...
139
  	if (ptrace_ldt)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
140
  		return read_ldt_from_host(ptr, bytecount);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
141

01ac835fd   Daniel Walker   uml: LDT mutex co...
142
  	mutex_lock(&ldt->lock);
ba180fd43   Jeff Dike   uml: style fixes ...
143
  	if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
144
  		size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
ba180fd43   Jeff Dike   uml: style fixes ...
145
  		if (size > bytecount)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
146
  			size = bytecount;
ba180fd43   Jeff Dike   uml: style fixes ...
147
  		if (copy_to_user(ptr, ldt->u.entries, size))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
148
149
150
151
152
  			err = -EFAULT;
  		bytecount -= size;
  		ptr += size;
  	}
  	else {
ba180fd43   Jeff Dike   uml: style fixes ...
153
154
  		for (i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount;
  		     i++) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
155
  			size = PAGE_SIZE;
ba180fd43   Jeff Dike   uml: style fixes ...
156
  			if (size > bytecount)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
157
  				size = bytecount;
ba180fd43   Jeff Dike   uml: style fixes ...
158
  			if (copy_to_user(ptr, ldt->u.pages[i], size)) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
159
160
161
162
163
164
165
  				err = -EFAULT;
  				break;
  			}
  			bytecount -= size;
  			ptr += size;
  		}
  	}
01ac835fd   Daniel Walker   uml: LDT mutex co...
166
  	mutex_unlock(&ldt->lock);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
167

ba180fd43   Jeff Dike   uml: style fixes ...
168
  	if (bytecount == 0 || err == -EFAULT)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
169
  		goto out;
ba180fd43   Jeff Dike   uml: style fixes ...
170
  	if (clear_user(ptr, bytecount))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
171
172
173
174
175
176
177
178
179
  		err = -EFAULT;
  
  out:
  	return err;
  }
  
  static int read_default_ldt(void __user * ptr, unsigned long bytecount)
  {
  	int err;
ba180fd43   Jeff Dike   uml: style fixes ...
180
  	if (bytecount > 5*LDT_ENTRY_SIZE)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
181
182
183
  		bytecount = 5*LDT_ENTRY_SIZE;
  
  	err = bytecount;
ba180fd43   Jeff Dike   uml: style fixes ...
184
185
  	/*
  	 * UML doesn't support lcall7 and lcall27.
858259cf7   Bodo Stroesser   [PATCH] uml: main...
186
187
188
  	 * So, we don't really have a default ldt, but emulate
  	 * an empty ldt of common host default ldt size.
  	 */
ba180fd43   Jeff Dike   uml: style fixes ...
189
  	if (clear_user(ptr, bytecount))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
190
191
192
193
194
195
196
  		err = -EFAULT;
  
  	return err;
  }
  
  static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
  {
6c738ffa9   Jeff Dike   uml: fold mmu_con...
197
198
  	uml_ldt_t * ldt = &current->mm->context.ldt;
  	struct mm_id * mm_idp = &current->mm->context.id;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
199
200
201
202
203
204
  	int i, err;
  	struct user_desc ldt_info;
  	struct ldt_entry entry0, *ldt_p;
  	void *addr = NULL;
  
  	err = -EINVAL;
ba180fd43   Jeff Dike   uml: style fixes ...
205
  	if (bytecount != sizeof(ldt_info))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
206
207
  		goto out;
  	err = -EFAULT;
ba180fd43   Jeff Dike   uml: style fixes ...
208
  	if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
209
210
211
  		goto out;
  
  	err = -EINVAL;
ba180fd43   Jeff Dike   uml: style fixes ...
212
  	if (ldt_info.entry_number >= LDT_ENTRIES)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
213
  		goto out;
ba180fd43   Jeff Dike   uml: style fixes ...
214
  	if (ldt_info.contents == 3) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
215
216
217
218
219
  		if (func == 1)
  			goto out;
  		if (ldt_info.seg_not_present == 0)
  			goto out;
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
220
  	if (!ptrace_ldt)
01ac835fd   Daniel Walker   uml: LDT mutex co...
221
  		mutex_lock(&ldt->lock);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
222
223
  
  	err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
ba180fd43   Jeff Dike   uml: style fixes ...
224
  	if (err)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
225
  		goto out_unlock;
ba180fd43   Jeff Dike   uml: style fixes ...
226
227
228
229
230
231
232
233
234
235
236
237
  	else if (ptrace_ldt) {
  		/* With PTRACE_LDT available, this is used as a flag only */
  		ldt->entry_count = 1;
  		goto out;
  	}
  
  	if (ldt_info.entry_number >= ldt->entry_count &&
  	    ldt_info.entry_number >= LDT_DIRECT_ENTRIES) {
  		for (i=ldt->entry_count/LDT_ENTRIES_PER_PAGE;
  		     i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number;
  		     i++) {
  			if (i == 0)
e23181dee   Jeff Dike   [PATCH] uml: elim...
238
239
240
241
  				memcpy(&entry0, ldt->u.entries,
  				       sizeof(entry0));
  			ldt->u.pages[i] = (struct ldt_entry *)
  				__get_free_page(GFP_KERNEL|__GFP_ZERO);
ba180fd43   Jeff Dike   uml: style fixes ...
242
  			if (!ldt->u.pages[i]) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
243
244
245
246
247
248
  				err = -ENOMEM;
  				/* Undo the change in host */
  				memset(&ldt_info, 0, sizeof(ldt_info));
  				write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1);
  				goto out_unlock;
  			}
ba180fd43   Jeff Dike   uml: style fixes ...
249
  			if (i == 0) {
e23181dee   Jeff Dike   [PATCH] uml: elim...
250
251
252
  				memcpy(ldt->u.pages[0], &entry0,
  				       sizeof(entry0));
  				memcpy(ldt->u.pages[0]+1, ldt->u.entries+1,
858259cf7   Bodo Stroesser   [PATCH] uml: main...
253
254
255
256
257
  				       sizeof(entry0)*(LDT_DIRECT_ENTRIES-1));
  			}
  			ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE;
  		}
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
258
  	if (ldt->entry_count <= ldt_info.entry_number)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
259
  		ldt->entry_count = ldt_info.entry_number + 1;
ba180fd43   Jeff Dike   uml: style fixes ...
260
  	if (ldt->entry_count <= LDT_DIRECT_ENTRIES)
e23181dee   Jeff Dike   [PATCH] uml: elim...
261
  		ldt_p = ldt->u.entries + ldt_info.entry_number;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
262
  	else
e23181dee   Jeff Dike   [PATCH] uml: elim...
263
  		ldt_p = ldt->u.pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] +
858259cf7   Bodo Stroesser   [PATCH] uml: main...
264
  			ldt_info.entry_number%LDT_ENTRIES_PER_PAGE;
ba180fd43   Jeff Dike   uml: style fixes ...
265
266
  	if (ldt_info.base_addr == 0 && ldt_info.limit == 0 &&
  	   (func == 1 || LDT_empty(&ldt_info))) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
267
268
269
270
271
272
273
274
275
276
277
278
  		ldt_p->a = 0;
  		ldt_p->b = 0;
  	}
  	else{
  		if (func == 1)
  			ldt_info.useable = 0;
  		ldt_p->a = LDT_entry_a(&ldt_info);
  		ldt_p->b = LDT_entry_b(&ldt_info);
  	}
  	err = 0;
  
  out_unlock:
01ac835fd   Daniel Walker   uml: LDT mutex co...
279
  	mutex_unlock(&ldt->lock);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  out:
  	return err;
  }
  
  static long do_modify_ldt_skas(int func, void __user *ptr,
  			       unsigned long bytecount)
  {
  	int ret = -ENOSYS;
  
  	switch (func) {
  		case 0:
  			ret = read_ldt(ptr, bytecount);
  			break;
  		case 1:
  		case 0x11:
  			ret = write_ldt(ptr, bytecount, func);
  			break;
  		case 2:
  			ret = read_default_ldt(ptr, bytecount);
  			break;
  	}
  	return ret;
  }
af7279022   Jeff Dike   [PATCH] uml: fix ...
303
304
305
  static DEFINE_SPINLOCK(host_ldt_lock);
  static short dummy_list[9] = {0, -1};
  static short * host_ldt_entries = NULL;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
306

af7279022   Jeff Dike   [PATCH] uml: fix ...
307
  static void ldt_get_host_info(void)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
308
309
  {
  	long ret;
622e69693   Jeff Dike   [PATCH] uml: fix ...
310
311
  	struct ldt_entry * ldt;
  	short *tmp;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
312
  	int i, size, k, order;
af7279022   Jeff Dike   [PATCH] uml: fix ...
313
  	spin_lock(&host_ldt_lock);
ba180fd43   Jeff Dike   uml: style fixes ...
314
  	if (host_ldt_entries != NULL) {
af7279022   Jeff Dike   [PATCH] uml: fix ...
315
316
317
  		spin_unlock(&host_ldt_lock);
  		return;
  	}
858259cf7   Bodo Stroesser   [PATCH] uml: main...
318
  	host_ldt_entries = dummy_list+1;
af7279022   Jeff Dike   [PATCH] uml: fix ...
319
  	spin_unlock(&host_ldt_lock);
ba180fd43   Jeff Dike   uml: style fixes ...
320
321
  	for (i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++)
  		;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
322
323
324
  
  	ldt = (struct ldt_entry *)
  	      __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
ba180fd43   Jeff Dike   uml: style fixes ...
325
326
327
328
  	if (ldt == NULL) {
  		printk(KERN_ERR "ldt_get_host_info: couldn't allocate buffer "
  		       "for host ldt
  ");
858259cf7   Bodo Stroesser   [PATCH] uml: main...
329
330
331
332
  		return;
  	}
  
  	ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE);
ba180fd43   Jeff Dike   uml: style fixes ...
333
334
335
  	if (ret < 0) {
  		printk(KERN_ERR "ldt_get_host_info: couldn't read host ldt
  ");
858259cf7   Bodo Stroesser   [PATCH] uml: main...
336
337
  		goto out_free;
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
338
  	if (ret == 0) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
339
340
341
342
  		/* default_ldt is active, simply write an empty entry 0 */
  		host_ldt_entries = dummy_list;
  		goto out_free;
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
343
344
  	for (i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++) {
  		if (ldt[i].a != 0 || ldt[i].b != 0)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
345
346
  			size++;
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
347
  	if (size < ARRAY_SIZE(dummy_list))
858259cf7   Bodo Stroesser   [PATCH] uml: main...
348
  		host_ldt_entries = dummy_list;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
349
350
  	else {
  		size = (size + 1) * sizeof(dummy_list[0]);
af7279022   Jeff Dike   [PATCH] uml: fix ...
351
  		tmp = kmalloc(size, GFP_KERNEL);
ba180fd43   Jeff Dike   uml: style fixes ...
352
353
354
355
  		if (tmp == NULL) {
  			printk(KERN_ERR "ldt_get_host_info: couldn't allocate "
  			       "host ldt list
  ");
858259cf7   Bodo Stroesser   [PATCH] uml: main...
356
357
  			goto out_free;
  		}
af7279022   Jeff Dike   [PATCH] uml: fix ...
358
  		host_ldt_entries = tmp;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
359
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
360
361
  	for (i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++) {
  		if (ldt[i].a != 0 || ldt[i].b != 0)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
362
  			host_ldt_entries[k++] = i;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
363
364
365
366
367
368
  	}
  	host_ldt_entries[k] = -1;
  
  out_free:
  	free_pages((unsigned long)ldt, order);
  }
6c738ffa9   Jeff Dike   uml: fold mmu_con...
369
  long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
370
371
372
373
374
375
  {
  	struct user_desc desc;
  	short * num_p;
  	int i;
  	long page, err=0;
  	void *addr = NULL;
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
376
  	struct proc_mm_op copy;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
377

858259cf7   Bodo Stroesser   [PATCH] uml: main...
378

ba180fd43   Jeff Dike   uml: style fixes ...
379
  	if (!ptrace_ldt)
01ac835fd   Daniel Walker   uml: LDT mutex co...
380
  		mutex_init(&new_mm->ldt.lock);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
381

ba180fd43   Jeff Dike   uml: style fixes ...
382
  	if (!from_mm) {
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
383
  		memset(&desc, 0, sizeof(desc));
858259cf7   Bodo Stroesser   [PATCH] uml: main...
384
385
386
  		/*
  		 * We have to initialize a clean ldt.
  		 */
ba180fd43   Jeff Dike   uml: style fixes ...
387
  		if (proc_mm) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
388
389
390
391
392
393
394
  			/*
  			 * If the new mm was created using proc_mm, host's
  			 * default-ldt currently is assigned, which normally
  			 * contains the call-gates for lcall7 and lcall27.
  			 * To remove these gates, we simply write an empty
  			 * entry as number 0 to the host.
  			 */
ba180fd43   Jeff Dike   uml: style fixes ...
395
  			err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
396
397
398
399
400
401
402
  		}
  		else{
  			/*
  			 * Now we try to retrieve info about the ldt, we
  			 * inherited from the host. All ldt-entries found
  			 * will be reset in the following loop
  			 */
af7279022   Jeff Dike   [PATCH] uml: fix ...
403
  			ldt_get_host_info();
ba180fd43   Jeff Dike   uml: style fixes ...
404
  			for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
405
406
407
  				desc.entry_number = *num_p;
  				err = write_ldt_entry(&new_mm->id, 1, &desc,
  						      &addr, *(num_p + 1) == -1);
ba180fd43   Jeff Dike   uml: style fixes ...
408
  				if (err)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
409
410
411
412
  					break;
  			}
  		}
  		new_mm->ldt.entry_count = 0;
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
413
414
  
  		goto out;
858259cf7   Bodo Stroesser   [PATCH] uml: main...
415
  	}
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
416

ba180fd43   Jeff Dike   uml: style fixes ...
417
418
419
  	if (proc_mm) {
  		/*
  		 * We have a valid from_mm, so we now have to copy the LDT of
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
420
421
422
423
424
425
426
  		 * from_mm to new_mm, because using proc_mm an new mm with
  		 * an empty/default LDT was created in new_mm()
  		 */
  		copy = ((struct proc_mm_op) { .op 	= MM_COPY_SEGMENTS,
  					      .u 	=
  					      { .copy_segments =
  							from_mm->id.u.mm_fd } } );
a6ea4ccee   Jeff Dike   uml: rename os_{r...
427
  		i = os_write_file(new_mm->id.u.mm_fd, &copy, sizeof(copy));
ba180fd43   Jeff Dike   uml: style fixes ...
428
429
430
431
  		if (i != sizeof(copy))
  			printk(KERN_ERR "new_mm : /proc/mm copy_segments "
  			       "failed, err = %d
  ", -i);
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
432
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
433
434
435
  	if (!ptrace_ldt) {
  		/*
  		 * Our local LDT is used to supply the data for
858259cf7   Bodo Stroesser   [PATCH] uml: main...
436
437
438
439
  		 * modify_ldt(READLDT), if PTRACE_LDT isn't available,
  		 * i.e., we have to use the stub for modify_ldt, which
  		 * can't handle the big read buffer of up to 64kB.
  		 */
01ac835fd   Daniel Walker   uml: LDT mutex co...
440
  		mutex_lock(&from_mm->ldt.lock);
ba180fd43   Jeff Dike   uml: style fixes ...
441
  		if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES)
e23181dee   Jeff Dike   [PATCH] uml: elim...
442
443
  			memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries,
  			       sizeof(new_mm->ldt.u.entries));
ba180fd43   Jeff Dike   uml: style fixes ...
444
  		else {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
445
  			i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE;
ba180fd43   Jeff Dike   uml: style fixes ...
446
  			while (i-->0) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
447
  				page = __get_free_page(GFP_KERNEL|__GFP_ZERO);
ba180fd43   Jeff Dike   uml: style fixes ...
448
  				if (!page) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
449
450
451
  					err = -ENOMEM;
  					break;
  				}
e23181dee   Jeff Dike   [PATCH] uml: elim...
452
453
454
455
  				new_mm->ldt.u.pages[i] =
  					(struct ldt_entry *) page;
  				memcpy(new_mm->ldt.u.pages[i],
  				       from_mm->ldt.u.pages[i], PAGE_SIZE);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
456
457
458
  			}
  		}
  		new_mm->ldt.entry_count = from_mm->ldt.entry_count;
01ac835fd   Daniel Walker   uml: LDT mutex co...
459
  		mutex_unlock(&from_mm->ldt.lock);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
460
  	}
12919aa6e   Bodo Stroesser   [PATCH] uml: move...
461
      out:
858259cf7   Bodo Stroesser   [PATCH] uml: main...
462
463
  	return err;
  }
6c738ffa9   Jeff Dike   uml: fold mmu_con...
464
  void free_ldt(struct mm_context *mm)
858259cf7   Bodo Stroesser   [PATCH] uml: main...
465
466
  {
  	int i;
ba180fd43   Jeff Dike   uml: style fixes ...
467
  	if (!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES) {
858259cf7   Bodo Stroesser   [PATCH] uml: main...
468
  		i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE;
ba180fd43   Jeff Dike   uml: style fixes ...
469
470
  		while (i-- > 0)
  			free_page((long) mm->ldt.u.pages[i]);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
471
472
473
  	}
  	mm->ldt.entry_count = 0;
  }
858259cf7   Bodo Stroesser   [PATCH] uml: main...
474
475
476
  
  int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
  {
6aa802ce6   Jeff Dike   uml: throw out CH...
477
  	return do_modify_ldt_skas(func, ptr, bytecount);
858259cf7   Bodo Stroesser   [PATCH] uml: main...
478
  }