ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ldt.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.