Beispiel #1
0
VOID
LfsTable_UpdatePrimaryInfo(
	IN PLFS_TABLE		LfsTable,
	IN PLPX_ADDRESS		NetDiskAddress,
	IN UCHAR			UnitDiskNo,
	IN PLPX_ADDRESS		PrimaryAddress
	) {
	PLIST_ENTRY		listEntry ;
	KIRQL			oldIrql ;
	KIRQL			oldIrql2 ;
	PLFSTAB_ENTRY	entry ;

	ExAcquireSpinLock(&LfsTable->SpinLock, &oldIrql) ;
	listEntry = LfsTable->LfsTabPartitionList.Flink ;
	while(listEntry != &LfsTable->LfsTabPartitionList) {
		entry = CONTAINING_RECORD(listEntry, LFSTAB_ENTRY, LfsTabPartitionEntry) ;
		
		if(		RtlCompareMemory(																			// NetDisk Address
						&entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node,
						NetDiskAddress->Node, 
						LPXADDR_NODE_LENGTH) == LPXADDR_NODE_LENGTH &&
						entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Port == NetDiskAddress->Port &&
						entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.UnitDiskNo == UnitDiskNo 		// UnitDisk No
			) {

			ExAcquireSpinLock(&entry->SpinLock, &oldIrql2) ;

			RtlCopyMemory(&entry->PrimaryAddress, PrimaryAddress, sizeof(LPX_ADDRESS)) ;
			entry->Flags |= LFSTABENTRY_FLAG_VAILDPRIMADDRESS;

			ExReleaseSpinLock(&entry->SpinLock, oldIrql2) ;


			SPY_LOG_PRINT( LFS_DEBUG_TABLE_INFO,
			("LFS: LfsTable_UpdatePrimaryInfo: updated the primary address of  NetDisk:%02x:%02x:%02x:%02x:%02x:%02x/%d UnitDisk:%d\n",
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[0],
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[1],
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[2],
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[3],
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[4],
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Node[5],
				NTOHS(entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress.Port),
				(int)entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.UnitDiskNo
			));

		}

		listEntry = listEntry->Flink ;
	}
	ExReleaseSpinLock(&LfsTable->SpinLock, oldIrql) ;
}
Beispiel #2
0
static
VOID
LfsTable_DereferenceEntry (
		IN PLFSTAB_ENTRY	LfsTableEntry
	)
{
    LONG result;
	PLFS_TABLE	LfsTable = LfsTableEntry->LfsTable ;
	KIRQL		oldIrql ;


    result = InterlockedDecrement (&LfsTableEntry->ReferenceCount);
    ASSERT (result >= 0);

    if (result == 0) 
	{
		ExAcquireSpinLock(&LfsTable->SpinLock, &oldIrql) ;
		RemoveEntryList(&LfsTableEntry->LfsTabPartitionEntry) ;
		ExReleaseSpinLock(&LfsTable->SpinLock, oldIrql) ;

		InterlockedDecrement(&LfsTable->EntryCount) ;

		LfsTable_Dereference(LfsTable) ;

		ExFreePoolWithTag(
			LfsTableEntry,
			LFSTAB_ENTRY_TAG
			);

		SPY_LOG_PRINT( LFS_DEBUG_TABLE_INFO,
				("LfsTable_DereferenceEntry: Lfs Table is Freed\n"));
	}
}
Beispiel #3
0
NTSTATUS
KeI386ReleaseLid(
    IN USHORT LogicalId,
    IN PDRIVER_OBJECT DriverObject
    )

/*++

Routine Description:

    This function releases a logical Id.  This routine is called at ABIOS
    device driver destallation or termination.

Arguments:

    LogicalId - Logical Id to be released.

    DriverObject - Supplies a 32-bit flat pointer of the requesting device
                driver's driver object.  The DriverObject is used to check
                the ownership of the specified LID.

Return Value:

    STATUS_SUCCESS - If the requested LID is released.

    STATUS_ABIOS_NOT_PRESENT - If there is no ABIOS support in the system.

    STATUS_ABIOS_NOT_LID_OWNER - If the caller does not own the LID.

--*/

{
    KIRQL OldIrql;
    NTSTATUS Status;

    if (!KiAbiosPresent) {
        return STATUS_ABIOS_NOT_PRESENT;
    }

    ExAcquireSpinLock(&KiAbiosLidTableLock, &OldIrql);

    if (KiLogicalIdTable[LogicalId].Owner == (ULONG)DriverObject) {
        KiLogicalIdTable[LogicalId].Owner = 0L;
        Status = STATUS_SUCCESS;
    } else if (KiLogicalIdTable[LogicalId].Owner == LID_NO_SPECIFIC_OWNER) {
        KiLogicalIdTable[LogicalId].OwnerCount--;
        if (KiLogicalIdTable[LogicalId].OwnerCount == 0L) {
            KiLogicalIdTable[LogicalId].Owner = 0L;
        }
        Status = STATUS_SUCCESS;
    } else {
        Status = STATUS_ABIOS_NOT_LID_OWNER;
    }

    ExReleaseSpinLock(&KiAbiosLidTableLock, OldIrql);

    return Status;
}
Beispiel #4
0
NTSTATUS
KeI386AllocateGdtSelectors(
    OUT PUSHORT SelectorArray,
    IN USHORT NumberOfSelectors
    )

/*++

Routine Description:

    This function allocates a set of GDT selectors for a device driver to use.
    Usually this allocation is performed at device driver initialization time
    to reserve the selectors for later use.

Arguments:

    SelectorArray - Supplies a pointer to an array of USHORT to be filled
                    in with the GDT selectors allocated.

    NumberOfSelectors - Specifies the number of selectors to be allocated.

Return Value:

    STATUS_SUCCESS - If the requested selectors are allocated.

    STATUS_ABIOS_SELECTOR_NOT_AVAILABLE - if system can not allocate the number
                               of selectors requested.

--*/

{
    PKFREE_GDT_ENTRY GdtEntry;
    KIRQL OldIrql;

    if (KiNumberFreeSelectors >= NumberOfSelectors) {
        ExAcquireSpinLock(&KiAbiosGdtLock, &OldIrql);

        //
        // The Free Gdt link list is maintained on Processor 0's GDT ONLY.
        // Because the 'selector' is an offset to the beginning of GDT and
        // it should be the same across all the processors.
        //

        KiNumberFreeSelectors = KiNumberFreeSelectors - NumberOfSelectors;
        GdtEntry = KiFreeGdtListHead;
        while (NumberOfSelectors != 0) {
            *SelectorArray++ = (USHORT)((ULONG)GdtEntry - KiAbiosGdt[0]);
            GdtEntry = GdtEntry->Flink;
            NumberOfSelectors--;
        }
        KiFreeGdtListHead = GdtEntry;
        ExReleaseSpinLock(&KiAbiosGdtLock, OldIrql);
        return STATUS_SUCCESS;
    } else {
        return STATUS_ABIOS_SELECTOR_NOT_AVAILABLE;
    }
}
Beispiel #5
0
static
BOOLEAN
LfsTable_Lookup(
	IN PLFS_TABLE				LfsTable,
	IN PNETDISK_PARTITION_INFO	NetDiskPartitionInfo,
	OUT	PLFSTAB_ENTRY			*LfsTabEntry
	) {
	PLIST_ENTRY		listEntry ;
	KIRQL			oldIrql ;
	PLFSTAB_ENTRY	entry ;
	BOOLEAN			Found ;

	Found = FALSE ;
	ExAcquireSpinLock(&LfsTable->SpinLock, &oldIrql) ;
	listEntry = LfsTable->LfsTabPartitionList.Flink ;
	while(listEntry != &LfsTable->LfsTabPartitionList) {
		entry = CONTAINING_RECORD(listEntry, LFSTAB_ENTRY, LfsTabPartitionEntry) ;
		
		if(		RtlCompareMemory(																			// NetDisk Address
						&entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.NetDiskAddress,
						&NetDiskPartitionInfo->NetDiskAddress, 
						sizeof(LPX_ADDRESS)) == sizeof(LPX_ADDRESS) &&
				entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.UnitDiskNo == NetDiskPartitionInfo->UnitDiskNo 							// UnitDisk No
				&& entry->LocalNetDiskPartitionInfo.NetDiskPartitionInfo.StartingOffset.QuadPart == NetDiskPartitionInfo->StartingOffset.QuadPart	//	Partition Starting Byte Offset
			) {

			LfsTable_ReferenceEntry (
					entry
				) ;
			*LfsTabEntry = entry ;
			Found = TRUE ;
			break ;
		}

		listEntry = listEntry->Flink ;
	}
	ExReleaseSpinLock(&LfsTable->SpinLock, oldIrql) ;

#if DBG
	if(!Found) {
		SPY_LOG_PRINT( LFS_DEBUG_TABLE_INFO,
			("LFS: LfsTable_Lookup: updated the primary address of  NetDisk:%02x:%02x:%02x:%02x:%02x:%02x/%d UnitDisk:%d\n",
				NetDiskPartitionInfo->NetDiskAddress.Node[0],
				NetDiskPartitionInfo->NetDiskAddress.Node[1],
				NetDiskPartitionInfo->NetDiskAddress.Node[2],
				NetDiskPartitionInfo->NetDiskAddress.Node[3],
				NetDiskPartitionInfo->NetDiskAddress.Node[4],
				NetDiskPartitionInfo->NetDiskAddress.Node[5],
				NTOHS(NetDiskPartitionInfo->NetDiskAddress.Port),
				(int)NetDiskPartitionInfo->UnitDiskNo
			));
	}
#endif

	return Found ;
}
Beispiel #6
0
NTSTATUS
ExInterlockedExtendZone(
    __inout PZONE_HEADER Zone,
    __inout PVOID Segment,
    __in ULONG SegmentSize,
    __inout PKSPIN_LOCK Lock
    )

/*++

Routine Description:

    This function extends a zone by adding another segment's worth of
    blocks to the zone.

Arguments:

    Zone - Supplies the address of a zone header to be extended.

    Segment - Supplies the address of a segment of storage.  The first
              ZONE_SEGMENT_HEADER-sized portion of the segment is used by the
              zone allocator.  The remainder of the segment is carved up
              into fixed-size (BlockSize) blocks and is added to the
              zone.  The address of the segment must be aligned on a 64-
              bit boundary.

    SegmentSize - Supplies the size in bytes of Segment.

    Lock - pointer to spinlock to use

Return Value:

    STATUS_UNSUCCESSFUL - BlockSize or Segment was not aligned on
                          64-bit boundaries, or BlockSize was larger than
                          the segment size.

    STATUS_SUCCESS - The zone was successfully extended.

--*/

{
    NTSTATUS Status;
    KIRQL OldIrql;

#ifdef NT_UP
    UNREFERENCED_PARAMETER (Lock);
#endif

    ExAcquireSpinLock( Lock, &OldIrql );

    Status = ExExtendZone( Zone, Segment, SegmentSize );

    ExReleaseSpinLock( Lock, OldIrql );

    return Status;
}
Beispiel #7
0
PLIST_ENTRY
IopErrorLogGetEntry(
    )

/*++

Routine Description:

    This routine gets the next entry from the head of the error log queue
    and returns it to the caller.

Arguments:

    None.

Return Value:

    The return value is a pointer to the packet removed, or NULL if there were
    no packets on the queue.

--*/

{
    KIRQL irql;
    PLIST_ENTRY listEntry;

    //
    // Remove the next packet from the queue, if there is one.
    //

    ExAcquireSpinLock( &IopErrorLogLock, &irql );
    if (IsListEmpty( &IopErrorLogListHead )) {

        //
        // Indicate no more work will be done in the context of this worker
        // thread and indicate to the caller that no packets were located.
        //

        IopErrorLogPortPending = FALSE;
        listEntry = (PLIST_ENTRY) NULL;
    } else {

        //
        // Remove the next packet from the head of the list.
        //

        listEntry = RemoveHeadList( &IopErrorLogListHead );
    }

    ExReleaseSpinLock( &IopErrorLogLock, irql );
    return listEntry;
}
Beispiel #8
0
VOID
FASTCALL
IovpTrackingDataAcquireLock(
    IN  PIOV_REQUEST_PACKET IovPacket OPTIONAL
    )
/*++

  Description:

    This routine is called by to acquire the IRPs tracking data lock.

    Incoming IRQL must be the same as the callers (IoCallDriver, IoCompleteRequest)
    We may be at DPC level when we return. Callers *must* follow up with
    IovpTrackingDataReleaseLock.

  Arguments:

    IovPacket        - Pointer to the IRP tracking data (or NULL, in which
                       case this routine does nothing).

  Return Value:

     None.
--*/
{
    KIRQL oldIrql ;
    PIOV_REQUEST_PACKET iovCurPacket;

    if (!IovPacket) {

        return ;
    }

    iovCurPacket = IovPacket;
    ASSERT(iovCurPacket->ReferenceCount != 0);
    while(1) {

        ExAcquireSpinLock( &iovCurPacket->IrpLock, &oldIrql );
        iovCurPacket->CallerIrql = oldIrql ;

        if (iovCurPacket == IovPacket->HeadPacket) {

            break;
        }

        iovCurPacket = CONTAINING_RECORD(
            iovCurPacket->SurrogateLink.Blink,
            IOV_REQUEST_PACKET,
            SurrogateLink
            );
    }
}
Beispiel #9
0
NTSTATUS
KeI386ReleaseGdtSelectors(
    OUT PUSHORT SelectorArray,
    IN USHORT NumberOfSelectors
    )

/*++

Routine Description:

    This function releases a set of GDT selectors for a device driver.
    Usually this function is called at device driver termination or
    deinstallation time.

Arguments:

    SelectorArray - Supplies a pointer to an array of USHORT selectors
                    to be freed.

    NumberOfSelectors - Specifies the number of selectors to be released.

Return Value:

    STATUS_SUCCESS - If the requested LID is released.

--*/
{
    PKFREE_GDT_ENTRY GdtEntry;
    KIRQL OldIrql;
    ULONG Gdt;

    ExAcquireSpinLock(&KiAbiosGdtLock, &OldIrql);

    //
    // The Free Gdt link list is maintained on Processor 0's GDT ONLY.
    // Because the 'selector' is an offset to the beginning of GDT and
    // it should be the same across all the processors.
    //

    KiNumberFreeSelectors = KiNumberFreeSelectors + NumberOfSelectors;
    Gdt = KiAbiosGdt[0];
    while (NumberOfSelectors != 0) {
        GdtEntry = (PKFREE_GDT_ENTRY)(Gdt + *SelectorArray++);
        GdtEntry->Flink = KiFreeGdtListHead;
        KiFreeGdtListHead = GdtEntry;
        NumberOfSelectors--;
    }
    ExReleaseSpinLock(&KiAbiosGdtLock, OldIrql);
    return STATUS_SUCCESS;
}
Beispiel #10
0
PDEVICE_OBJECT
IopGetDevicePDO(
    IN PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

    Call this routine to obtain the Base PDO for a device object

Arguments:

    DeviceObject - pointer to device object to get PDO for

ReturnValue:

    PDO if DeviceObject is attached to a PDO, otherwise NULL
    The returned PDO is reference-counted

--*/
{
    PDEVICE_OBJECT deviceBaseObject;
    KIRQL irql;

    ASSERT(DeviceObject);

    IopAcquireEnumerationLock(NULL);        // ensure we have acquired P&P locks

    ExAcquireSpinLock(&IopDatabaseLock,&irql);
    deviceBaseObject = IopGetDeviceAttachmentBase(DeviceObject);
    if ((deviceBaseObject->Flags & DO_BUS_ENUMERATED_DEVICE) != 0) {
        //
        // we have determined that this is attached to a PDO
        //
        ObReferenceObject( deviceBaseObject );

    } else {
        //
        // not a PDO
        //
        deviceBaseObject = NULL;
    }
    ExReleaseSpinLock(&IopDatabaseLock,irql);

    IopReleaseEnumerationLock(NULL);

    return deviceBaseObject;
}
Beispiel #11
0
static VOID
ExpDeleteTimer (
    IN PVOID Object
    )

/*++

Routine Description:

    This function is the delete routine for timer objects. Its function is
    to cancel the timer and free the spin lock associated with a timer.

Arguments:

    Object - Supplies a pointer to an executive timer object.

Return Value:

    None.

--*/

{
    PETIMER     ExTimer;
    KIRQL       OldIrql;

    ExTimer = (PETIMER) Object;

    //
    // Remove from wake list
    //

    if (ExTimer->WakeTimerListEntry.Flink) {
        ExAcquireSpinLock(&ExpWakeTimerListLock, &OldIrql);
        if (ExTimer->WakeTimerListEntry.Flink) {
            RemoveEntryList(&ExTimer->WakeTimerListEntry);
            ExTimer->WakeTimerListEntry.Flink = NULL;
        }
        ExReleaseSpinLock(&ExpWakeTimerListLock, OldIrql);
    }

    //
    // Cancel the timer and free the spin lock associated with the timer.
    //

    KeCancelTimer(&ExTimer->KeTimer);
    return;
}
Beispiel #12
0
VOID
ExDeletePagedLookasideList (
    IN PPAGED_LOOKASIDE_LIST Lookaside
    )

/*++

Routine Description:

    This function removes a paged lookaside structure from the system paged
    lookaside list and frees any entries specified by the lookaside structure.

Arguments:

    Lookaside - Supplies a pointer to a paged lookaside list structure.

Return Value:

    None.

--*/

{

    PVOID Entry;
    KIRQL OldIrql;

    //
    // Acquire the paged system lookaside list lock and remove the
    // specified lookaside list structure from the list.
    //

    ExAcquireSpinLock(&ExPagedLookasideLock, &OldIrql);
    RemoveEntryList(&Lookaside->L.ListEntry);
    ExReleaseSpinLock(&ExPagedLookasideLock, OldIrql);

    //
    // Remove all pool entries from the specified lookaside structure
    // and free them.
    //

    Lookaside->L.Allocate = ExpDummyAllocate;
    while ((Entry = ExAllocateFromPagedLookasideList(Lookaside)) != NULL) {
        (Lookaside->L.Free)(Entry);
    }

    return;
}
Beispiel #13
0
VOID
FASTCALL
IovpTrackingDataDereference(
    IN PIOV_REQUEST_PACKET IovPacket,
    IN IOV_REFERENCE_TYPE  IovRefType
    )
{
    KIRQL oldIrql;

    ASSERT_SPINLOCK_HELD(&IovPacket->IrpLock);
    ASSERT(IovPacket->ReferenceCount > 0);

    TRACKIRP_DBGPRINT((
        "  VRP DEREF(%x) %x--\n",
        IovPacket,
        IovPacket->ReferenceCount
        ), 3) ;

    if (IovRefType == IOVREFTYPE_POINTER) {

        ASSERT(IovPacket->PointerCount > 0);

        TRACKIRP_DBGPRINT((
            "  VRP DEREF2(%x) %x--\n",
            IovPacket,
            IovPacket->PointerCount
            ), 3) ;

        IovPacket->PointerCount--;

        if (IovPacket->PointerCount == 0) {

            ExAcquireSpinLock( &IovpIrpHashLock, &oldIrql );

            IovPacket->TrackedIrp->Flags &=~ IRPFLAG_EXAMINE_MASK;
            IovPacket->TrackedIrp = NULL;

            ExReleaseSpinLock( &IovpIrpHashLock, oldIrql );
        }
    }
    InterlockedDecrement(&IovPacket->ReferenceCount);

    ASSERT(IovPacket->ReferenceCount >= IovPacket->PointerCount);
}
Beispiel #14
0
NTSTATUS
ExDeleteResource (
    IN PNTDDK_ERESOURCE Resource
    )

/*++

Routine Description:

    This routine deletes (i.e., uninitializes) the input resource variable


Arguments:

    Resource - Supplies the resource variable being deleted

Return Value:

    None

--*/

{
    ASSERTMSG("Routine cannot be called at DPC ", !KeIsExecutingDpc() );

    ASSERT_RESOURCE( Resource );
    ASSERT( !IsExclusiveWaiting(Resource) );


    if (Resource >= (PNTDDK_ERESOURCE)MM_USER_PROBE_ADDRESS) {
        KIRQL OldIrql;

        ExAcquireSpinLock( &ExpResourceSpinLock, &OldIrql );
        RemoveEntryList( &Resource->SystemResourcesList );
        ExReleaseSpinLock( &ExpResourceSpinLock, OldIrql );

    }

    return STATUS_SUCCESS;
}
Beispiel #15
0
VOID
IopErrorLogRequeueEntry(
    IN PLIST_ENTRY ListEntry
    )

/*++

Routine Description:

    This routine puts an error packet back at the head of the error log queue
    since it cannot be processed at the moment.

Arguments:

    ListEntry - Supplies a pointer to the packet to be placed back onto the
        error log queue.

Return Value:

    None.

--*/

{
    KIRQL irql;

    //
    // Simply insert the packet back onto the head of the queue, indicate that
    // the error log port is not connected, queue a request to check again
    // soon, and return.
    //

    ExAcquireSpinLock( &IopErrorLogLock, &irql );
    InsertHeadList( &IopErrorLogListHead, ListEntry );
    ErrorLogPortConnected = FALSE;
    ExReleaseSpinLock( &IopErrorLogLock, irql );
}
Beispiel #16
0
NTSTATUS
KeI386GetLid(
    IN USHORT DeviceId,
    IN USHORT RelativeLid,
    IN BOOLEAN SharedLid,
    IN PDRIVER_OBJECT DriverObject,
    OUT PUSHORT LogicalId
    )

/*++

Routine Description:

    This function searches Device Blocks and Common Data Area for the
    Logical Id matching the specified Device Id.

    N.B. To speed the search, this routine ASSUMES that
    the LIDs with the same Device ID always appear consecutively in the
    Common Data Area.  IBM ABIOS doc does not explicitly specify this.
    But from the way ABIOS initializes Device Block and Function Transfer
    Table, I think the assumption is true.

Arguments:

    DeviceId - Desired Device Id.

    RelativeLid - Specifies the Nth logical Id for this device Id.  A value
                  of 0 indicates the first available Lid.

    SharedLid - A boolean value indicates if it is a shared or exclusively
                owned logical Id.

    DriverObject - Supplies a 32-bit flat pointer of the requesting device
                driver's driver object.  The DriverObject is used to establish
                the ownership of the desired LID.

    LogicalId - A pointer to a variable which will receive the Lid.

Return Value:

    STATUS_SUCCESS - If the requested LID is available.

    STATUS_ABIOS_NOT_PRESENT - If there is no ABIOS support in the system.

    STATUS_ABIOS_LID_NOT_EXIST - If the specified LID does not exist.

    STATUS_ABIOS_LID_ALREADY_OWNED - If the caller requests an exclusively
                                     owned LID.

--*/

{
    PKDB_FTT_SECTION CdaPointer;
    PKDEVICE_BLOCK DeviceBlock;
    USHORT Lid, RelativeLidCount = 1;
    ULONG Owner;
    USHORT Increment;
    KIRQL OldIrql;
    NTSTATUS Status;

    if (!KiAbiosPresent) {
        return STATUS_ABIOS_NOT_PRESENT;
    }

    if (SharedLid) {
        Owner = LID_NO_SPECIFIC_OWNER;
        Increment = 1;
    } else {
        Owner = (ULONG)DriverObject;
        Increment = 0;
    }

    //
    // If the Logical Id Table hasn't been created yet, create it now.
    //
    if (KiLogicalIdTable==NULL) {
        KiLogicalIdTable = ExAllocatePoolWithTag(NonPagedPool,
                                          NUMBER_LID_TABLE_ENTRIES *
                                          sizeof(KLID_TABLE_ENTRY),
                                          '  eK');
        if (KiLogicalIdTable == NULL) {
            return(STATUS_NO_MEMORY);
        }
        RtlZeroMemory(KiLogicalIdTable, NUMBER_LID_TABLE_ENTRIES*sizeof(KLID_TABLE_ENTRY));
    }

    //
    // For each Lid defined in Common Data Area, we check if it has non
    // empty device block and function transfer table.  If yes, we proceed
    // to check the device id.  Otherwise, we skip the Lid.
    //

    CdaPointer = (PKDB_FTT_SECTION)KiCommonDataArea + 2;
    Status = STATUS_ABIOS_LID_NOT_EXIST;

    ExAcquireSpinLock(&KiAbiosLidTableLock, &OldIrql);

    for (Lid = 2; Lid < KiCommonDataArea->NumberLids; Lid++) {
        if (CdaPointer->DeviceBlock.Selector != 0 &&
            CdaPointer->FunctionTransferTable.Selector != 0) {

            DeviceBlock = (PKDEVICE_BLOCK)(KiI386SelectorBase(
                                               CdaPointer->DeviceBlock.Selector)
                                           + (CdaPointer->DeviceBlock.Offset));
            if (DeviceBlock->DeviceId == DeviceId) {
                if (RelativeLid == RelativeLidCount || RelativeLid == 0) {
                    if (KiLogicalIdTable[Lid].Owner == 0L) {
                        KiLogicalIdTable[Lid].Owner = Owner;
                        KiLogicalIdTable[Lid].OwnerCount += Increment;
                        *LogicalId = Lid;
                        Status = STATUS_SUCCESS;
                    } else if (KiLogicalIdTable[Lid].Owner == LID_NO_SPECIFIC_OWNER) {
                        if (SharedLid) {
                            *LogicalId = Lid;
                            KiLogicalIdTable[Lid].OwnerCount += Increment;
                            Status = STATUS_SUCCESS;
                        } else {
                            Status = STATUS_ABIOS_LID_ALREADY_OWNED;
                        }
                    } else if (KiLogicalIdTable[Lid].Owner == (ULONG)DriverObject) {
                        *LogicalId = Lid;
                        Status = STATUS_SUCCESS;
                    } else if (RelativeLid != 0) {
                        Status = STATUS_ABIOS_LID_ALREADY_OWNED;
                    }
                    break;
                } else {
                    RelativeLidCount++;
                }
            }
        }
        CdaPointer++;
    }

    ExReleaseSpinLock(&KiAbiosLidTableLock, OldIrql);
    return Status;
}
Beispiel #17
0
NTSTATUS
File_UpdateEntireFileByFileObject(
	__in PFLT_CALLBACK_DATA Data,
	__in PFLT_RELATED_OBJECTS FltObjects,
	__in PFILE_OBJECT FileObject, 
	__in PSTREAM_CONTEXT pStreamCtx,
	__in PVOLUME_CONTEXT pVolCtx
	)
{
	NTSTATUS status = STATUS_SUCCESS ;
	PUCHAR Buffer = NULL ;
	LARGE_INTEGER ReadWriteOffset = {0} ;
	BOOLEAN EndOfFile = FALSE;
	ULONG uReadBytes = 0 ;
	ULONG uWriteBytes = 0 ;
	ULONG uAllocateBufferSize = 1024*64 ; 
	ULONG uReadWriteLength = 0 ;
	ULONG uOffset = 0 ;
	LARGE_INTEGER FileSize = {0} ;
	PFILE_FLAG psFileFlag = NULL ;
	KIRQL OldIrql ;

	try{

		//判断分配空间长度是否SectorSize对齐
		if ((uAllocateBufferSize % pVolCtx->SectorSize) != 0)
		{//由于SectorSize目前为512bytes,故暂时先返回失败,以后可以对AllocateBufferSize进行调整
			status = ERR_CORE_LENGTH_NOT_ALIGNED ;
			__leave ;
		}

		Buffer = FltAllocatePoolAlignedWithTag(FltObjects->Instance,PagedPool, uAllocateBufferSize, FILEFLAG_POOL_TAG);
		if (!Buffer)
		{
			status = STATUS_INSUFFICIENT_RESOURCES;
			__leave ;
		}

             //allocate local file flag buffer
		psFileFlag = (PFILE_FLAG)ExAllocatePoolWithTag(NonPagedPool, FILE_FLAG_LENGTH, FILEFLAG_POOL_TAG) ;
		if (NULL == psFileFlag)
		{
			status = STATUS_INSUFFICIENT_RESOURCES ;
			__leave ;
		}
		RtlCopyMemory(psFileFlag, g_psFileFlag, FILE_FLAG_LENGTH) ; //实际上这里应该是当前文件自身的flag

        //set current file size into file flag buffer
        File_GetFileSize(Data, FltObjects, &FileSize) ;
		psFileFlag->FileValidLength= FileSize.QuadPart ;

		//calculate padded file size
		if (FileSize.QuadPart % SECTOR_SIZE)
		{//file size is not multiply of sector size
			FileSize.QuadPart = FileSize.QuadPart + (SECTOR_SIZE - FileSize.QuadPart % SECTOR_SIZE) + FILE_FLAG_LENGTH ;
		}
		else
		{//file size is multiply of sector size
			FileSize.QuadPart += FILE_FLAG_LENGTH ;
		}
		RtlCopyMemory(psFileFlag->FileKeyHash, pStreamCtx->szKeyHash, HASH_SIZE) ;
		

		while (TRUE)
		{
			status = File_ReadWriteFile(IRP_MJ_READ, 
										FltObjects->Instance, 
										FileObject, 
										&ReadWriteOffset,
										uAllocateBufferSize, 
										Buffer, 
										&uReadBytes,
										FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ;
			if (!NT_SUCCESS(status))
				break;

			if (0 == uReadBytes)
				break;

			if (KeGetCurrentIrql() > PASSIVE_LEVEL)
				ExAcquireSpinLock(&pVolCtx->FsCryptSpinLock, &OldIrql);
			else
				ExAcquireFastMutex(&pVolCtx->FsCtxTableMutex) ;
			///if (data_crypt(pVolCtx->aes_ctr_ctx, Buffer, uOffset, uReadBytes))
			///{
			///	if (KeGetCurrentIrql() > PASSIVE_LEVEL)
			///		ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ;
			///	else
			///		ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ;
			///	break ;
			///}
			if (KeGetCurrentIrql() > PASSIVE_LEVEL)
				ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ;
			else
				ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ;

			if (uReadBytes < uAllocateBufferSize)
				EndOfFile = TRUE;

			status = File_ReadWriteFile(IRP_MJ_WRITE, 
										FltObjects->Instance, 
										FileObject, 
										&ReadWriteOffset,
										uReadBytes, 
										Buffer, 
										&uWriteBytes,
										FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ;
			if (!NT_SUCCESS(status))
				break;

			if (EndOfFile)
				break;
			
			uOffset += uAllocateBufferSize ;
			ReadWriteOffset.QuadPart += uAllocateBufferSize ;
			RtlZeroMemory(Buffer, uAllocateBufferSize) ;
		}

		// write file flag
		ReadWriteOffset.QuadPart = FileSize.QuadPart - FILE_FLAG_LENGTH ;
		File_ReadWriteFile(IRP_MJ_WRITE, 
						   FltObjects->Instance, 
						   FileObject, 
						   &ReadWriteOffset, 
						   FILE_FLAG_LENGTH, 
						   psFileFlag, 
						   &uWriteBytes,
						   FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ;
		
	}
	finally{

		if (Buffer)
		{
			FltFreePoolAlignedWithTag(FltObjects->Instance, Buffer, FILEFLAG_POOL_TAG);
			Buffer = NULL ;
		}

		if (psFileFlag)
		{
			ExFreePoolWithTag(psFileFlag, FILEFLAG_POOL_TAG) ;
			psFileFlag = NULL ;
		}
	}

	return status;
}
Beispiel #18
0
BOOLEAN
KeRemoveEntryDeviceQueue (
    IN PKDEVICE_QUEUE DeviceQueue,
    IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
    )

/*++

Routine Description:

    This function removes a specified entry from the the specified device
    queue. If the device queue entry is not in the device queue, then no
    operation is performed. Otherwise the specified device queue entry is
    removed from the device queue and its inserted status is set to FALSE.

Arguments:

    DeviceQueue - Supplies a pointer to a control object of type device queue.

    DeviceQueueEntry - Supplies a pointer to a device queue entry which is to
        be removed from its device queue.

Return Value:

    A value of TRUE is returned if the device queue entry is removed from its
    device queue. Otherwise a value of FALSE is returned.

--*/

{

    KIRQL OldIrql;
    BOOLEAN Removed;

    ASSERT_DEVICE_QUEUE(DeviceQueue);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock specified device queue.
    //

    ExAcquireSpinLock(&DeviceQueue->Lock, &OldIrql);

    //
    // If the device queue entry is not in a device queue, then no operation
    // is performed. Otherwise remove the specified device queue entry from its
    // device queue.
    //

    Removed = DeviceQueueEntry->Inserted;
    if (Removed == TRUE) {
        DeviceQueueEntry->Inserted = FALSE;
        RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
    }

    //
    // Unlock specified device queue, lower IRQL to its previous level, and
    // return whether the device queue entry was removed from its queue.
    //

    ExReleaseSpinLock(&DeviceQueue->Lock, OldIrql);
    return Removed;
}
Beispiel #19
0
NTSYSAPI
NTSTATUS
NTAPI
IoAcquireRemoveLockEx(
    IN PIO_REMOVE_LOCK PublicLock,
    IN OPTIONAL PVOID   Tag,
    IN PCSTR            File,
    IN ULONG            Line,
    IN ULONG            RemlockSize // are we checked or free
    )

/*++

Routine Description:

    This routine is called to acquire the remove lock for a device object.
    While the lock is held, the caller can assume that no pending pnp REMOVE
    requests will be completed.

    The lock should be acquired immediately upon entering a dispatch routine.
    It should also be acquired before creating any new reference to the
    device object if there's a chance of releasing the reference before the
    new one is done.

Arguments:

    RemoveLock - A pointer to an initialized REMOVE_LOCK structure.

    Tag - Used for tracking lock allocation and release.  If an irp is
          specified when acquiring the lock then the same Tag must be
          used to release the lock before the Tag is completed.

    File - set to __FILE__ as the location in the code where the lock was taken.

    Line - set to __LINE__.

Return Value:

    Returns whether or not the remove lock was obtained.
    If successful the caller should continue with work calling
    IoReleaseRemoveLock when finished.

    If not successful the lock was not obtained.  The caller should abort the
    work but not call IoReleaseRemoveLock.

--*/

{
    PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock;
    LONG        lockValue;
    NTSTATUS    status;

    PIO_REMOVE_LOCK_TRACKING_BLOCK trackingBlock;

    //
    // Grab the remove lock
    //

    lockValue = InterlockedIncrement(&Lock->Common.IoCount);

    ASSERTMSG("IoAcquireRemoveLock - lock value was negative : ",
              (lockValue > 0));

    if (! Lock->Common.Removed) {

        switch (RemlockSize) {
        case CHECKEDSIZE:

            ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
                      ((0 == Lock->Dbg.HighWatermark) ||
                       (lockValue <= Lock->Dbg.HighWatermark)));

            trackingBlock = ExAllocatePoolWithTag(
                                NonPagedPool,
                                sizeof(IO_REMOVE_LOCK_TRACKING_BLOCK),
                                Lock->Dbg.AllocateTag);

            if (NULL == trackingBlock) {

                // ASSERTMSG ("insufficient resources", FALSE);
                InterlockedIncrement (& Lock->Dbg.LowMemoryCount);
                //
                // Let the acquire go through but without adding the
                // tracking block.
                // When we are later releasing the lock, but the tracking
                // block does not exist, deduct from this value to see if the
                // release was still valuable.
                //

            } else {

                KIRQL oldIrql;

                RtlZeroMemory (trackingBlock,
                               sizeof (IO_REMOVE_LOCK_TRACKING_BLOCK));

                trackingBlock->Tag = Tag;
                trackingBlock->File = File;
                trackingBlock->Line = Line;

                KeQueryTickCount(&trackingBlock->TimeLocked);

                ExAcquireSpinLock (&Lock->Dbg.Spin, &oldIrql);
                trackingBlock->Link = Lock->Dbg.Blocks;
                Lock->Dbg.Blocks = trackingBlock;
                ExReleaseSpinLock(&Lock->Dbg.Spin, oldIrql);
            }
            break;

        case FREESIZE:
            break;

        default:
            break;
        }

        status = STATUS_SUCCESS;

    } else {

        if (0 == InterlockedDecrement (&Lock->Common.IoCount)) {
            KeSetEvent (&Lock->Common.RemoveEvent, 0, FALSE);
        }
        status = STATUS_DELETE_PENDING;
    }

    return status;
}
Beispiel #20
0
VOID
ExpTimerApcRoutine (
    IN PKAPC Apc,
    IN PKNORMAL_ROUTINE *NormalRoutine,
    IN PVOID *NormalContext,
    IN PVOID *SystemArgument1,
    IN PVOID *SystemArgument2
    )

/*++

Routine Description:

    This function is the special APC routine that is called to remove
    a timer from the current thread's active timer list.

Arguments:

    Apc - Supplies a pointer to the APC object used to invoke this routine.

    NormalRoutine - Supplies a pointer to a pointer to the normal routine
        function that was specified when the APC was initialized.

    NormalContext - Supplies a pointer to a pointer to an arbitrary data
        structure that was specified when the APC was initialized.

    SystemArgument1, SystemArgument2 - Supplies a set of two pointers to
        two arguments that contain untyped data.

Return Value:

    None.

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    KIRQL OldIrql1;

    //
    // Get address of executive timer object and the current thread object.
    //

    ExThread = PsGetCurrentThread();
    ExTimer = CONTAINING_RECORD(Apc, ETIMER, TimerApc);

    //
    // If the timer is still in the current thread's active timer list, then
    // remove it if it is not a periodic timer and set APC associated FALSE.
    // It is possible for the timer not to be in the current thread's active
    // timer list since the APC could have been delivered, and then another
    // thread could have set the timer again with another APC. This would
    // have caused the timer to be removed from the current thread's active
    // timer list.
    //
    // N. B. The spin locks for the timer and the active timer list must be
    //  acquired in the order: 1) timer lock, 2) thread list lock.
    //

    Dereference = FALSE;
    ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
    ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
    if ((ExTimer->ApcAssociated) && (&ExThread->Tcb == ExTimer->TimerApc.Thread)) {
        if (ExTimer->Period == 0) {
            RemoveEntryList(&ExTimer->ActiveTimerListEntry);
            ExTimer->ApcAssociated = FALSE;
            Dereference = TRUE;
        }

    } else {
        *NormalRoutine = (PKNORMAL_ROUTINE)NULL;
    }

    ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
    ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
    if (Dereference) {
        ObDereferenceObject((PVOID)ExTimer);
    }

    return;
}
Beispiel #21
0
VOID
ExTimerRundown (
    )

/*++

Routine Description:

    This function is called when a thread is about to be terminated to
    process the active timer list. It is assumed that APC's have been
    disabled for the subject thread, thus this code cannot be interrupted
    to execute an APC for the current thread.

Arguments:

    None.

Return Value:

    None.

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql1;

    //
    // Process each entry in the active timer list.
    //

    ExThread = PsGetCurrentThread();
    ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
    NextEntry = ExThread->ActiveTimerListHead.Flink;
    while (NextEntry != &ExThread->ActiveTimerListHead) {
        ExTimer = CONTAINING_RECORD(NextEntry, ETIMER, ActiveTimerListEntry);

        //
        // Increment the reference count on the object so that it cannot be
        // deleted, and then drop the active timer list lock.
        //
        // N. B. The object reference cannot fail and will acquire no mutexes.
        //

        ObReferenceObject(ExTimer);
        ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);

        //
        // Acquire the timer spin lock and reacquire the active time list spin
        // lock. If the timer is still in the current thread's active timer
        // list, then cancel the timer, remove the timer's DPC from the DPC
        // queue, remove the timer's APC from the APC queue, remove the timer
        // from the thread's active timer list, and set the associate APC
        // flag FALSE.
        //
        // N. B. The spin locks for the timer and the active timer list must be
        //  acquired in the order: 1) timer lock, 2) thread list lock.
        //

        ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
        ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
        if ((ExTimer->ApcAssociated) && (&ExThread->Tcb == ExTimer->TimerApc.Thread)) {
            RemoveEntryList(&ExTimer->ActiveTimerListEntry);
            ExTimer->ApcAssociated = FALSE;
            KeCancelTimer(&ExTimer->KeTimer);
            KeRemoveQueueDpc(&ExTimer->TimerDpc);
            KeRemoveQueueApc(&ExTimer->TimerApc);
            Dereference = TRUE;

        } else {
            Dereference = FALSE;
        }

        ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
        ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
        if (Dereference) {
            ObDereferenceObject((PVOID)ExTimer);
        }

        ObDereferenceObject((PVOID)ExTimer);

        //
        // Raise IRQL to DISPATCH_LEVEL and reacquire active timer list
        // spin lock.
        //

        ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
        NextEntry = ExThread->ActiveTimerListHead.Flink;
    }

    ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);
    return;
}
Beispiel #22
0
VOID
ExpTimerDpcRoutine (
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This function is the DPC routine that is called when a timer expires that
    has an associated APC routine. Its function is to insert the associated
    APC into the target thread's APC queue.

Arguments:

    Dpc - Supplies a pointer to a control object of type DPC.

    DeferredContext - Supplies a pointer to the executive timer that contains
        the DPC that caused this routine to be executed.

    SystemArgument1, SystemArgument2 - Supplies values that are not used by
        this routine.

Return Value:

    None.

--*/

{

    PETIMER ExTimer;
    PKTIMER KeTimer;
    KIRQL OldIrql;

    //
    // Get address of executive and kernel timer objects.
    //

    ExTimer = (PETIMER)DeferredContext;
    KeTimer = &ExTimer->KeTimer;

    //
    // If there is still an APC associated with the timer, then insert the APC
    // in target thread's APC queue. It is possible that the timer does not
    // have an associated APC. This can happen when the timer is set to expire
    // by a thread running on another processor just after the DPC has been
    // removed from the DPC queue, but before it has acquired the timer related
    // spin lock.
    //

    ExAcquireSpinLock(&ExTimer->Lock, &OldIrql);
    if (ExTimer->ApcAssociated) {
        KeInsertQueueApc(&ExTimer->TimerApc,
                         SystemArgument1,
                         SystemArgument2,
                         TIMER_APC_INCREMENT);
    }

    ExReleaseSpinLock(&ExTimer->Lock, OldIrql);
    return;
}
Beispiel #23
0
VOID
ExGetNextWakeTime (
    OUT PULONGLONG      DueTime,
    OUT PTIME_FIELDS    TimeFields,
    OUT PVOID           *TimerObject
    )
{
    PLIST_ENTRY     Link;
    PETIMER         ExTimer;
    PETIMER         BestTimer;
    KIRQL           OldIrql;
    ULONGLONG       TimerDueTime;
    ULONGLONG       BestDueTime;
    ULONGLONG       InterruptTime;
    LARGE_INTEGER   SystemTime;
    LARGE_INTEGER   CmosTime;

    ExAcquireSpinLock(&ExpWakeTimerListLock, &OldIrql);
    BestDueTime = 0;
    BestTimer = NULL;
    Link = ExpWakeTimerList.Flink;
    while (Link != &ExpWakeTimerList) {
        ExTimer = CONTAINING_RECORD(Link, ETIMER, WakeTimerListEntry);
        Link = Link->Flink;

        if (ExTimer->WakeTimer) {

            TimerDueTime = KeQueryTimerDueTime(&ExTimer->KeTimer);
            TimerDueTime = 0 - TimerDueTime;

            //
            // Is this timers due time closer?
            //

            if (TimerDueTime > BestDueTime) {
                BestDueTime = TimerDueTime;
                BestTimer = ExTimer;
            }

        } else {

            //
            // Timer is not an active wake timer, remove it
            //

            RemoveEntryList(&ExTimer->WakeTimerListEntry);
            ExTimer->WakeTimerListEntry.Flink = NULL;
        }
    }

    ExReleaseSpinLock(&ExpWakeTimerListLock, OldIrql);

    if (BestDueTime) {
        //
        // Convert time to timefields
        //

        KeQuerySystemTime (&SystemTime);
        InterruptTime = KeQueryInterruptTime ();
        BestDueTime = 0 - BestDueTime;

        SystemTime.QuadPart += BestDueTime - InterruptTime;

        //
        // Many system alarms are only good to 1 second resolution.
        // Add one sceond to the target time so that the timer is really
        // elasped if this is the wake event.
        //

        SystemTime.QuadPart += 10000000;

        ExSystemTimeToLocalTime(&SystemTime,&CmosTime);
        RtlTimeToTimeFields(&CmosTime, TimeFields);
    }

    *DueTime = BestDueTime;
    *TimerObject = BestTimer;
}
Beispiel #24
0
NTSTATUS
TdiHandleSerializedRequest (
	PVOID		RequestInfo,
	UINT		RequestType
)

/*++

Routine Description:

	Called when we want to process a request relating to one of the
	lists we manage. We look to see if we are currently processing such
	a request - if we are, we queue this for later. Otherwise we'll
	remember that we are doing this, and we'll process this request.
	When we're done we'll look to see if any more came in while we were
	busy.

Arguments:

	RequestInfo			- Reqeust specific information.
	RequestType			- The type of the request.

Return Value:

	Request completion status.


--*/

{
	KIRQL					OldIrql;
	PLIST_ENTRY				List;
	PLIST_ENTRY				ClientList;
	PLIST_ENTRY				ProviderList;
	PLIST_ENTRY				RequestList;
	PBOOLEAN				SerializeFlag;
	PETHREAD				*RequestThread;
	PTDI_SERIALIZED_REQUEST	Request;
	PKEVENT					BlockedEvent = NULL;
	PTDI_NOTIFY_COMMON		NotifyElement;
	PTDI_PROVIDER_RESOURCE	ProviderElement;

	ExAcquireSpinLock(
					&TDIListLock,
					&OldIrql
					);

	if (RequestType <= TDI_MAX_BIND_REQUEST) {
		ClientList = &BindClientList;
		ProviderList = &BindProviderList;
		RequestList = &BindRequestList;
		SerializeFlag = &BindRequestInProgress;
		RequestThread = &BindRequestThread;
	} else {
		ClientList = &NetAddressClientList;
		ProviderList = &NetAddressProviderList;
		RequestList = &NetAddressRequestList;
		SerializeFlag = &AddressRequestInProgress;
		RequestThread = &AddressRequestThread;
	}

	// If we're not already here, handle it right away.

	if (!(*SerializeFlag)) {

		*SerializeFlag = TRUE;

		// Save the identity of the thread we're doing this in in case someone
		// tries to delete a client, which needs to block. In that case we'll
		// check to make sure it's not being done in the same thread we're using
		// to prevent deadlock.

		*RequestThread = PsGetCurrentThread();

		for (;;) {

			// We're done with the lock for now, so free it.

			ExReleaseSpinLock(
							&TDIListLock,
							OldIrql
							);

			// Figure out the type of request we have here.

			switch (RequestType) {
			case TDI_REGISTER_BIND_NOTIFY:
			case TDI_REGISTER_ADDRESS_NOTIFY:
				// This is a client register bind or address handler request.

				// Insert this one into the registered client list.
				NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
				InsertTailList(
							ClientList,
							&NotifyElement->Linkage,
							);

				// Call TdiNotifyNewClient to notify this new client of all
				// all existing providers.

				TdiNotifyNewClient(
							ProviderList,
							RequestInfo
							);

				break;

			case TDI_DEREGISTER_BIND_NOTIFY:
			case TDI_DEREGISTER_ADDRESS_NOTIFY:

				// This is a client deregister request. Pull him from the
				// client list, free it, and we're done.

				NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
				RemoveEntryList(&NotifyElement->Linkage);

				ExFreePool(NotifyElement);

				break;

			case TDI_REGISTER_DEVICE:
			case TDI_REGISTER_ADDRESS:

				// A provider is registering a device or address. Add him to
				// the appropriate provider list, and then notify all
				// existing clients of the new device.

				ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;

				InsertTailList(
							ProviderList,
							&ProviderElement->Common.Linkage
							);

				// Call TdiNotifyClientList to do the hard work.

				TdiNotifyClientList(
							ClientList,
							RequestInfo,
							TRUE
							);
				break;

			case TDI_DEREGISTER_DEVICE:
			case TDI_DEREGISTER_ADDRESS:

				// A provider device or address is deregistering. Pull the
				// resource from the provider list, and notify clients that
				// he's gone.

				ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;
				RemoveEntryList(&ProviderElement->Common.Linkage);

				TdiNotifyClientList(
							ClientList,
							RequestInfo,
							FALSE
							);

				// Free the tracking structure we had.

				if (RequestType == TDI_DEREGISTER_DEVICE) {
					ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
				}
				ExFreePool(ProviderElement);

				break;
			default:
				break;
			}

			// If there was an event specified with this request, signal
			// it now. This should only be a client deregister request, which
			// needs to block until it's completed.

			if (BlockedEvent != NULL) {
                KeSetEvent(BlockedEvent, 0, FALSE);
			}

			// Get the lock, and see if more requests have come in while
			// we've been busy. If they have, we'll service them now, otherwise
			// we'll clear the in progress flag and exit.

			ExAcquireSpinLock(
							&TDIListLock,
							&OldIrql
							);

			if (!IsListEmpty(RequestList)) {

				// The request list isn't empty. Pull the next one from
				// the list and process it.

				List = RemoveHeadList(RequestList);

				Request = CONTAINING_RECORD(List, TDI_SERIALIZED_REQUEST, Linkage);

				RequestInfo = Request->Element;
				RequestType = Request->Type;
				BlockedEvent = Request->Event;

				ExFreePool(Request);

			} else {

				// The request list is empty. Clear the flag and we're done.

				*SerializeFlag = FALSE;

				ExReleaseSpinLock(
								&TDIListLock,
								OldIrql
								);
				break;
			}
		}

		return STATUS_SUCCESS;
	} else {
Beispiel #25
0
NTSTATUS
KeI386FlatToGdtSelector(
    IN ULONG SelectorBase,
    IN USHORT Length,
    IN USHORT Selector
    )

/*++

Routine Description:

    This function converts a 32-bit flat address to a GDT selector-offset
    pair.  The segment set up is always 16-bit ring 0 data segment.

Arguments:

    SelectorBase - Supplies 32 bit flat address to be set as the base address
                   of the desired selector.

    Length - Supplies the Length of the segment.  The Length is a 16 bit value
             and zero means 64KB.

    Selector - Supplies the selector to be set up.

Return Value:

    STATUS_SUCCESS - If the requested LID is released.

    STATUS_ABIOS_NOT_PRESENT - If there is no ABIOS support in the system.

    STATUS_ABIOS_INVALID_SELECTOR - If the selector supplied is invalid.


--*/

{
    PKGDTENTRY GdtEntry, GdtEntry1;
    KIRQL OldIrql;
    ULONG i;

    if (!KiAbiosPresent) {
        return STATUS_ABIOS_NOT_PRESENT;
    }
    if (Selector < RESERVED_GDT_ENTRIES * sizeof(KGDTENTRY)) {
        return STATUS_ABIOS_INVALID_SELECTOR;
    } else {
        ExAcquireSpinLock(&KiAbiosGdtLock, &OldIrql);
        GdtEntry = (PKGDTENTRY)(KiAbiosGdt[0] + Selector);
        GdtEntry->LimitLow = (USHORT)(Length - 1);
        GdtEntry->BaseLow = LOWWORD(SelectorBase);
        GdtEntry->HighWord.Bytes.BaseMid = LOWBYTE(HIGHWORD(SelectorBase));
        GdtEntry->HighWord.Bytes.BaseHi = HIGHBYTE(HIGHWORD(SelectorBase));
        GdtEntry->HighWord.Bits.Pres = 1;
        GdtEntry->HighWord.Bits.Type = TYPE_DATA;
        GdtEntry->HighWord.Bits.Dpl = DPL_SYSTEM;
        for (i = 1; i < (ULONG)KeNumberProcessors; i++) {
            GdtEntry1 = (PKGDTENTRY)(KiAbiosGdt[i] + Selector);
            *GdtEntry1 = *GdtEntry;
        }
        ExReleaseSpinLock(&KiAbiosGdtLock, OldIrql);
        return STATUS_SUCCESS;
    }
}
Beispiel #26
0
NTSTATUS
NtSetTimer (
    IN HANDLE TimerHandle,
    IN PLARGE_INTEGER DueTime,
    IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
    IN PVOID TimerContext OPTIONAL,
    IN BOOLEAN WakeTimer,
    IN LONG Period OPTIONAL,
    OUT PBOOLEAN PreviousState OPTIONAL
    )

/*++

Routine Description:

    This function sets an timer object to a Not-Signaled state and sets the timer
    to expire at the specified time.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    DueTime - Supplies a pointer to absolute of relative time at which the
        timer is to expire.

    TimerApcRoutine - Supplies an optional pointer to a function which is to
        be executed when the timer expires. If this parameter is not specified,
        then the TimerContext parameter is ignored.

    TimerContext - Supplies an optional pointer to an arbitrary data structure
        that will be passed to the function specified by the TimerApcRoutine
        parameter. This parameter is ignored if the TimerApcRoutine parameter
        is not specified.

    WakeTimer - Supplies a boolean value that specifies whether the timer
        wakes computer operation if sleeping

    Period - Supplies an optional repetitive period for the timer.

    PreviousState - Supplies an optional pointer to a variable that will
        receive the previous state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN AssociatedApc;
    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    LARGE_INTEGER ExpirationTime;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the due time and previous state
    // address if specified, reference the timer object, and set the timer
    // object. If the probe fails, then return the exception code as the
    // service status. Otherwise return the status value returned by the
    // reference object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe previous state address
        // if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            if (ARGUMENT_PRESENT(PreviousState)) {
                ProbeForWriteBoolean(PreviousState);
            }

            ProbeForRead(DueTime, sizeof(LARGE_INTEGER), sizeof(ULONG));
        }

        //
        // Check argument validity.
        //

        if (Period < 0) {
            return STATUS_INVALID_PARAMETER_6;
        }

        //
        // Capture the expiration time.
        //

        ExpirationTime = *DueTime;

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_MODIFY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If this WakeTimer flag is set, return the appropiate informational
        // success status code.
        //

        if (NT_SUCCESS(Status) && WakeTimer && !PoWakeTimerSupported()) {
            Status = STATUS_TIMER_RESUME_IGNORED;
        }

        //
        // If the reference was successful, then cancel the timer object, set
        // the timer object, dereference time object, and write the previous
        // state value if specified. If the write of the previous state value
        // fails, then do not report an error. When the caller attempts to
        // access the previous state value, an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);

            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            //
            // Read the current state of the timer.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);

            //
            // If this is a wake timer ensure it's on the wake timer list
            //

            ExTimer->WakeTimer = WakeTimer;
            ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);
            if (WakeTimer) {
                if (!ExTimer->WakeTimerListEntry.Flink) {
                    InsertTailList(&ExpWakeTimerList, &ExTimer->WakeTimerListEntry);
                }
            } else {
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
            }
            ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);

            //
            // If an APC routine is specified, then initialize the APC, acquire the
            // thread's active time list lock, insert the timer in the thread's
            // active timer list, set the timer with an associated DPC, and set the
            // associated APC flag TRUE. Otherwise set the timer without an associated
            // DPC, and set the associated APC flag FALSE.
            //

            ExTimer->Period = Period;
            if (ARGUMENT_PRESENT(TimerApcRoutine)) {
                ExThread = PsGetCurrentThread();
                KeInitializeApc(&ExTimer->TimerApc,
                                &ExThread->Tcb,
                                CurrentApcEnvironment,
                                ExpTimerApcRoutine,
                                (PKRUNDOWN_ROUTINE)NULL,
                                (PKNORMAL_ROUTINE)TimerApcRoutine,
                                PreviousMode,
                                TimerContext);

                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                InsertTailList(&ExThread->ActiveTimerListHead,
                               &ExTimer->ActiveTimerListEntry);

                ExTimer->ApcAssociated = TRUE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             &ExTimer->TimerDpc);

                AssociatedApc = TRUE;

            } else {
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             NULL);

                AssociatedApc = FALSE;
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);

            //
            // Dereference the object as appropriate.
            //

            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (AssociatedApc == FALSE) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (ARGUMENT_PRESENT(PreviousState)) {
                try {
                    *PreviousState = State;

                } except(ExSystemExceptionFilter()) {
                }
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Beispiel #27
0
NTSYSAPI
VOID
NTAPI
IoReleaseRemoveLockEx(
    IN PIO_REMOVE_LOCK PublicLock,
    IN PVOID            Tag,
    IN ULONG            RemlockSize // are we checked or free
    )

/*++

Routine Description:

    This routine is called to release the remove lock on the device object.  It
    must be called when finished using a previously locked reference to the
    device object.  If an Tag was specified when acquiring the lock then the
    same Tag must be specified when releasing the lock.

    When the lock count reduces to zero, this routine will signal the waiting
    event to release the waiting thread deleting the device object protected
    by this lock.

Arguments:

    DeviceObject - the device object to lock

    Tag - The tag (if any) specified when acquiring the lock.  This is used
          for lock tracking purposes

Return Value:

    none

--*/

{
    PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock;
    LONG            lockValue;
    KIRQL           oldIrql;
    LARGE_INTEGER   ticks;
    LONGLONG        difference;
    BOOLEAN         found;

    PIO_REMOVE_LOCK_TRACKING_BLOCK last;
    PIO_REMOVE_LOCK_TRACKING_BLOCK current;

    switch (RemlockSize) {
    case CHECKEDSIZE:

        //
        // Check the tick count and make sure this thing hasn't been locked
        // for more than MaxLockedMinutes.
        //

        found = FALSE;
        ExAcquireSpinLock(&Lock->Dbg.Spin, &oldIrql);
        last = (Lock->Dbg.Blocks);
        current = last;

        KeQueryTickCount((&ticks));

        while (NULL != current) {

            if (Lock->Dbg.MaxLockedTicks) {
                difference = ticks.QuadPart - current->TimeLocked.QuadPart;

                if (Lock->Dbg.MaxLockedTicks < difference) {

                    KdPrint(("IoReleaseRemoveLock: Lock %#08lx (tag %#08lx) "
                             "locked for %I64d ticks - TOO LONG\n",
                             Lock,
                             current->Tag,
                             difference));

                    KdPrint(("IoReleaseRemoveLock: Lock acquired in file "
                             "%s on line %d\n",
                             current->File,
                             current->Line));
                    ASSERT(FALSE);
                }
            }

            if ((!found) && (current->Tag == Tag)) {
                found = TRUE;
                if (current == Lock->Dbg.Blocks) {
                    Lock->Dbg.Blocks = current->Link;
                    ExFreePool (current);
                    current = Lock->Dbg.Blocks;
                } else {
                    last->Link = current->Link;
                    ExFreePool (current);
                    current = last->Link;
                }
                continue;
            }

            last = current;
            current = current->Link;
        }

        ExReleaseSpinLock(&Lock->Dbg.Spin, oldIrql);

        if (!found) {
            //
            // Check to see if we have any credits in our Low Memory Count.
            // In this fassion we can tell if we have acquired any locks without
            // the memory for adding tracking blocks.
            //
            if (InterlockedDecrement (& Lock->Dbg.LowMemoryCount) < 0) {
                //
                // We have just released a lock that neither had a corresponding
                // tracking block, nor a credit in LowMemoryCount.
                //
                InterlockedIncrement (& Lock->Dbg.LowMemoryCount);
                KdPrint (("IoReleaseRemoveLock: Couldn't find Tag %#08lx "
                          "in the lock tracking list\n",
                          Tag));
                ASSERT(FALSE);
            }
        }
        break;

    case FREESIZE:
        break;

    default:
        break;
    }

    lockValue = InterlockedDecrement(&Lock->Common.IoCount);

    ASSERT(0 <= lockValue);

    if (0 == lockValue) {

        ASSERT (Lock->Common.Removed);

        //
        // The device needs to be removed.  Signal the remove event
        // that it's safe to go ahead.
        //

        KeSetEvent(&Lock->Common.RemoveEvent,
                   IO_NO_INCREMENT,
                   FALSE);
    }
    return;
}
Beispiel #28
0
LOGICAL
ExpScanGeneralLookasideList (
    IN PLIST_ENTRY ListHead,
    IN PKSPIN_LOCK SpinLock
    )

/*++

Routine Description:

    This function scans the specified list of general lookaside descriptors
    and adjusts the maximum depth as necessary.

Arguments:

    ListHead - Supplies the address of the listhead for a list of lookaside
        descriptors.

    SpinLock - Supplies the address of the spinlock to be used to synchronize
        access to the list of lookaside descriptors.

Return Value:

    A value of TRUE is returned if the maximum depth of any lookaside list
    is changed. Otherwise, a value of FALSE is returned.

--*/

{

    ULONG Allocates;
    LOGICAL Changes;
    PLIST_ENTRY Entry;
    PPAGED_LOOKASIDE_LIST Lookaside;
    ULONG Misses;
    KIRQL OldIrql;

    //
    // Raise IRQL and acquire the specified spinlock.
    //

    Changes = FALSE;
    ExAcquireSpinLock(SpinLock, &OldIrql);

    //
    // Scan the specified list of lookaside descriptors and adjust the
    // maximum depth as necessary.
    //
    // N.B. All lookaside list descriptor are treated as if they were
    //      paged descriptor even though they may be nonpaged descriptors.
    //      This is possible since both structures are identical except
    //      for the locking fields which are the last structure fields.

    Entry = ListHead->Flink;
    while (Entry != ListHead) {
        Lookaside = CONTAINING_RECORD(Entry,
                                      PAGED_LOOKASIDE_LIST,
                                      L.ListEntry);

        //
        // Compute the total number of allocations and misses per second for
        // this scan period.
        //

        Allocates = Lookaside->L.TotalAllocates - Lookaside->L.LastTotalAllocates;
        Lookaside->L.LastTotalAllocates = Lookaside->L.TotalAllocates;
        Misses = Lookaside->L.AllocateMisses - Lookaside->L.LastAllocateMisses;
        Lookaside->L.LastAllocateMisses = Lookaside->L.AllocateMisses;

        //
        // Compute target depth of lookaside list.
        //

        Changes |= ExpComputeLookasideDepth(Allocates,
                                            Misses,
                                            Lookaside->L.MaximumDepth,
                                            &Lookaside->L.Depth);

        Entry = Entry->Flink;
    }

    //
    // Release spinlock, lower IRQL, and return function value.
    //

    ExReleaseSpinLock(SpinLock, OldIrql);
    return Changes;
}
Beispiel #29
0
NTSTATUS
NtCancelTimer (
    IN HANDLE TimerHandle,
    OUT PBOOLEAN CurrentState OPTIONAL
    )

/*++

Routine Description:

    This function cancels a timer object.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    CurrentState - Supplies an optional pointer to a variable that will
        receive the current state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the current state address if
    // specified, reference the timer object, and cancel the timer object.
    // If the probe fails, then return the exception code as the service
    // status. Otherwise return the status value returned by the reference
    // object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe current state address if
        // necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(CurrentState))) {
            ProbeForWriteBoolean(CurrentState);
        }

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_MODIFY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If the reference was successful, then cancel the timer object,
        // dereference the timer object, and write the current state value
        // if specified. If the write attempt fails, then do not report an
        // error. When the caller attempts to access the current state value,
        // an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            if (ExTimer->WakeTimerListEntry.Flink) {
                ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);

                //
                // Check again as ExGetNextWakeTime might have removed it.
                //
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
                ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            //
            // Read current state of timer, dereference timer object, and set
            // current state.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);
            ObDereferenceObject(ExTimer);
            if (ARGUMENT_PRESENT(CurrentState)) {
                try {
                    *CurrentState = State;

                } except(ExSystemExceptionFilter()) {
                }
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Beispiel #30
0
NTSTATUS
MmRemovePhysicalMemory (
    IN PPHYSICAL_ADDRESS StartAddress,
    IN OUT PLARGE_INTEGER NumberOfBytes
    )

/*++

Routine Description:

    This routine attempts to remove the specified physical address range
    from the system.

Arguments:

    StartAddress  - Supplies the starting physical address.

    NumberOfBytes  - Supplies a pointer to the number of bytes being removed.

Return Value:

    NTSTATUS.

Environment:

    Kernel mode.  PASSIVE level.  No locks held.

--*/

{
    ULONG i;
    ULONG Additional;
    PFN_NUMBER Page;
    PFN_NUMBER LastPage;
    PFN_NUMBER OriginalLastPage;
    PFN_NUMBER start;
    PFN_NUMBER PagesReleased;
    PMMPFN Pfn1;
    PMMPFN StartPfn;
    PMMPFN EndPfn;
    KIRQL OldIrql;
    PFN_NUMBER StartPage;
    PFN_NUMBER EndPage;
    PFN_COUNT NumberOfPages;
    SPFN_NUMBER MaxPages;
    PFN_NUMBER PageFrameIndex;
    PFN_NUMBER RemovedPages;
    LOGICAL Inserted;
    NTSTATUS Status;
    PMMPTE PointerPte;
    PMMPTE EndPte;
    PVOID VirtualAddress;
    PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock;
    PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock;
    PPHYSICAL_MEMORY_RUN NewRun;
    LOGICAL PfnDatabaseIsPhysical;

    ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);

    ASSERT (BYTE_OFFSET(NumberOfBytes->LowPart) == 0);
    ASSERT (BYTE_OFFSET(StartAddress->LowPart) == 0);

    if (MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) {

        //
        // The system must be configured for dynamic memory addition.  This is
        // not strictly required to remove the memory, but it's better to check
        // for it now under the assumption that the administrator is probably
        // going to want to add this range of memory back in - better to give
        // the error now and refuse the removal than to refuse the addition
        // later.
        //
    
        if (MmDynamicPfn == FALSE) {
            return STATUS_NOT_SUPPORTED;
        }

        PfnDatabaseIsPhysical = TRUE;
    }
    else {
        PfnDatabaseIsPhysical = FALSE;
    }

    StartPage = (PFN_NUMBER)(StartAddress->QuadPart >> PAGE_SHIFT);
    NumberOfPages = (PFN_COUNT)(NumberOfBytes->QuadPart >> PAGE_SHIFT);

    EndPage = StartPage + NumberOfPages;

    if (EndPage - 1 > MmHighestPossiblePhysicalPage) {

        //
        // Truncate the request into something that can be mapped by the PFN
        // database.
        //

        EndPage = MmHighestPossiblePhysicalPage + 1;
        NumberOfPages = (PFN_COUNT)(EndPage - StartPage);
    }

    //
    // The range cannot wrap.
    //

    if (StartPage >= EndPage) {
        return STATUS_INVALID_PARAMETER_1;
    }

    StartPfn = MI_PFN_ELEMENT (StartPage);
    EndPfn = MI_PFN_ELEMENT (EndPage);

    ExAcquireFastMutex (&MmDynamicMemoryMutex);

#if DBG
    MiDynmemData[0] += 1;
#endif

    //
    // Decrease all commit limits to reflect the removed memory.
    //

    ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql);

    ASSERT (MmTotalCommitLimit <= MmTotalCommitLimitMaximum);

    if ((NumberOfPages + 100 > MmTotalCommitLimit - MmTotalCommittedPages) ||
        (MmTotalCommittedPages > MmTotalCommitLimit)) {

#if DBG
        MiDynmemData[1] += 1;
#endif
        ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);
        ExReleaseFastMutex (&MmDynamicMemoryMutex);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    MmTotalCommitLimit -= NumberOfPages;
    MmTotalCommitLimitMaximum -= NumberOfPages;

    ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);

    //
    // Check for outstanding promises that cannot be broken.
    //

    LOCK_PFN (OldIrql);

    MaxPages = MI_NONPAGABLE_MEMORY_AVAILABLE() - 100;

    if ((SPFN_NUMBER)NumberOfPages > MaxPages) {
#if DBG
        MiDynmemData[2] += 1;
#endif
        UNLOCK_PFN (OldIrql);
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto giveup2;
    }

    MmResidentAvailablePages -= NumberOfPages;
    MmNumberOfPhysicalPages -= NumberOfPages;

    //
    // The range must be contained in a single entry.  It is permissible for
    // it to be part of a single entry, but it must not cross multiple entries.
    //

    Additional = (ULONG)-2;

    start = 0;
    do {

        Page = MmPhysicalMemoryBlock->Run[start].BasePage;
        LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount;

        if ((StartPage >= Page) && (EndPage <= LastPage)) {
            if ((StartPage == Page) && (EndPage == LastPage)) {
                Additional = (ULONG)-1;
            }
            else if ((StartPage == Page) || (EndPage == LastPage)) {
                Additional = 0;
            }
            else {
                Additional = 1;
            }
            break;
        }

        start += 1;

    } while (start != MmPhysicalMemoryBlock->NumberOfRuns);

    if (Additional == (ULONG)-2) {
#if DBG
        MiDynmemData[3] += 1;
#endif
        MmResidentAvailablePages += NumberOfPages;
        MmNumberOfPhysicalPages += NumberOfPages;
        UNLOCK_PFN (OldIrql);
        Status = STATUS_CONFLICTING_ADDRESSES;
        goto giveup2;
    }

    for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
        Pfn1->u3.e1.RemovalRequested = 1;
    }

    //
    // The free and zero lists must be pruned now before releasing the PFN
    // lock otherwise if another thread allocates the page from these lists,
    // the allocation will clear the RemovalRequested flag forever.
    //

    RemovedPages = MiRemovePhysicalPages (StartPage, EndPage);

    if (RemovedPages != NumberOfPages) {

#if DBG
retry:
#endif
    
        Pfn1 = StartPfn;
    
        InterlockedIncrement (&MiDelayPageFaults);
    
        for (i = 0; i < 5; i += 1) {
    
            UNLOCK_PFN (OldIrql);
    
            //
            // Attempt to move pages to the standby list.  Note that only the
            // pages with RemovalRequested set are moved.
            //
    
            MiTrimRemovalPagesOnly = TRUE;
    
            MiEmptyAllWorkingSets ();
    
            MiTrimRemovalPagesOnly = FALSE;
    
            MiFlushAllPages ();
    
            KeDelayExecutionThread (KernelMode, FALSE, &MmHalfSecond);
    
            LOCK_PFN (OldIrql);
    
            RemovedPages += MiRemovePhysicalPages (StartPage, EndPage);
    
            if (RemovedPages == NumberOfPages) {
                break;
            }
    
            //
            // RemovedPages doesn't include pages that were freed directly to
            // the bad page list via MiDecrementReferenceCount.  So use the above
            // check purely as an optimization - and walk here when necessary.
            //
    
            for ( ; Pfn1 < EndPfn; Pfn1 += 1) {
                if (Pfn1->u3.e1.PageLocation != BadPageList) {
                    break;
                }
            }
    
            if (Pfn1 == EndPfn) {
                RemovedPages = NumberOfPages;
                break;
            }
        }

        InterlockedDecrement (&MiDelayPageFaults);
    }

    if (RemovedPages != NumberOfPages) {
#if DBG
        MiDynmemData[4] += 1;
        if (MiShowStuckPages != 0) {

            RemovedPages = 0;
            for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
                if (Pfn1->u3.e1.PageLocation != BadPageList) {
                    RemovedPages += 1;
                }
            }

            ASSERT (RemovedPages != 0);

            DbgPrint("MmRemovePhysicalMemory : could not get %d of %d pages\n",
                RemovedPages, NumberOfPages);

            if (MiShowStuckPages & 0x2) {

                ULONG PfnsPrinted;
                ULONG EnoughShown;
                PMMPFN FirstPfn;
                PFN_COUNT PfnCount;

                PfnCount = 0;
                PfnsPrinted = 0;
                EnoughShown = 100;
    
                if (MiShowStuckPages & 0x4) {
                    EnoughShown = (ULONG)-1;
                }
    
                DbgPrint("Stuck PFN list: ");
                for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
                    if (Pfn1->u3.e1.PageLocation != BadPageList) {
                        if (PfnCount == 0) {
                            FirstPfn = Pfn1;
                        }
                        PfnCount += 1;
                    }
                    else {
                        if (PfnCount != 0) {
                            DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase,
                                                    (FirstPfn - MmPfnDatabase) + PfnCount - 1);
                            PfnsPrinted += 1;
                            if (PfnsPrinted == EnoughShown) {
                                break;
                            }
                            PfnCount = 0;
                        }
                    }
                }
                if (PfnCount != 0) {
                    DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase,
                                            (FirstPfn - MmPfnDatabase) + PfnCount - 1);
                }
                DbgPrint("\n");
            }
            if (MiShowStuckPages & 0x8) {
                DbgBreakPoint ();
            }
            if (MiShowStuckPages & 0x10) {
                goto retry;
            }
        }
#endif
        UNLOCK_PFN (OldIrql);
        Status = STATUS_NO_MEMORY;
        goto giveup;
    }

#if DBG
    for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {
        ASSERT (Pfn1->u3.e1.PageLocation == BadPageList);
    }
#endif

    //
    // All the pages in the range have been removed.  Update the physical
    // memory blocks and other associated housekeeping.
    //

    if (Additional == 0) {

        //
        // The range can be split off from an end of an existing chunk so no
        // pool growth or shrinkage is required.
        //

        NewPhysicalMemoryBlock = MmPhysicalMemoryBlock;
        OldPhysicalMemoryBlock = NULL;
    }
    else {

        //
        // The range cannot be split off from an end of an existing chunk so
        // pool growth or shrinkage is required.
        //

        UNLOCK_PFN (OldIrql);

        i = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
             (sizeof(PHYSICAL_MEMORY_RUN) * (MmPhysicalMemoryBlock->NumberOfRuns + Additional)));

        NewPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool,
                                                        i,
                                                        '  mM');

        if (NewPhysicalMemoryBlock == NULL) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
#if DBG
            MiDynmemData[5] += 1;
#endif
            goto giveup;
        }

        OldPhysicalMemoryBlock = MmPhysicalMemoryBlock;
        RtlZeroMemory (NewPhysicalMemoryBlock, i);

        LOCK_PFN (OldIrql);
    }

    //
    // Remove or split the requested range from the existing memory block.
    //

    NewPhysicalMemoryBlock->NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns + Additional;
    NewPhysicalMemoryBlock->NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages - NumberOfPages;

    NewRun = &NewPhysicalMemoryBlock->Run[0];
    start = 0;
    Inserted = FALSE;

    do {

        Page = MmPhysicalMemoryBlock->Run[start].BasePage;
        LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount;

        if (Inserted == FALSE) {

            if ((StartPage >= Page) && (EndPage <= LastPage)) {

                if ((StartPage == Page) && (EndPage == LastPage)) {
                    ASSERT (Additional == -1);
                    start += 1;
                    continue;
                }
                else if ((StartPage == Page) || (EndPage == LastPage)) {
                    ASSERT (Additional == 0);
                    if (StartPage == Page) {
                        MmPhysicalMemoryBlock->Run[start].BasePage += NumberOfPages;
                    }
                    MmPhysicalMemoryBlock->Run[start].PageCount -= NumberOfPages;
                }
                else {
                    ASSERT (Additional == 1);

                    OriginalLastPage = LastPage;

                    MmPhysicalMemoryBlock->Run[start].PageCount =
                        StartPage - MmPhysicalMemoryBlock->Run[start].BasePage;

                    *NewRun = MmPhysicalMemoryBlock->Run[start];
                    NewRun += 1;

                    NewRun->BasePage = EndPage;
                    NewRun->PageCount = OriginalLastPage - EndPage;
                    NewRun += 1;

                    start += 1;
                    continue;
                }

                Inserted = TRUE;
            }
        }

        *NewRun = MmPhysicalMemoryBlock->Run[start];
        NewRun += 1;
        start += 1;

    } while (start != MmPhysicalMemoryBlock->NumberOfRuns);

    //
    // Repoint the MmPhysicalMemoryBlock at the new chunk.
    // Free the old block after releasing the PFN lock.
    //

    MmPhysicalMemoryBlock = NewPhysicalMemoryBlock;

    if (EndPage - 1 == MmHighestPhysicalPage) {
        MmHighestPhysicalPage = StartPage - 1;
    }

    //
    // Throw away all the removed pages that are currently enqueued.
    //

    for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) {

        ASSERT (Pfn1->u3.e1.PageLocation == BadPageList);
        ASSERT (Pfn1->u3.e1.RemovalRequested == 1);

        MiUnlinkPageFromList (Pfn1);

        ASSERT (Pfn1->u1.Flink == 0);
        ASSERT (Pfn1->u2.Blink == 0);
        ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
        ASSERT64 (Pfn1->UsedPageTableEntries == 0);

        Pfn1->PteAddress = PFN_REMOVED;
        Pfn1->u3.e2.ShortFlags = 0;
        Pfn1->OriginalPte.u.Long = ZeroKernelPte.u.Long;
        Pfn1->PteFrame = 0;
    }

    //
    // Now that the removed pages have been discarded, eliminate the PFN
    // entries that mapped them.  Straddling entries left over from an
    // adjacent earlier removal are not collapsed at this point.
    //
    //

    PagesReleased = 0;

    if (PfnDatabaseIsPhysical == FALSE) {

        VirtualAddress = (PVOID)ROUND_TO_PAGES(MI_PFN_ELEMENT(StartPage));
        PointerPte = MiGetPteAddress (VirtualAddress);
        EndPte = MiGetPteAddress (PAGE_ALIGN(MI_PFN_ELEMENT(EndPage)));

        while (PointerPte < EndPte) {
            PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
            Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
            ASSERT (Pfn1->u2.ShareCount == 1);
            ASSERT (Pfn1->u3.e2.ReferenceCount == 1);
            Pfn1->u2.ShareCount = 0;
            MI_SET_PFN_DELETED (Pfn1);
#if DBG
            Pfn1->u3.e1.PageLocation = StandbyPageList;
#endif //DBG
            MiDecrementReferenceCount (PageFrameIndex);
    
            KeFlushSingleTb (VirtualAddress,
                             TRUE,
                             TRUE,
                             (PHARDWARE_PTE)PointerPte,
                             ZeroKernelPte.u.Flush);
    
            PagesReleased += 1;
            PointerPte += 1;
            VirtualAddress = (PVOID)((PCHAR)VirtualAddress + PAGE_SIZE);
        }

        MmResidentAvailablePages += PagesReleased;
    }

#if DBG
    MiDynmemData[6] += 1;
#endif

    UNLOCK_PFN (OldIrql);

    if (PagesReleased != 0) {
        MiReturnCommitment (PagesReleased);
    }

    ExReleaseFastMutex (&MmDynamicMemoryMutex);

    if (OldPhysicalMemoryBlock != NULL) {
        ExFreePool (OldPhysicalMemoryBlock);
    }

    NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages * PAGE_SIZE;

    return STATUS_SUCCESS;

giveup:

    //
    // All the pages in the range were not obtained.  Back everything out.
    //

    PageFrameIndex = StartPage;
    Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);

    LOCK_PFN (OldIrql);

    while (PageFrameIndex < EndPage) {

        ASSERT (Pfn1->u3.e1.RemovalRequested == 1);

        Pfn1->u3.e1.RemovalRequested = 0;

        if ((Pfn1->u3.e1.PageLocation == BadPageList) &&
            (Pfn1->u3.e1.ParityError == 0)) {

            MiUnlinkPageFromList (Pfn1);
            MiInsertPageInList (MmPageLocationList[FreePageList],
                                PageFrameIndex);
        }

        Pfn1 += 1;
        PageFrameIndex += 1;
    }

    MmResidentAvailablePages += NumberOfPages;
    MmNumberOfPhysicalPages += NumberOfPages;

    UNLOCK_PFN (OldIrql);

giveup2:

    ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql);
    MmTotalCommitLimit += NumberOfPages;
    MmTotalCommitLimitMaximum += NumberOfPages;
    ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);

    ExReleaseFastMutex (&MmDynamicMemoryMutex);

    return Status;
}