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;
|
2006-09-03 07:13:02 +00:00
|
|
|
static KSPIN_LOCK GdtLock;
|
2001-04-16 23:29:55 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2006-09-03 07:13:02 +00:00
|
|
|
VOID
|
|
|
|
KeSetBaseGdtSelector(ULONG Entry,
|
|
|
|
PVOID Base)
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PUSHORT Gdt;
|
|
|
|
|
|
|
|
DPRINT("KeSetBaseGdtSelector(Entry %x, Base %x)\n",
|
|
|
|
Entry, Base);
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&GdtLock, &oldIrql);
|
|
|
|
|
|
|
|
Gdt = KeGetCurrentKPCR()->GDT;
|
|
|
|
Entry = (Entry & (~0x3)) / 2;
|
|
|
|
|
|
|
|
Gdt[Entry + 1] = (USHORT)(((ULONG)Base) & 0xffff);
|
|
|
|
|
|
|
|
Gdt[Entry + 2] = Gdt[Entry + 2] & ~(0xff);
|
|
|
|
Gdt[Entry + 2] = (USHORT)(Gdt[Entry + 2] |
|
|
|
|
((((ULONG)Base) & 0xff0000) >> 16));
|
|
|
|
|
|
|
|
Gdt[Entry + 3] = Gdt[Entry + 3] & ~(0xff00);
|
|
|
|
Gdt[Entry + 3] = (USHORT)(Gdt[Entry + 3] |
|
|
|
|
((((ULONG)Base) & 0xff000000) >> 16));
|
|
|
|
|
|
|
|
DPRINT("%x %x %x %x\n",
|
|
|
|
Gdt[Entry + 0],
|
|
|
|
Gdt[Entry + 1],
|
|
|
|
Gdt[Entry + 2],
|
|
|
|
Gdt[Entry + 3]);
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&GdtLock, oldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
KeSetGdtSelector(ULONG Entry,
|
|
|
|
ULONG Value1,
|
|
|
|
ULONG Value2)
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PULONG Gdt;
|
|
|
|
|
|
|
|
DPRINT("KeSetGdtSelector(Entry %x, Value1 %x, Value2 %x)\n",
|
|
|
|
Entry, Value1, Value2);
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&GdtLock, &oldIrql);
|
|
|
|
|
|
|
|
Gdt = (PULONG) KeGetCurrentKPCR()->GDT;
|
|
|
|
Entry = (Entry & (~0x3)) / 4;
|
|
|
|
|
|
|
|
Gdt[Entry] = Value1;
|
|
|
|
Gdt[Entry + 1] = Value2;
|
|
|
|
|
|
|
|
DPRINT("%x %x\n",
|
|
|
|
Gdt[Entry + 0],
|
|
|
|
Gdt[Entry + 1]);
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&GdtLock, oldIrql);
|
|
|
|
}
|
2005-06-18 15:15:25 +00:00
|
|
|
|
2006-09-07 05:07:34 +00:00
|
|
|
BOOLEAN PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
|
2003-08-19 23:59:08 +00:00
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
2006-08-06 22:02:02 +00:00
|
|
|
if ((Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
|
|
|
|
(Base > Base+SegLimit))
|
|
|
|
{
|
|
|
|
DPRINT1("WARNING: Windows would mark this descriptor invalid!");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Certain "DOS32" programs expect to be able to create DPMI selectors
|
|
|
|
that wrap the address space. Windows NT does not allow user-created
|
|
|
|
selectors to reach into kernel memory. However, there is no security
|
|
|
|
risk in allowing it; the page table will prevent access anyway.
|
|
|
|
*/
|
|
|
|
return (/*(Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
|
|
|
|
(Base > Base+SegLimit) ? FALSE : TRUE*/ TRUE);
|
2003-08-19 23:59:08 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2005-11-27 03:08:35 +00:00
|
|
|
KeSetGdtSelector(KGDT_LDT,
|
2003-08-19 23:59:08 +00:00
|
|
|
((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 */
|
2005-11-27 03:08:35 +00:00
|
|
|
: "a" (KGDT_LDT));
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
2005-11-27 03:08:35 +00:00
|
|
|
__asm mov ax, KGDT_LDT
|
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
|
|
|
|