229 lines
4.6 KiB
C
229 lines
4.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
vdmint21.c
|
||
|
||
Abstract:
|
||
|
||
This module implements interfaces that support manipulation of i386
|
||
int 21 entry of IDT. These entry points only exist on i386 machines.
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) 26-Dec-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
#pragma hdrstop
|
||
#include "vdmntos.h"
|
||
|
||
#define IDT_ACCESS_DPL_USER 0x6000
|
||
#define IDT_ACCESS_TYPE_386_TRAP 0xF00
|
||
#define IDT_ACCESS_TYPE_286_TRAP 0x700
|
||
#define IDT_ACCESS_PRESENT 0x8000
|
||
#define LDT_MASK 4
|
||
|
||
//
|
||
// External Reference
|
||
//
|
||
|
||
BOOLEAN
|
||
Ki386GetSelectorParameters(
|
||
IN USHORT Selector,
|
||
OUT PULONG Flags,
|
||
OUT PULONG Base,
|
||
OUT PULONG Limit
|
||
);
|
||
|
||
//
|
||
// Define forward referenced function prototypes.
|
||
//
|
||
|
||
VOID
|
||
Ki386LoadTargetInt21Entry (
|
||
IN PKIPI_CONTEXT SignalDone,
|
||
IN PVOID Parameter1,
|
||
IN PVOID Parameter2,
|
||
IN PVOID Parameter3
|
||
);
|
||
|
||
#define KiLoadInt21Entry() \
|
||
KeGetPcr()->IDT[0x21] = PsGetCurrentProcess()->Pcb.Int21Descriptor
|
||
|
||
NTSTATUS
|
||
Ke386SetVdmInterruptHandler (
|
||
PKPROCESS Process,
|
||
ULONG Interrupt,
|
||
USHORT Selector,
|
||
ULONG Offset,
|
||
BOOLEAN Gate32
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The specified (software) interrupt entry of IDT will be updated to
|
||
point to the specified handler. For all threads which belong to the
|
||
specified process, their execution processors will be notified to
|
||
make the same change.
|
||
|
||
This function only exists on i386 and i386 compatible processors.
|
||
|
||
No checking is done on the validity of the interrupt handler.
|
||
|
||
Arguments:
|
||
|
||
Process - Pointer to KPROCESS object describing the process for
|
||
which the int 21 entry is to be set.
|
||
|
||
Interrupt - The software interrupt vector which will be updated.
|
||
|
||
Selector, offset - Specified the address of the new handler.
|
||
|
||
Gate32 - True if the gate should be 32 bit, false otherwise
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
BOOLEAN LocalProcessor;
|
||
KAFFINITY TargetProcessors;
|
||
PKPRCB Prcb;
|
||
KIDTENTRY IdtDescriptor;
|
||
ULONG Flags, Base, Limit;
|
||
|
||
//
|
||
// Check the validity of the request
|
||
// 1. Currently, we support int21 redirection only
|
||
// 2. The specified interrupt handler must be in user space.
|
||
//
|
||
|
||
if (Interrupt != 0x21 || Offset >= (ULONG)MM_HIGHEST_USER_ADDRESS ||
|
||
!Ki386GetSelectorParameters(Selector, &Flags, &Base, &Limit) ){
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// Initialize the contents of the IDT entry
|
||
//
|
||
|
||
IdtDescriptor.Offset = (USHORT)Offset;
|
||
IdtDescriptor.Selector = Selector | RPL_MASK | LDT_MASK;
|
||
IdtDescriptor.ExtendedOffset = (USHORT)(Offset >> 16);
|
||
IdtDescriptor.Access = IDT_ACCESS_DPL_USER | IDT_ACCESS_PRESENT;
|
||
if (Gate32) {
|
||
IdtDescriptor.Access |= IDT_ACCESS_TYPE_386_TRAP;
|
||
|
||
} else {
|
||
IdtDescriptor.Access |= IDT_ACCESS_TYPE_286_TRAP;
|
||
}
|
||
|
||
//
|
||
// Acquire the context swap lock so a context switch will not occur.
|
||
//
|
||
|
||
KiLockContextSwap(&OldIrql);
|
||
|
||
//
|
||
// Set the Ldt fields in the process object
|
||
//
|
||
|
||
Process->Int21Descriptor = IdtDescriptor;
|
||
|
||
//
|
||
// Tell all processors active for this process to reload their LDTs
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
Prcb = KeGetCurrentPrcb();
|
||
TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
|
||
if (TargetProcessors != 0) {
|
||
KiIpiSendPacket(TargetProcessors,
|
||
Ki386LoadTargetInt21Entry,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
}
|
||
|
||
#endif
|
||
|
||
KiLoadInt21Entry();
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
//
|
||
// Wait until all of the target processors have finished reloading
|
||
// their LDT.
|
||
//
|
||
|
||
if (TargetProcessors != 0) {
|
||
KiIpiStallOnPacketTargets(TargetProcessors);
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Restore IRQL and unlock the context swap lock.
|
||
//
|
||
|
||
KiUnlockContextSwap(OldIrql);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
|
||
VOID
|
||
Ki386LoadTargetInt21Entry (
|
||
IN PKIPI_CONTEXT PacketContext,
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Set the int 21 entry of IDT from currently active process object
|
||
//
|
||
|
||
KiLoadInt21Entry();
|
||
KiIpiSignalPacketDone(PacketContext);
|
||
return;
|
||
}
|
||
|
||
#endif
|