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 %p)\n", Entry
, Base
);
82 KeAcquireSpinLock(&GdtLock
, &oldIrql
);
84 Gdt
= (PUSHORT
)KeGetPcr()->GDT
;
85 Entry
= (Entry
& (~0x3)) / 2;
87 Gdt
[Entry
+ 1] = (USHORT
)(((ULONG
)Base
) & 0xffff);
89 Gdt
[Entry
+ 2] = Gdt
[Entry
+ 2] & ~(0xff);
90 Gdt
[Entry
+ 2] = (USHORT
)(Gdt
[Entry
+ 2] |
91 ((((ULONG
)Base
) & 0xff0000) >> 16));
93 Gdt
[Entry
+ 3] = Gdt
[Entry
+ 3] & ~(0xff00);
94 Gdt
[Entry
+ 3] = (USHORT
)(Gdt
[Entry
+ 3] |
95 ((((ULONG
)Base
) & 0xff000000) >> 16));
97 DPRINT("%x %x %x %x\n",
103 KeReleaseSpinLock(&GdtLock
, oldIrql
);
107 KeSetGdtSelector(ULONG Entry
,
114 DPRINT("KeSetGdtSelector(Entry %x, Value1 %x, Value2 %x)\n",
115 Entry
, Value1
, Value2
);
117 KeAcquireSpinLock(&GdtLock
, &oldIrql
);
119 Gdt
= (PULONG
) KeGetPcr()->GDT
;
120 Entry
= (Entry
& (~0x3)) / 4;
123 Gdt
[Entry
+ 1] = Value2
;
129 KeReleaseSpinLock(&GdtLock
, oldIrql
);
132 BOOLEAN
PspIsDescriptorValid(PLDT_ENTRY ldt_entry
)
134 ULONG Base
, SegLimit
;
136 Allow invalid descriptors.
138 if(!ldt_entry
->HighWord
.Bits
.Type
&&
139 !ldt_entry
->HighWord
.Bits
.Dpl
)
142 /* eliminate system descriptors and code segments other than
143 execute and execute/read and DPL<3 descriptors */
144 if(!(ldt_entry
->HighWord
.Bits
.Type
& 0x10) ||
145 (ldt_entry
->HighWord
.Bits
.Type
& 0x8 &&
146 ldt_entry
->HighWord
.Bits
.Type
& 0x4) ||
147 ldt_entry
->HighWord
.Bits
.Dpl
!= 3 ||
148 ldt_entry
->HighWord
.Bits
.Reserved_0
) return FALSE
;
150 if(!ldt_entry
->HighWord
.Bits
.Pres
) return TRUE
;
152 Base
=ldt_entry
->BaseLow
| (ldt_entry
->HighWord
.Bytes
.BaseMid
<< 16) |
153 (ldt_entry
->HighWord
.Bytes
.BaseHi
<< 24);
155 SegLimit
=ldt_entry
->LimitLow
|
156 (ldt_entry
->HighWord
.Bits
.LimitHi
<< 16);
158 if(ldt_entry
->HighWord
.Bits
.Type
& 0x4)
160 SegLimit
=(ldt_entry
->HighWord
.Bits
.Default_Big
) ? -1 : (USHORT
)-1;
162 } else if(ldt_entry
->HighWord
.Bits
.Granularity
)
164 SegLimit
=(SegLimit
<< 12) | 0xfff;
167 if ((Base
+ SegLimit
> (ULONG_PTR
) MmHighestUserAddress
) ||
168 (Base
> Base
+SegLimit
))
170 DPRINT1("WARNING: Windows would mark this descriptor invalid!");
174 Certain "DOS32" programs expect to be able to create DPMI selectors
175 that wrap the address space. Windows NT does not allow user-created
176 selectors to reach into kernel memory. However, there is no security
177 risk in allowing it; the page table will prevent access anyway.
179 return (/*(Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
180 (Base > Base+SegLimit) ? FALSE : TRUE*/ TRUE
);
184 NtSetLdtEntries (ULONG Selector1
,
190 ULONG NewLdtSize
= sizeof(LDT_ENTRY
);
191 PUSHORT LdtDescriptor
;
195 if((Selector1
& ~0xffff) || (Selector2
& ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR
;
200 if((Selector1
&& !PspIsDescriptorValid(&LdtEntry1
)) ||
201 (Selector2
&& !PspIsDescriptorValid(&LdtEntry2
))) return STATUS_INVALID_LDT_DESCRIPTOR
;
202 if(!(Selector1
|| Selector2
)) return STATUS_SUCCESS
;
204 NewLdtSize
+= (Selector1
>= Selector2
) ? Selector1
: Selector2
;
206 KeAcquireSpinLock(&LdtLock
, &oldIrql
);
208 LdtDescriptor
= (PUSHORT
) &PsGetCurrentProcess()->Pcb
.LdtDescriptor
;
209 LdtBase
= LdtDescriptor
[1] |
210 ((LdtDescriptor
[2] & 0xff) << 16) |
211 ((LdtDescriptor
[3] & ~0xff) << 16);
212 LdtLimit
= LdtDescriptor
[0] |
213 ((LdtDescriptor
[3] & 0xf) << 16);
215 if(LdtLimit
< (NewLdtSize
- 1))
217 /* allocate new ldt, copy old one there, set gdt ldt entry to new
218 values and load ldtr register and free old ldt */
220 ULONG NewLdtBase
= (ULONG
) ExAllocatePool(NonPagedPool
,
225 KeReleaseSpinLock(&LdtLock
, oldIrql
);
226 return STATUS_INSUFFICIENT_RESOURCES
;
231 memcpy((PVOID
) NewLdtBase
, (PVOID
) LdtBase
, LdtLimit
+1);
234 LdtDescriptor
[0] = (USHORT
)((--NewLdtSize
) & 0xffff);
235 LdtDescriptor
[1] = (USHORT
)(NewLdtBase
& 0xffff);
236 LdtDescriptor
[2] = (USHORT
)(((NewLdtBase
& 0xff0000) >> 16) | 0x8200);
237 LdtDescriptor
[3] = (USHORT
)(((NewLdtSize
& 0xf0000) >> 16) |
238 ((NewLdtBase
& 0xff000000) >> 16));
240 KeSetGdtSelector(KGDT_LDT
,
241 ((PULONG
) LdtDescriptor
)[0],
242 ((PULONG
) LdtDescriptor
)[1]);
244 Ke386SetLocalDescriptorTable(KGDT_LDT
);
248 ExFreePool((PVOID
) LdtBase
);
251 LdtBase
= NewLdtBase
;
256 memcpy((char*)LdtBase
+ Selector1
,
263 memcpy((char*)LdtBase
+ Selector2
,
268 KeReleaseSpinLock(&LdtLock
, oldIrql
);
269 return STATUS_SUCCESS
;