KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / i386 / ldt.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/ldt.c
6 * PURPOSE: LDT managment
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 static KSPIN_LOCK LdtLock;
20
21 /* FUNCTIONS *****************************************************************/
22
23 BOOL PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
24 {
25 ULONG Base, SegLimit;
26 /*
27 Allow invalid descriptors.
28 */
29 if(!ldt_entry->HighWord.Bits.Type &&
30 !ldt_entry->HighWord.Bits.Dpl)
31 return TRUE;
32
33 /* eliminate system descriptors and code segments other than
34 execute and execute/read and DPL<3 descriptors */
35 if(!(ldt_entry->HighWord.Bits.Type & 0x10) ||
36 (ldt_entry->HighWord.Bits.Type & 0x8 &&
37 ldt_entry->HighWord.Bits.Type & 0x4) ||
38 ldt_entry->HighWord.Bits.Dpl != 3 ||
39 ldt_entry->HighWord.Bits.Reserved_0) return FALSE;
40
41 if(!ldt_entry->HighWord.Bits.Pres) return TRUE;
42
43 Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) |
44 (ldt_entry->HighWord.Bytes.BaseHi << 24);
45
46 SegLimit=ldt_entry->LimitLow |
47 (ldt_entry->HighWord.Bits.LimitHi << 16);
48
49 if(ldt_entry->HighWord.Bits.Type & 0x4)
50 {
51 SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1;
52
53 } else if(ldt_entry->HighWord.Bits.Granularity)
54 {
55 SegLimit=(SegLimit << 12) | 0xfff;
56 }
57
58 return ((Base + SegLimit > (ULONG) MmHighestUserAddress) ||
59 (Base > Base+SegLimit) ? FALSE : TRUE);
60 }
61
62 NTSTATUS STDCALL
63 NtSetLdtEntries (ULONG Selector1,
64 LDT_ENTRY LdtEntry1,
65 ULONG Selector2,
66 LDT_ENTRY LdtEntry2)
67 {
68 KIRQL oldIrql;
69 ULONG NewLdtSize = sizeof(LDT_ENTRY);
70 PUSHORT LdtDescriptor;
71 ULONG LdtBase;
72 ULONG LdtLimit;
73
74 if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR;
75
76 Selector1 &= ~0x7;
77 Selector2 &= ~0x7;
78
79 if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) ||
80 (Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR;
81 if(!(Selector1 || Selector2)) return STATUS_SUCCESS;
82
83 NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2;
84
85 KeAcquireSpinLock(&LdtLock, &oldIrql);
86
87 LdtDescriptor = (PUSHORT) &KeGetCurrentProcess()->LdtDescriptor[0];
88 LdtBase = LdtDescriptor[1] |
89 ((LdtDescriptor[2] & 0xff) << 16) |
90 ((LdtDescriptor[3] & ~0xff) << 16);
91 LdtLimit = LdtDescriptor[0] |
92 ((LdtDescriptor[3] & 0xf) << 16);
93
94 if(LdtLimit < (NewLdtSize - 1))
95 {
96 /* allocate new ldt, copy old one there, set gdt ldt entry to new
97 values and load ldtr register and free old ldt */
98
99 ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool,
100 NewLdtSize);
101
102 if(!NewLdtBase)
103 {
104 KeReleaseSpinLock(&LdtLock, oldIrql);
105 return STATUS_INSUFFICIENT_RESOURCES;
106 }
107
108 if(LdtBase)
109 {
110 memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1);
111 }
112
113 LdtDescriptor[0] = (USHORT)((--NewLdtSize) & 0xffff);
114 LdtDescriptor[1] = (USHORT)(NewLdtBase & 0xffff);
115 LdtDescriptor[2] = (USHORT)(((NewLdtBase & 0xff0000) >> 16) | 0x8200);
116 LdtDescriptor[3] = (USHORT)(((NewLdtSize & 0xf0000) >> 16) |
117 ((NewLdtBase & 0xff000000) >> 16));
118
119 KeSetGdtSelector(LDT_SELECTOR,
120 ((PULONG) LdtDescriptor)[0],
121 ((PULONG) LdtDescriptor)[1]);
122
123 #if defined(__GNUC__)
124 __asm__("lldtw %%ax"
125 : /* no output */
126 : "a" (LDT_SELECTOR));
127 #elif defined(_MSC_VER)
128 __asm mov ax, LDT_SELECTOR
129 __asm lldt ax
130 #else
131 #error Unknown compiler for inline assembler
132 #endif
133
134 if(LdtBase)
135 {
136 ExFreePool((PVOID) LdtBase);
137 }
138
139 LdtBase = NewLdtBase;
140 }
141
142 if(Selector1)
143 {
144 memcpy((char*)LdtBase + Selector1,
145 &LdtEntry1,
146 sizeof(LDT_ENTRY));
147 }
148
149 if(Selector2)
150 {
151 memcpy((char*)LdtBase + Selector2,
152 &LdtEntry2,
153 sizeof(LDT_ENTRY));
154 }
155
156 KeReleaseSpinLock(&LdtLock, oldIrql);
157 return STATUS_SUCCESS;
158 }
159
160 VOID
161 Ki386InitializeLdt(VOID)
162 {
163 PUSHORT Gdt = KeGetCurrentKPCR()->GDT;
164 unsigned int base, length;
165
166 /*
167 * Set up an a descriptor for the LDT
168 */
169 base = length = 0;
170
171 Gdt[(LDT_SELECTOR / 2) + 0] = (length & 0xFFFF);
172 Gdt[(LDT_SELECTOR / 2) + 1] = (base & 0xFFFF);
173 Gdt[(LDT_SELECTOR / 2) + 2] = ((base & 0xFF0000) >> 16) | 0x8200;
174 Gdt[(LDT_SELECTOR / 2) + 3] = ((length & 0xF0000) >> 16) |
175 ((base & 0xFF000000) >> 16);
176 }