2005-04-22 12:52:25 +00:00
|
|
|
/* $Id$
|
2001-04-16 23:29:55 +00:00
|
|
|
*
|
2005-01-26 13:58:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
1998-10-05 04:00:59 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
2001-04-16 23:29:55 +00:00
|
|
|
* FILE: ntoskrnl/ke/i386/ldt.c
|
1999-03-30 12:55:31 +00:00
|
|
|
* PURPOSE: LDT managment
|
2005-01-26 13:58:37 +00:00
|
|
|
*
|
|
|
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
1998-10-05 04:00:59 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2001-04-16 23:29:55 +00:00
|
|
|
#define NDEBUG
|
1998-10-05 04:00:59 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
2001-04-16 23:29:55 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2003-08-19 23:59:08 +00:00
|
|
|
static KSPIN_LOCK LdtLock;
|
2001-04-16 23:29:55 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2003-08-19 23:59:08 +00:00
|
|
|
BOOL PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
|
|
|
|
{
|
2003-08-21 04:17:15 +00:00
|
|
|
ULONG Base, SegLimit;
|
2005-05-09 01:38:29 +00:00
|
|
|
/*
|
2003-08-19 23:59:08 +00:00
|
|
|
Allow invalid descriptors.
|
|
|
|
*/
|
|
|
|
if(!ldt_entry->HighWord.Bits.Type &&
|
|
|
|
!ldt_entry->HighWord.Bits.Dpl)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* eliminate system descriptors and code segments other than
|
|
|
|
execute and execute/read and DPL<3 descriptors */
|
|
|
|
if(!(ldt_entry->HighWord.Bits.Type & 0x10) ||
|
|
|
|
(ldt_entry->HighWord.Bits.Type & 0x8 &&
|
|
|
|
ldt_entry->HighWord.Bits.Type & 0x4) ||
|
|
|
|
ldt_entry->HighWord.Bits.Dpl != 3 ||
|
|
|
|
ldt_entry->HighWord.Bits.Reserved_0) return FALSE;
|
|
|
|
|
|
|
|
if(!ldt_entry->HighWord.Bits.Pres) return TRUE;
|
|
|
|
|
2003-08-21 04:17:15 +00:00
|
|
|
Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) |
|
2003-08-19 23:59:08 +00:00
|
|
|
(ldt_entry->HighWord.Bytes.BaseHi << 24);
|
|
|
|
|
2003-08-21 04:17:15 +00:00
|
|
|
SegLimit=ldt_entry->LimitLow |
|
2003-08-19 23:59:08 +00:00
|
|
|
(ldt_entry->HighWord.Bits.LimitHi << 16);
|
|
|
|
|
|
|
|
if(ldt_entry->HighWord.Bits.Type & 0x4)
|
|
|
|
{
|
|
|
|
SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1;
|
|
|
|
|
|
|
|
} else if(ldt_entry->HighWord.Bits.Granularity)
|
|
|
|
{
|
|
|
|
SegLimit=(SegLimit << 12) | 0xfff;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ((Base + SegLimit > (ULONG) MmHighestUserAddress) ||
|
|
|
|
(Base > Base+SegLimit) ? FALSE : TRUE);
|
|
|
|
}
|
|
|
|
|
2001-04-16 23:29:55 +00:00
|
|
|
NTSTATUS STDCALL
|
2003-08-19 23:59:08 +00:00
|
|
|
NtSetLdtEntries (ULONG Selector1,
|
|
|
|
LDT_ENTRY LdtEntry1,
|
|
|
|
ULONG Selector2,
|
|
|
|
LDT_ENTRY LdtEntry2)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2003-08-19 23:59:08 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
ULONG NewLdtSize = sizeof(LDT_ENTRY);
|
2003-08-21 04:17:15 +00:00
|
|
|
PUSHORT LdtDescriptor;
|
|
|
|
ULONG LdtBase;
|
|
|
|
ULONG LdtLimit;
|
2003-08-19 23:59:08 +00:00
|
|
|
|
|
|
|
if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR;
|
|
|
|
|
|
|
|
Selector1 &= ~0x7;
|
|
|
|
Selector2 &= ~0x7;
|
|
|
|
|
|
|
|
if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) ||
|
|
|
|
(Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR;
|
|
|
|
if(!(Selector1 || Selector2)) return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&LdtLock, &oldIrql);
|
|
|
|
|
2005-05-05 22:40:05 +00:00
|
|
|
LdtDescriptor = (PUSHORT) &KeGetCurrentProcess()->LdtDescriptor;
|
2003-08-21 04:17:15 +00:00
|
|
|
LdtBase = LdtDescriptor[1] |
|
2003-08-19 23:59:08 +00:00
|
|
|
((LdtDescriptor[2] & 0xff) << 16) |
|
|
|
|
((LdtDescriptor[3] & ~0xff) << 16);
|
2003-08-21 04:17:15 +00:00
|
|
|
LdtLimit = LdtDescriptor[0] |
|
2003-08-19 23:59:08 +00:00
|
|
|
((LdtDescriptor[3] & 0xf) << 16);
|
|
|
|
|
|
|
|
if(LdtLimit < (NewLdtSize - 1))
|
|
|
|
{
|
|
|
|
/* allocate new ldt, copy old one there, set gdt ldt entry to new
|
|
|
|
values and load ldtr register and free old ldt */
|
|
|
|
|
|
|
|
ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool,
|
|
|
|
NewLdtSize);
|
|
|
|
|
|
|
|
if(!NewLdtBase)
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&LdtLock, oldIrql);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(LdtBase)
|
|
|
|
{
|
|
|
|
memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1);
|
|
|
|
}
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
LdtDescriptor[0] = (USHORT)((--NewLdtSize) & 0xffff);
|
|
|
|
LdtDescriptor[1] = (USHORT)(NewLdtBase & 0xffff);
|
|
|
|
LdtDescriptor[2] = (USHORT)(((NewLdtBase & 0xff0000) >> 16) | 0x8200);
|
|
|
|
LdtDescriptor[3] = (USHORT)(((NewLdtSize & 0xf0000) >> 16) |
|
|
|
|
((NewLdtBase & 0xff000000) >> 16));
|
2003-08-19 23:59:08 +00:00
|
|
|
|
|
|
|
KeSetGdtSelector(LDT_SELECTOR,
|
|
|
|
((PULONG) LdtDescriptor)[0],
|
|
|
|
((PULONG) LdtDescriptor)[1]);
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2005-05-09 01:38:29 +00:00
|
|
|
__asm__("lldtw %%ax"
|
2003-08-19 23:59:08 +00:00
|
|
|
: /* no output */
|
|
|
|
: "a" (LDT_SELECTOR));
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm mov ax, LDT_SELECTOR
|
2005-05-09 01:38:29 +00:00
|
|
|
__asm lldt ax
|
2003-12-30 18:52:06 +00:00
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2003-08-19 23:59:08 +00:00
|
|
|
|
|
|
|
if(LdtBase)
|
|
|
|
{
|
|
|
|
ExFreePool((PVOID) LdtBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
LdtBase = NewLdtBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Selector1)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
memcpy((char*)LdtBase + Selector1,
|
2003-08-19 23:59:08 +00:00
|
|
|
&LdtEntry1,
|
|
|
|
sizeof(LDT_ENTRY));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Selector2)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
memcpy((char*)LdtBase + Selector2,
|
2003-08-19 23:59:08 +00:00
|
|
|
&LdtEntry2,
|
|
|
|
sizeof(LDT_ENTRY));
|
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&LdtLock, oldIrql);
|
|
|
|
return STATUS_SUCCESS;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
|
2001-04-17 04:11:01 +00:00
|
|
|
VOID
|
|
|
|
Ki386InitializeLdt(VOID)
|
|
|
|
{
|
|
|
|
PUSHORT Gdt = KeGetCurrentKPCR()->GDT;
|
|
|
|
unsigned int base, length;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up an a descriptor for the LDT
|
|
|
|
*/
|
2003-08-19 23:59:08 +00:00
|
|
|
base = length = 0;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2001-04-17 04:11:01 +00:00
|
|
|
Gdt[(LDT_SELECTOR / 2) + 0] = (length & 0xFFFF);
|
|
|
|
Gdt[(LDT_SELECTOR / 2) + 1] = (base & 0xFFFF);
|
|
|
|
Gdt[(LDT_SELECTOR / 2) + 2] = ((base & 0xFF0000) >> 16) | 0x8200;
|
|
|
|
Gdt[(LDT_SELECTOR / 2) + 3] = ((length & 0xF0000) >> 16) |
|
|
|
|
((base & 0xFF000000) >> 16);
|
|
|
|
}
|