update for HEAD-2003091401
[reactos.git] / ntoskrnl / ke / i386 / ldt.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2000  ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  */
19 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/ke/i386/ldt.c
22  * PURPOSE:         LDT managment
23  * PROGRAMMER:      David Welch (welch@cwcom.net)
24  * UPDATE HISTORY:
25  *                  Created 22/05/98
26  */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/ke.h>
32 #include <internal/ps.h>
33 #include <internal/i386/segment.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 static KSPIN_LOCK LdtLock;
41
42 /* FUNCTIONS *****************************************************************/
43
44 BOOL PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
45 {
46   ULONG Base, SegLimit;
47   /* 
48      Allow invalid descriptors.
49   */
50   if(!ldt_entry->HighWord.Bits.Type &&
51      !ldt_entry->HighWord.Bits.Dpl)
52        return TRUE;
53
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;
61
62   if(!ldt_entry->HighWord.Bits.Pres) return TRUE;
63
64   Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) |
65              (ldt_entry->HighWord.Bytes.BaseHi << 24);
66
67   SegLimit=ldt_entry->LimitLow |
68                  (ldt_entry->HighWord.Bits.LimitHi << 16);
69
70   if(ldt_entry->HighWord.Bits.Type & 0x4)
71   {
72     SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1;
73
74   } else if(ldt_entry->HighWord.Bits.Granularity)
75   {
76     SegLimit=(SegLimit << 12) | 0xfff;
77   }
78
79   return ((Base + SegLimit > (ULONG) MmHighestUserAddress) ||
80           (Base > Base+SegLimit) ? FALSE : TRUE);
81 }
82
83 NTSTATUS STDCALL
84 NtSetLdtEntries (ULONG Selector1,
85                  LDT_ENTRY LdtEntry1,
86                  ULONG Selector2,
87                  LDT_ENTRY LdtEntry2)
88 {
89   KIRQL oldIrql;
90   ULONG NewLdtSize = sizeof(LDT_ENTRY);
91   PUSHORT LdtDescriptor;
92   ULONG LdtBase;
93   ULONG LdtLimit;
94
95   if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR;
96
97   Selector1 &= ~0x7;
98   Selector2 &= ~0x7;
99
100   if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) ||
101      (Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR;
102   if(!(Selector1 || Selector2)) return STATUS_SUCCESS;
103
104   NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2;
105
106   KeAcquireSpinLock(&LdtLock, &oldIrql);
107
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);
114
115   if(LdtLimit < (NewLdtSize - 1))
116   {
117     /* allocate new ldt, copy old one there, set gdt ldt entry to new
118        values and load ldtr register and free old ldt */
119
120     ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool,
121                                               NewLdtSize);
122
123     if(!NewLdtBase)
124     {
125       KeReleaseSpinLock(&LdtLock, oldIrql);
126       return STATUS_INSUFFICIENT_RESOURCES;
127     }
128
129     if(LdtBase)
130     {
131       memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1);
132     }
133
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);
139
140     KeSetGdtSelector(LDT_SELECTOR,
141                      ((PULONG) LdtDescriptor)[0],
142                      ((PULONG) LdtDescriptor)[1]);
143
144     __asm__("lldtw %%ax" 
145             : /* no output */
146             : "a" (LDT_SELECTOR));
147
148     if(LdtBase)
149     {
150       ExFreePool((PVOID) LdtBase);
151     }
152
153     LdtBase = NewLdtBase;
154   }
155
156   if(Selector1)
157   {
158     memcpy((PVOID) LdtBase + Selector1,
159            &LdtEntry1,
160            sizeof(LDT_ENTRY));
161   }
162
163   if(Selector2)
164   {
165     memcpy((PVOID) LdtBase + Selector2,
166            &LdtEntry2,
167            sizeof(LDT_ENTRY));
168   }
169
170   KeReleaseSpinLock(&LdtLock, oldIrql);
171   return STATUS_SUCCESS;
172 }
173
174 VOID
175 Ki386InitializeLdt(VOID)
176 {
177   PUSHORT Gdt = KeGetCurrentKPCR()->GDT;
178   unsigned int base, length;
179
180   /*
181    * Set up an a descriptor for the LDT
182    */
183   base = length = 0;
184   
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);
190 }