393 lines
7.8 KiB
C
393 lines
7.8 KiB
C
|
/*++
|
|||
|
|
|||
|
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 (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
Ki386FlushTargetDescriptors (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
);
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KGDTENTRY LdtDescriptor;
|
|||
|
BOOLEAN LocalProcessor;
|
|||
|
KIRQL OldIrql;
|
|||
|
PKPRCB Prcb;
|
|||
|
KAFFINITY TargetProcessors;
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the context swap lock so a context switch cannot occur.
|
|||
|
//
|
|||
|
|
|||
|
KiLockContextSwap(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Set the Ldt fields in the process object.
|
|||
|
//
|
|||
|
|
|||
|
Process->LdtDescriptor = LdtDescriptor;
|
|||
|
|
|||
|
//
|
|||
|
// Tell all processors active for this process to reload their LDTs
|
|||
|
//
|
|||
|
|
|||
|
#ifdef NT_UP
|
|||
|
|
|||
|
KiLoadLdtr();
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
Prcb = KeGetCurrentPrcb();
|
|||
|
TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiSendPacket(TargetProcessors,
|
|||
|
Ki386LoadTargetLdtr,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
KiLoadLdtr();
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Stall until target processor(s) release us
|
|||
|
//
|
|||
|
|
|||
|
KiIpiStallOnPacketTargets(TargetProcessors);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Restore IRQL and release the context swap lock.
|
|||
|
//
|
|||
|
|
|||
|
KiUnlockContextSwap(OldIrql);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
Ki386LoadTargetLdtr (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reload local Ldt register and clear signal bit in TargetProcessor mask
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Argument - pointer to a ipi packet structure.
|
|||
|
ReadyFlag - Pointer to flag to be set once LDTR has been reloaded
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Reload the LDTR register from currently active process object
|
|||
|
//
|
|||
|
|
|||
|
KiLoadLdtr();
|
|||
|
KiIpiSignalPacketDone(SignalDone);
|
|||
|
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 accross 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;
|
|||
|
KIRQL OldIrql;
|
|||
|
PKPRCB Prcb;
|
|||
|
KAFFINITY TargetProcessors;
|
|||
|
|
|||
|
//
|
|||
|
// Compute address of descriptor to edit.
|
|||
|
//
|
|||
|
|
|||
|
Ldt =
|
|||
|
(PLDT_ENTRY)
|
|||
|
((Process->LdtDescriptor.HighWord.Bytes.BaseHi << 24) |
|
|||
|
((Process->LdtDescriptor.HighWord.Bytes.BaseMid << 16) & 0xff0000) |
|
|||
|
(Process->LdtDescriptor.BaseLow & 0xffff));
|
|||
|
Offset = Offset / 8;
|
|||
|
KiLockContextSwap(&OldIrql);
|
|||
|
|
|||
|
#ifdef NT_UP
|
|||
|
|
|||
|
//
|
|||
|
// Edit the Ldt.
|
|||
|
//
|
|||
|
|
|||
|
Ldt[Offset] = LdtEntry;
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
Prcb = KeGetCurrentPrcb();
|
|||
|
TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiSendSynchronousPacket(
|
|||
|
Prcb,
|
|||
|
TargetProcessors,
|
|||
|
Ki386FlushTargetDescriptors,
|
|||
|
(PVOID)&Prcb->ReverseStall,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
KiIpiStallOnPacketTargets(TargetProcessors);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// All target processors have flushed the segment descriptors and
|
|||
|
// are waiting to proceed. Edit the ldt on the current processor,
|
|||
|
// then continue the execution of target processors.
|
|||
|
//
|
|||
|
|
|||
|
Ldt[Offset] = LdtEntry;
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
Prcb->ReverseStall += 1;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Restore IRQL and release the context swap lock.
|
|||
|
//
|
|||
|
|
|||
|
KiUnlockContextSwap(OldIrql);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
Ki386FlushTargetDescriptors (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Proceed,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function flushes the segment descriptors on the current processor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Argument - pointer to a _KIPI_FLUSH_DESCRIPTOR structure.
|
|||
|
|
|||
|
ReadyFlag - pointer to flag to syncroize with
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Flush the segment descriptors on the current processor and signal that
|
|||
|
// the descriptors have been flushed.
|
|||
|
//
|
|||
|
|
|||
|
KiFlushDescriptors();
|
|||
|
KiIpiSignalPacketDoneAndStall (SignalDone, Proceed);
|
|||
|
return;
|
|||
|
}
|