3 * Copyright (C) 2000 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/ldt.c
22 * PURPOSE: LDT managment
23 * PROGRAMMER: David Welch (welch@cwcom.net)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
31 #include <internal/ke.h>
32 #include <internal/ps.h>
33 #include <internal/i386/segment.h>
36 #include <internal/debug.h>
38 /* GLOBALS *******************************************************************/
40 static KSPIN_LOCK LdtLock;
42 /* FUNCTIONS *****************************************************************/
44 BOOL PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
48 Allow invalid descriptors.
50 if(!ldt_entry->HighWord.Bits.Type &&
51 !ldt_entry->HighWord.Bits.Dpl)
54 /* eliminate system descriptors and code segments other than
55 execute and execute/read and DPL<3 descriptors */
56 if(!(ldt_entry->HighWord.Bits.Type & 0x10) ||
57 (ldt_entry->HighWord.Bits.Type & 0x8 &&
58 ldt_entry->HighWord.Bits.Type & 0x4) ||
59 ldt_entry->HighWord.Bits.Dpl != 3 ||
60 ldt_entry->HighWord.Bits.Reserved_0) return FALSE;
62 if(!ldt_entry->HighWord.Bits.Pres) return TRUE;
64 Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) |
65 (ldt_entry->HighWord.Bytes.BaseHi << 24);
67 SegLimit=ldt_entry->LimitLow |
68 (ldt_entry->HighWord.Bits.LimitHi << 16);
70 if(ldt_entry->HighWord.Bits.Type & 0x4)
72 SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1;
74 } else if(ldt_entry->HighWord.Bits.Granularity)
76 SegLimit=(SegLimit << 12) | 0xfff;
79 return ((Base + SegLimit > (ULONG) MmHighestUserAddress) ||
80 (Base > Base+SegLimit) ? FALSE : TRUE);
84 NtSetLdtEntries (ULONG Selector1,
90 ULONG NewLdtSize = sizeof(LDT_ENTRY);
91 PUSHORT LdtDescriptor;
95 if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR;
100 if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) ||
101 (Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR;
102 if(!(Selector1 || Selector2)) return STATUS_SUCCESS;
104 NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2;
106 KeAcquireSpinLock(&LdtLock, &oldIrql);
108 LdtDescriptor = (PUSHORT) &KeGetCurrentProcess()->LdtDescriptor[0];
109 LdtBase = LdtDescriptor[1] |
110 ((LdtDescriptor[2] & 0xff) << 16) |
111 ((LdtDescriptor[3] & ~0xff) << 16);
112 LdtLimit = LdtDescriptor[0] |
113 ((LdtDescriptor[3] & 0xf) << 16);
115 if(LdtLimit < (NewLdtSize - 1))
117 /* allocate new ldt, copy old one there, set gdt ldt entry to new
118 values and load ldtr register and free old ldt */
120 ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool,
125 KeReleaseSpinLock(&LdtLock, oldIrql);
126 return STATUS_INSUFFICIENT_RESOURCES;
131 memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1);
134 LdtDescriptor[0] = (--NewLdtSize) & 0xffff;
135 LdtDescriptor[1] = NewLdtBase & 0xffff;
136 LdtDescriptor[2] = ((NewLdtBase & 0xff0000) >> 16) | 0x8200;
137 LdtDescriptor[3] = ((NewLdtSize & 0xf0000) >> 16) |
138 ((NewLdtBase & 0xff000000) >> 16);
140 KeSetGdtSelector(LDT_SELECTOR,
141 ((PULONG) LdtDescriptor)[0],
142 ((PULONG) LdtDescriptor)[1]);
146 : "a" (LDT_SELECTOR));
150 ExFreePool((PVOID) LdtBase);
153 LdtBase = NewLdtBase;
158 memcpy((PVOID) LdtBase + Selector1,
165 memcpy((PVOID) LdtBase + Selector2,
170 KeReleaseSpinLock(&LdtLock, oldIrql);
171 return STATUS_SUCCESS;
175 Ki386InitializeLdt(VOID)
177 PUSHORT Gdt = KeGetCurrentKPCR()->GDT;
178 unsigned int base, length;
181 * Set up an a descriptor for the LDT
185 Gdt[(LDT_SELECTOR / 2) + 0] = (length & 0xFFFF);
186 Gdt[(LDT_SELECTOR / 2) + 1] = (base & 0xFFFF);
187 Gdt[(LDT_SELECTOR / 2) + 2] = ((base & 0xFF0000) >> 16) | 0x8200;
188 Gdt[(LDT_SELECTOR / 2) + 3] = ((length & 0xF0000) >> 16) |
189 ((base & 0xFF000000) >> 16);