177 lines
3.4 KiB
C
177 lines
3.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
gdtsup.c
|
||
|
||
Abstract:
|
||
|
||
This module implements interfaces that support manipulation of i386 GDTs.
|
||
These entry points only exist on i386 machines.
|
||
|
||
Author:
|
||
|
||
Dave Hastings (daveh) 28 May 1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGELK, KeI386SetGdtSelector)
|
||
#pragma alloc_text(PAGE, Ke386GetGdtEntryThread)
|
||
#endif
|
||
|
||
VOID
|
||
Ke386GetGdtEntryThread(
|
||
IN PKTHREAD Thread,
|
||
IN ULONG Offset,
|
||
IN PKGDTENTRY Descriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the contents of an entry in the GDT. If the
|
||
entry is thread specific, the entry for the specified thread is
|
||
created and returned (KGDT_LDT, and KGDT_R3_TEB). If the selector
|
||
is processor dependent, the entry for the current processor is
|
||
returned (KGDT_R0_PCR).
|
||
|
||
Arguments:
|
||
|
||
Thread -- Supplies a pointer to the thread to return the entry for.
|
||
|
||
Offset -- Supplies the offset in the Gdt. This value must be 0
|
||
mod 8.
|
||
|
||
Descriptor -- Returns the contents of the Gdt descriptor
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PKGDTENTRY Gdt;
|
||
PKPROCESS Process;
|
||
|
||
//
|
||
// If the entry is out of range, don't return anything
|
||
//
|
||
|
||
if (Offset >= KGDT_NUMBER * sizeof(KGDTENTRY)) {
|
||
return ;
|
||
}
|
||
|
||
if (Offset == KGDT_LDT) {
|
||
|
||
//
|
||
// Materialize Ldt selector
|
||
//
|
||
|
||
Process = Thread->ApcState.Process;
|
||
RtlCopyMemory( Descriptor,
|
||
&(Process->LdtDescriptor),
|
||
sizeof(KGDTENTRY)
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Copy Selector from Ldt
|
||
//
|
||
// N.B. We will change the base later, if it is KGDT_R3_TEB
|
||
//
|
||
|
||
|
||
Gdt = KiPcr()->GDT;
|
||
|
||
RtlCopyMemory(Descriptor, (PCHAR)Gdt + Offset, sizeof(KGDTENTRY));
|
||
|
||
//
|
||
// if it is the TEB selector, fix the base
|
||
//
|
||
|
||
if (Offset == KGDT_R3_TEB) {
|
||
Descriptor->BaseLow = (USHORT)((ULONG)(Thread->Teb) & 0xFFFF);
|
||
Descriptor->HighWord.Bytes.BaseMid =
|
||
(UCHAR) ( ( (ULONG)(Thread->Teb) & 0xFF0000L) >> 16);
|
||
Descriptor->HighWord.Bytes.BaseHi =
|
||
(CHAR) ( ( (ULONG)(Thread->Teb) & 0xFF000000L) >> 24);
|
||
}
|
||
}
|
||
|
||
return ;
|
||
}
|
||
|
||
NTSTATUS
|
||
KeI386SetGdtSelector (
|
||
ULONG Selector,
|
||
PKGDTENTRY GdtValue
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets a GDT entry obtained via KeI386AllocateGdtSelectors to the supplied
|
||
GdtValue.
|
||
|
||
Arguments:
|
||
|
||
Selector - Which GDT to set
|
||
|
||
GdtValue - GDT value to set into GDT
|
||
|
||
Return Value:
|
||
|
||
status code
|
||
|
||
--*/
|
||
{
|
||
KAFFINITY TargetSet;
|
||
PKPRCB Prcb;
|
||
PKPCR Pcr;
|
||
PKGDTENTRY GdtEntry;
|
||
ULONG GdtIndex, BitNumber;
|
||
|
||
PAGED_CODE ();
|
||
|
||
//
|
||
// Verify GDT entry passed, and it's above the kernel GDT values
|
||
//
|
||
|
||
GdtIndex = Selector >> 3;
|
||
if ((Selector & 0x7) != 0 || GdtIndex < KGDT_NUMBER) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Set GDT entry in each processor's GDT
|
||
//
|
||
|
||
TargetSet = KeActiveProcessors;
|
||
while (TargetSet != 0) {
|
||
KeFindFirstSetLeftAffinity(TargetSet, &BitNumber);
|
||
ClearMember(BitNumber, TargetSet);
|
||
|
||
Prcb = KiProcessorBlock[BitNumber];
|
||
Pcr = CONTAINING_RECORD (Prcb, KPCR, PrcbData);
|
||
GdtEntry = Pcr->GDT + GdtIndex;
|
||
|
||
// set it
|
||
*GdtEntry = *GdtValue;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|