2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/ldt.c
5 * PURPOSE: LDT managment
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
11 /* INCLUDES *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 static KSPIN_LOCK LdtLock
;
20 static KSPIN_LOCK GdtLock
;
22 /* FUNCTIONS *****************************************************************/
26 Ke386GetGdtEntryThread(IN PKTHREAD Thread
,
28 IN PKGDTENTRY Descriptor
)
30 /* Make sure the offset isn't outside the allowed range */
31 if (Offset
>= (KGDT_NUMBER
* sizeof(KGDTENTRY
)))
34 return STATUS_ACCESS_VIOLATION
;
37 /* Check if this is the LDT selector */
38 if (Offset
== KGDT_LDT
)
40 /* Get it from the thread's process */
41 RtlCopyMemory(Descriptor
,
42 &Thread
->Process
->LdtDescriptor
,
47 /* Get the descriptor entry from the GDT */
48 RtlCopyMemory(Descriptor
,
49 (PVOID
)(((ULONG_PTR
)KeGetPcr()->GDT
) + Offset
),
52 /* Check if this is the TEB selector */
53 if (Offset
== KGDT_R3_TEB
)
56 * Make sure we set the correct base for this thread. This is per
57 * process and is set in the GDT on context switch, so it might not
58 * be correct for the thread specified.
61 (USHORT
)((ULONG_PTR
)(Thread
->Teb
) & 0xFFFF);
62 Descriptor
->HighWord
.Bytes
.BaseMid
=
63 (UCHAR
)((ULONG_PTR
)(Thread
->Teb
) >> 16);
64 Descriptor
->HighWord
.Bytes
.BaseHi
=
65 (UCHAR
)((ULONG_PTR
)(Thread
->Teb
) >> 24);
70 return STATUS_SUCCESS
;
74 KeSetBaseGdtSelector(ULONG Entry
,
80 DPRINT("KeSetBaseGdtSelector(Entry %x, Base %x)\n",
83 KeAcquireSpinLock(&GdtLock
, &oldIrql
);
85 Gdt
= (PUSHORT
)KeGetPcr()->GDT
;
86 Entry
= (Entry
& (~0x3)) / 2;
88 Gdt
[Entry
+ 1] = (USHORT
)(((ULONG
)Base
) & 0xffff);
90 Gdt
[Entry
+ 2] = Gdt
[Entry
+ 2] & ~(0xff);
91 Gdt
[Entry
+ 2] = (USHORT
)(Gdt
[Entry
+ 2] |
92 ((((ULONG
)Base
) & 0xff0000) >> 16));
94 Gdt
[Entry
+ 3] = Gdt
[Entry
+ 3] & ~(0xff00);
95 Gdt
[Entry
+ 3] = (USHORT
)(Gdt
[Entry
+ 3] |
96 ((((ULONG
)Base
) & 0xff000000) >> 16));
98 DPRINT("%x %x %x %x\n",
104 KeReleaseSpinLock(&GdtLock
, oldIrql
);
108 KeSetGdtSelector(ULONG Entry
,
115 DPRINT("KeSetGdtSelector(Entry %x, Value1 %x, Value2 %x)\n",
116 Entry
, Value1
, Value2
);
118 KeAcquireSpinLock(&GdtLock
, &oldIrql
);
120 Gdt
= (PULONG
) KeGetPcr()->GDT
;
121 Entry
= (Entry
& (~0x3)) / 4;
124 Gdt
[Entry
+ 1] = Value2
;
130 KeReleaseSpinLock(&GdtLock
, oldIrql
);
133 BOOLEAN
PspIsDescriptorValid(PLDT_ENTRY ldt_entry
)
135 ULONG Base
, SegLimit
;
137 Allow invalid descriptors.
139 if(!ldt_entry
->HighWord
.Bits
.Type
&&
140 !ldt_entry
->HighWord
.Bits
.Dpl
)
143 /* eliminate system descriptors and code segments other than
144 execute and execute/read and DPL<3 descriptors */
145 if(!(ldt_entry
->HighWord
.Bits
.Type
& 0x10) ||
146 (ldt_entry
->HighWord
.Bits
.Type
& 0x8 &&
147 ldt_entry
->HighWord
.Bits
.Type
& 0x4) ||
148 ldt_entry
->HighWord
.Bits
.Dpl
!= 3 ||
149 ldt_entry
->HighWord
.Bits
.Reserved_0
) return FALSE
;
151 if(!ldt_entry
->HighWord
.Bits
.Pres
) return TRUE
;
153 Base
=ldt_entry
->BaseLow
| (ldt_entry
->HighWord
.Bytes
.BaseMid
<< 16) |
154 (ldt_entry
->HighWord
.Bytes
.BaseHi
<< 24);
156 SegLimit
=ldt_entry
->LimitLow
|
157 (ldt_entry
->HighWord
.Bits
.LimitHi
<< 16);
159 if(ldt_entry
->HighWord
.Bits
.Type
& 0x4)
161 SegLimit
=(ldt_entry
->HighWord
.Bits
.Default_Big
) ? -1 : (USHORT
)-1;
163 } else if(ldt_entry
->HighWord
.Bits
.Granularity
)
165 SegLimit
=(SegLimit
<< 12) | 0xfff;
168 if ((Base
+ SegLimit
> (ULONG_PTR
) MmHighestUserAddress
) ||
169 (Base
> Base
+SegLimit
))
171 DPRINT1("WARNING: Windows would mark this descriptor invalid!");
175 Certain "DOS32" programs expect to be able to create DPMI selectors
176 that wrap the address space. Windows NT does not allow user-created
177 selectors to reach into kernel memory. However, there is no security
178 risk in allowing it; the page table will prevent access anyway.
180 return (/*(Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
181 (Base > Base+SegLimit) ? FALSE : TRUE*/ TRUE
);
185 NtSetLdtEntries (ULONG Selector1
,
191 ULONG NewLdtSize
= sizeof(LDT_ENTRY
);
192 PUSHORT LdtDescriptor
;
196 if((Selector1
& ~0xffff) || (Selector2
& ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR
;
201 if((Selector1
&& !PspIsDescriptorValid(&LdtEntry1
)) ||
202 (Selector2
&& !PspIsDescriptorValid(&LdtEntry2
))) return STATUS_INVALID_LDT_DESCRIPTOR
;
203 if(!(Selector1
|| Selector2
)) return STATUS_SUCCESS
;
205 NewLdtSize
+= (Selector1
>= Selector2
) ? Selector1
: Selector2
;
207 KeAcquireSpinLock(&LdtLock
, &oldIrql
);
209 LdtDescriptor
= (PUSHORT
) &PsGetCurrentProcess()->Pcb
.LdtDescriptor
;
210 LdtBase
= LdtDescriptor
[1] |
211 ((LdtDescriptor
[2] & 0xff) << 16) |
212 ((LdtDescriptor
[3] & ~0xff) << 16);
213 LdtLimit
= LdtDescriptor
[0] |
214 ((LdtDescriptor
[3] & 0xf) << 16);
216 if(LdtLimit
< (NewLdtSize
- 1))
218 /* allocate new ldt, copy old one there, set gdt ldt entry to new
219 values and load ldtr register and free old ldt */
221 ULONG NewLdtBase
= (ULONG
) ExAllocatePool(NonPagedPool
,
226 KeReleaseSpinLock(&LdtLock
, oldIrql
);
227 return STATUS_INSUFFICIENT_RESOURCES
;
232 memcpy((PVOID
) NewLdtBase
, (PVOID
) LdtBase
, LdtLimit
+1);
235 LdtDescriptor
[0] = (USHORT
)((--NewLdtSize
) & 0xffff);
236 LdtDescriptor
[1] = (USHORT
)(NewLdtBase
& 0xffff);
237 LdtDescriptor
[2] = (USHORT
)(((NewLdtBase
& 0xff0000) >> 16) | 0x8200);
238 LdtDescriptor
[3] = (USHORT
)(((NewLdtSize
& 0xf0000) >> 16) |
239 ((NewLdtBase
& 0xff000000) >> 16));
241 KeSetGdtSelector(KGDT_LDT
,
242 ((PULONG
) LdtDescriptor
)[0],
243 ((PULONG
) LdtDescriptor
)[1]);
245 Ke386SetLocalDescriptorTable(KGDT_LDT
);
249 ExFreePool((PVOID
) LdtBase
);
252 LdtBase
= NewLdtBase
;
257 memcpy((char*)LdtBase
+ Selector1
,
264 memcpy((char*)LdtBase
+ Selector2
,
269 KeReleaseSpinLock(&LdtLock
, oldIrql
);
270 return STATUS_SUCCESS
;