2 * linux/arch/x86_64/kernel/ldt.c
4 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
5 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
6 * Copyright (C) 2002 Andi Kleen
8 * Manage the local descriptor table for user processes.
9 * This handles calls from both 32bit and 64bit mode.
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14 #include <linux/string.h>
16 #include <linux/smp.h>
17 #include <linux/smp_lock.h>
18 #include <linux/vmalloc.h>
20 #include <asm/uaccess.h>
21 #include <asm/system.h>
26 * read_ldt() is not really atomic - this is not a problem since
27 * synchronization of reads and writes done to the LDT has to be
28 * assured by user-space anyway. Writes are atomic, to protect
29 * the security checks done on new descriptors.
31 static int read_ldt(void * ptr, unsigned long bytecount)
35 struct mm_struct * mm = current->mm;
38 if (!mm->context.segments)
41 size = LDT_ENTRIES*LDT_ENTRY_SIZE;
46 if (copy_to_user(ptr, mm->context.segments, size))
52 static int read_default_ldt(void * ptr, unsigned long bytecount)
57 if (clear_user(ptr, bytecount))
62 static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
64 struct task_struct *me = current;
65 struct mm_struct * mm = me->mm;
66 __u32 entry_1, entry_2, *lp;
68 struct modify_ldt_ldt_s ldt_info;
72 if (bytecount != sizeof(ldt_info))
75 if (copy_from_user(&ldt_info, ptr, bytecount))
79 if (ldt_info.entry_number >= LDT_ENTRIES)
81 if (ldt_info.contents == 3) {
84 if (ldt_info.seg_not_present == 0)
89 * the GDT index of the LDT is allocated dynamically, and is
90 * limited by MAX_LDT_DESCRIPTORS.
92 down_write(&mm->mmap_sem);
93 if (!mm->context.segments) {
94 void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
98 memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
100 mm->context.segments = segments;
101 mm->context.cpuvalid = 1UL << smp_processor_id();
105 lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments);
107 /* Allow LDTs to be cleared by the user. */
108 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
110 (ldt_info.contents == 0 &&
111 ldt_info.read_exec_only == 1 &&
112 ldt_info.seg_32bit == 0 &&
113 ldt_info.limit_in_pages == 0 &&
114 ldt_info.seg_not_present == 1 &&
115 ldt_info.useable == 0 &&
123 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
124 (ldt_info.limit & 0x0ffff);
125 entry_2 = (ldt_info.base_addr & 0xff000000) |
126 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
127 (ldt_info.limit & 0xf0000) |
128 ((ldt_info.read_exec_only ^ 1) << 9) |
129 (ldt_info.contents << 10) |
130 ((ldt_info.seg_not_present ^ 1) << 15) |
131 (ldt_info.seg_32bit << 22) |
132 (ldt_info.limit_in_pages << 23) |
133 (ldt_info.lm << 21) |
136 entry_2 |= (ldt_info.useable << 20);
138 /* Install the new entry ... */
145 up_write(&mm->mmap_sem);
150 asmlinkage long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
156 ret = read_ldt(ptr, bytecount);
159 ret = write_ldt(ptr, bytecount, 1);
162 ret = read_default_ldt(ptr, bytecount);
165 ret = write_ldt(ptr, bytecount, 0);