Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenldt.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/ke/i386/ldt.c 00005 * PURPOSE: LDT managment 00006 * 00007 * PROGRAMMERS: David Welch (welch@cwcom.net) 00008 * Stefan Ginsberg (stefan.ginsberg@reactos.org) 00009 */ 00010 00011 /* INCLUDES *****************************************************************/ 00012 00013 #include <ntoskrnl.h> 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 /* GLOBALS *******************************************************************/ 00018 00019 static KSPIN_LOCK LdtLock; 00020 static KSPIN_LOCK GdtLock; 00021 00022 /* FUNCTIONS *****************************************************************/ 00023 00024 NTSTATUS 00025 NTAPI 00026 Ke386GetGdtEntryThread(IN PKTHREAD Thread, 00027 IN ULONG Offset, 00028 IN PKGDTENTRY Descriptor) 00029 { 00030 /* Make sure the offset isn't outside the allowed range */ 00031 if (Offset >= (KGDT_NUMBER * sizeof(KGDTENTRY))) 00032 { 00033 /* It is, fail */ 00034 return STATUS_ACCESS_VIOLATION; 00035 } 00036 00037 /* Check if this is the LDT selector */ 00038 if (Offset == KGDT_LDT) 00039 { 00040 /* Get it from the thread's process */ 00041 RtlCopyMemory(Descriptor, 00042 &Thread->Process->LdtDescriptor, 00043 sizeof(KGDTENTRY)); 00044 } 00045 else 00046 { 00047 /* Get the descriptor entry from the GDT */ 00048 RtlCopyMemory(Descriptor, 00049 (PVOID)(((ULONG_PTR)KeGetPcr()->GDT) + Offset), 00050 sizeof(KGDTENTRY)); 00051 00052 /* Check if this is the TEB selector */ 00053 if (Offset == KGDT_R3_TEB) 00054 { 00055 /* 00056 * Make sure we set the correct base for this thread. This is per 00057 * process and is set in the GDT on context switch, so it might not 00058 * be correct for the thread specified. 00059 */ 00060 Descriptor->BaseLow = 00061 (USHORT)((ULONG_PTR)(Thread->Teb) & 0xFFFF); 00062 Descriptor->HighWord.Bytes.BaseMid = 00063 (UCHAR)((ULONG_PTR)(Thread->Teb) >> 16); 00064 Descriptor->HighWord.Bytes.BaseHi = 00065 (UCHAR)((ULONG_PTR)(Thread->Teb) >> 24); 00066 } 00067 } 00068 00069 /* Success */ 00070 return STATUS_SUCCESS; 00071 } 00072 00073 VOID 00074 KeSetBaseGdtSelector(ULONG Entry, 00075 PVOID Base) 00076 { 00077 KIRQL oldIrql; 00078 PUSHORT Gdt; 00079 00080 DPRINT("KeSetBaseGdtSelector(Entry %x, Base %x)\n", 00081 Entry, Base); 00082 00083 KeAcquireSpinLock(&GdtLock, &oldIrql); 00084 00085 Gdt = (PUSHORT)KeGetPcr()->GDT; 00086 Entry = (Entry & (~0x3)) / 2; 00087 00088 Gdt[Entry + 1] = (USHORT)(((ULONG)Base) & 0xffff); 00089 00090 Gdt[Entry + 2] = Gdt[Entry + 2] & ~(0xff); 00091 Gdt[Entry + 2] = (USHORT)(Gdt[Entry + 2] | 00092 ((((ULONG)Base) & 0xff0000) >> 16)); 00093 00094 Gdt[Entry + 3] = Gdt[Entry + 3] & ~(0xff00); 00095 Gdt[Entry + 3] = (USHORT)(Gdt[Entry + 3] | 00096 ((((ULONG)Base) & 0xff000000) >> 16)); 00097 00098 DPRINT("%x %x %x %x\n", 00099 Gdt[Entry + 0], 00100 Gdt[Entry + 1], 00101 Gdt[Entry + 2], 00102 Gdt[Entry + 3]); 00103 00104 KeReleaseSpinLock(&GdtLock, oldIrql); 00105 } 00106 00107 VOID 00108 KeSetGdtSelector(ULONG Entry, 00109 ULONG Value1, 00110 ULONG Value2) 00111 { 00112 KIRQL oldIrql; 00113 PULONG Gdt; 00114 00115 DPRINT("KeSetGdtSelector(Entry %x, Value1 %x, Value2 %x)\n", 00116 Entry, Value1, Value2); 00117 00118 KeAcquireSpinLock(&GdtLock, &oldIrql); 00119 00120 Gdt = (PULONG) KeGetPcr()->GDT; 00121 Entry = (Entry & (~0x3)) / 4; 00122 00123 Gdt[Entry] = Value1; 00124 Gdt[Entry + 1] = Value2; 00125 00126 DPRINT("%x %x\n", 00127 Gdt[Entry + 0], 00128 Gdt[Entry + 1]); 00129 00130 KeReleaseSpinLock(&GdtLock, oldIrql); 00131 } 00132 00133 BOOLEAN PspIsDescriptorValid(PLDT_ENTRY ldt_entry) 00134 { 00135 ULONG Base, SegLimit; 00136 /* 00137 Allow invalid descriptors. 00138 */ 00139 if(!ldt_entry->HighWord.Bits.Type && 00140 !ldt_entry->HighWord.Bits.Dpl) 00141 return TRUE; 00142 00143 /* eliminate system descriptors and code segments other than 00144 execute and execute/read and DPL<3 descriptors */ 00145 if(!(ldt_entry->HighWord.Bits.Type & 0x10) || 00146 (ldt_entry->HighWord.Bits.Type & 0x8 && 00147 ldt_entry->HighWord.Bits.Type & 0x4) || 00148 ldt_entry->HighWord.Bits.Dpl != 3 || 00149 ldt_entry->HighWord.Bits.Reserved_0) return FALSE; 00150 00151 if(!ldt_entry->HighWord.Bits.Pres) return TRUE; 00152 00153 Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) | 00154 (ldt_entry->HighWord.Bytes.BaseHi << 24); 00155 00156 SegLimit=ldt_entry->LimitLow | 00157 (ldt_entry->HighWord.Bits.LimitHi << 16); 00158 00159 if(ldt_entry->HighWord.Bits.Type & 0x4) 00160 { 00161 SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1; 00162 00163 } else if(ldt_entry->HighWord.Bits.Granularity) 00164 { 00165 SegLimit=(SegLimit << 12) | 0xfff; 00166 } 00167 00168 if ((Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) || 00169 (Base > Base+SegLimit)) 00170 { 00171 DPRINT1("WARNING: Windows would mark this descriptor invalid!"); 00172 } 00173 00174 /* 00175 Certain "DOS32" programs expect to be able to create DPMI selectors 00176 that wrap the address space. Windows NT does not allow user-created 00177 selectors to reach into kernel memory. However, there is no security 00178 risk in allowing it; the page table will prevent access anyway. 00179 */ 00180 return (/*(Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) || 00181 (Base > Base+SegLimit) ? FALSE : TRUE*/ TRUE); 00182 } 00183 00184 NTSTATUS NTAPI 00185 NtSetLdtEntries (ULONG Selector1, 00186 LDT_ENTRY LdtEntry1, 00187 ULONG Selector2, 00188 LDT_ENTRY LdtEntry2) 00189 { 00190 KIRQL oldIrql; 00191 ULONG NewLdtSize = sizeof(LDT_ENTRY); 00192 PUSHORT LdtDescriptor; 00193 ULONG LdtBase; 00194 ULONG LdtLimit; 00195 00196 if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR; 00197 00198 Selector1 &= ~0x7; 00199 Selector2 &= ~0x7; 00200 00201 if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) || 00202 (Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR; 00203 if(!(Selector1 || Selector2)) return STATUS_SUCCESS; 00204 00205 NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2; 00206 00207 KeAcquireSpinLock(&LdtLock, &oldIrql); 00208 00209 LdtDescriptor = (PUSHORT) &PsGetCurrentProcess()->Pcb.LdtDescriptor; 00210 LdtBase = LdtDescriptor[1] | 00211 ((LdtDescriptor[2] & 0xff) << 16) | 00212 ((LdtDescriptor[3] & ~0xff) << 16); 00213 LdtLimit = LdtDescriptor[0] | 00214 ((LdtDescriptor[3] & 0xf) << 16); 00215 00216 if(LdtLimit < (NewLdtSize - 1)) 00217 { 00218 /* allocate new ldt, copy old one there, set gdt ldt entry to new 00219 values and load ldtr register and free old ldt */ 00220 00221 ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool, 00222 NewLdtSize); 00223 00224 if(!NewLdtBase) 00225 { 00226 KeReleaseSpinLock(&LdtLock, oldIrql); 00227 return STATUS_INSUFFICIENT_RESOURCES; 00228 } 00229 00230 if(LdtBase) 00231 { 00232 memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1); 00233 } 00234 00235 LdtDescriptor[0] = (USHORT)((--NewLdtSize) & 0xffff); 00236 LdtDescriptor[1] = (USHORT)(NewLdtBase & 0xffff); 00237 LdtDescriptor[2] = (USHORT)(((NewLdtBase & 0xff0000) >> 16) | 0x8200); 00238 LdtDescriptor[3] = (USHORT)(((NewLdtSize & 0xf0000) >> 16) | 00239 ((NewLdtBase & 0xff000000) >> 16)); 00240 00241 KeSetGdtSelector(KGDT_LDT, 00242 ((PULONG) LdtDescriptor)[0], 00243 ((PULONG) LdtDescriptor)[1]); 00244 00245 Ke386SetLocalDescriptorTable(KGDT_LDT); 00246 00247 if(LdtBase) 00248 { 00249 ExFreePool((PVOID) LdtBase); 00250 } 00251 00252 LdtBase = NewLdtBase; 00253 } 00254 00255 if(Selector1) 00256 { 00257 memcpy((char*)LdtBase + Selector1, 00258 &LdtEntry1, 00259 sizeof(LDT_ENTRY)); 00260 } 00261 00262 if(Selector2) 00263 { 00264 memcpy((char*)LdtBase + Selector2, 00265 &LdtEntry2, 00266 sizeof(LDT_ENTRY)); 00267 } 00268 00269 KeReleaseSpinLock(&LdtLock, oldIrql); 00270 return STATUS_SUCCESS; 00271 } 00272 00273 Generated on Fri May 25 2012 04:35:55 for ReactOS by
1.7.6.1
|