Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

388 lines
8.2 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ldtsup.c
Abstract:
This module implements interfaces that support manipulation of i386 Ldts.
These entry points only exist on i386 machines.
Author:
Bryan M. Willman (bryanwi) 14-May-1991
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
//
// Low level assembler support procedures
//
VOID
KiLoadLdtr(
VOID
);
VOID
KiFlushDescriptors(
VOID
);
//
// Local service procedures
//
VOID
Ki386LoadTargetLdtr (
PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
VOID
Ki386FlushTargetDescriptors (
PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
typedef struct _LDTINFO {
PKPROCESS Process;
KGDTENTRY LdtDescriptor;
ULONG Offset;
LDT_ENTRY LdtEntry;
PLDT_ENTRY Ldt;
} LDTINFO, *PLDTINFO;
VOID
Ke386SetLdtProcess (
IN PKPROCESS Process,
IN PLDT_ENTRY Ldt,
IN ULONG Limit
)
/*++
Routine Description:
The specified LDT (which may be null) will be made the active Ldt of
the specified process, for all threads thereof, on whichever
processors they are running. The change will take effect before the
call returns.
An Ldt address of NULL or a Limit of 0 will cause the process to
receive the NULL Ldt.
This function only exists on i386 and i386 compatible processors.
No checking is done on the validity of Ldt entries.
N.B.
While a single Ldt structure can be shared amoung processes, any
edits to the Ldt of one of those processes will only be synchronized
for that process. Thus, processes other than the one the change is
applied to may not see the change correctly.
Arguments:
Process - Pointer to KPROCESS object describing the process for
which the Ldt is to be set.
Ldt - Pointer to an array of LDT_ENTRYs (that is, a pointer to an
Ldt.)
Limit - Ldt limit (must be 0 mod 8)
Return Value:
None.
--*/
{
LDTINFO LdtInfo;
KGDTENTRY LdtDescriptor;
//
// Compute the contents of the Ldt descriptor
//
if ((Ldt == NULL) || (Limit == 0)) {
//
// Set up an empty descriptor
//
LdtDescriptor.LimitLow = 0;
LdtDescriptor.BaseLow = 0;
LdtDescriptor.HighWord.Bytes.BaseMid = 0;
LdtDescriptor.HighWord.Bytes.Flags1 = 0;
LdtDescriptor.HighWord.Bytes.Flags2 = 0;
LdtDescriptor.HighWord.Bytes.BaseHi = 0;
} else {
//
// Insure that the unfilled fields of the selector are zero
// N.B. If this is not done, random values appear in the high
// portion of the Ldt limit.
//
LdtDescriptor.HighWord.Bytes.Flags1 = 0;
LdtDescriptor.HighWord.Bytes.Flags2 = 0;
//
// Set the limit and base
//
LdtDescriptor.LimitLow = (USHORT) ((ULONG) Limit - 1);
LdtDescriptor.BaseLow = (USHORT) ((ULONG) Ldt & 0xffff);
LdtDescriptor.HighWord.Bytes.BaseMid = (UCHAR) (((ULONG)Ldt & 0xff0000) >> 16);
LdtDescriptor.HighWord.Bytes.BaseHi = (UCHAR) (((ULONG)Ldt & 0xff000000) >> 24);
//
// Type is LDT, DPL = 0
//
LdtDescriptor.HighWord.Bits.Type = TYPE_LDT;
LdtDescriptor.HighWord.Bits.Dpl = DPL_SYSTEM;
//
// Make it present
//
LdtDescriptor.HighWord.Bits.Pres = 1;
}
LdtInfo.Process = Process;
LdtInfo.LdtDescriptor = LdtDescriptor;
KeGenericCallDpc (Ki386LoadTargetLdtr,
&LdtInfo);
return;
}
VOID
Ki386LoadTargetLdtr (
PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
Reload local Ldt register and clear signal bit in TargetProcessor mask
Arguments:
Dpc - DPC used to initiate this call
DeferredContext - Context
SystemArgument1 - System context, Used to signal completion of this call
SystemArgument2 - System context
Return Value:
none.
--*/
{
PLDTINFO LdtInfo;
UNREFERENCED_PARAMETER (Dpc);
LdtInfo = DeferredContext;
//
// Make sure all DPC's are running so a load of the process
// LdtDescriptor field can't be torn
//
if (KeSignalCallDpcSynchronize (SystemArgument2)) {
//
// Set the Ldt fields in the process object.
//
LdtInfo->Process->LdtDescriptor = LdtInfo->LdtDescriptor;
}
//
// Make sure the field has been updated before we continue
//
KeSignalCallDpcSynchronize (SystemArgument2);
//
// Reload the LDTR register from currently active process object
//
KiLoadLdtr();
//
// Signal that all processing has been done
//
KeSignalCallDpcDone (SystemArgument1);
return;
}
VOID
Ke386SetDescriptorProcess (
IN PKPROCESS Process,
IN ULONG Offset,
IN LDT_ENTRY LdtEntry
)
/*++
Routine Description:
The specified LdtEntry (which could be 0, not present, etc) will be
edited into the specified Offset in the Ldt of the specified Process.
This will be synchronzied across all the processors executing the
process. The edit will take affect on all processors before the call
returns.
N.B.
Editing an Ldt descriptor requires stalling all processors active
for the process, to prevent accidental loading of descriptors in
an inconsistent state.
Arguments:
Process - Pointer to KPROCESS object describing the process for
which the descriptor edit is to be performed.
Offset - Byte offset into the Ldt of the descriptor to edit.
Must be 0 mod 8.
LdtEntry - Value to edit into the descriptor in hardware format.
No checking is done on the validity of this item.
Return Value:
none.
--*/
{
PLDT_ENTRY Ldt;
LDTINFO LdtInfo;
//
// Compute address of descriptor to edit. It is safe to fetch the process
// LdtDescriptor here as we are always called with the PS LdtMutex held.
//
Ldt =
(PLDT_ENTRY)
((Process->LdtDescriptor.HighWord.Bytes.BaseHi << 24) |
((Process->LdtDescriptor.HighWord.Bytes.BaseMid << 16) & 0xff0000) |
(Process->LdtDescriptor.BaseLow & 0xffff));
Offset = Offset / 8;
LdtInfo.Process = Process;
LdtInfo.Offset = Offset;
LdtInfo.Ldt = Ldt;
LdtInfo.LdtEntry = LdtEntry;
KeGenericCallDpc (Ki386FlushTargetDescriptors,
&LdtInfo);
return;
}
VOID
Ki386FlushTargetDescriptors (
PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This function flushes the segment descriptors on the current processor.
Arguments:
Dpc - DPC used to initiate this call
DeferredContext - Context
SystemArgument1 - System context, Used to signal completion of this call
SystemArgument2 - System context
Return Value:
none.
--*/
{
PLDTINFO LdtInfo;
UNREFERENCED_PARAMETER (Dpc);
LdtInfo = DeferredContext;
//
// Flush the segment descriptors on the current processor.
// This call removes all possible references to the LDT from
// the segment registers.
//
KiFlushDescriptors ();
//
// Make sure all DPC's are running so a load of the process
// LdtDescriptor field can't be torn
//
if (KeSignalCallDpcSynchronize (SystemArgument2)) {
//
// Update the LDT entry
//
LdtInfo->Ldt[LdtInfo->Offset] = LdtInfo->LdtEntry;
}
//
// Wait until everyone has got to this point before continuing
//
KeSignalCallDpcSynchronize (SystemArgument2);
//
// Signal that all processing has been done
//
KeSignalCallDpcDone (SystemArgument1);
return;
}