reactos/ntoskrnl/io/iomgr/irq.c
Serge Gautherie cb6fc76b8b
[NTOS:IO] IoDisconnectInterrupt(): Switch to ExFreePoolWithTag() (#6503)
Follow-up to commit 24a14abf2 (r57412).

HBelusca's comment:
> If this ExFreePoolWithTag() call was left commented, it's probably
> because, back in the day where I introduced it, there was a pool
> corruption that was detected, the source of which was unknown at
> that time. In retrospect, it is most probably the interrupt disconnect
> bug in IoDisconnectInterrupt() that was causing it. Now that this
> bug has been fixed just previously, it should be safe to re-enable
> pool freeing with tag.
2024-05-05 17:03:42 +02:00

233 lines
6.8 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iomgr/irq.c
* PURPOSE: I/O Wrappers (called Completion Ports) for Kernel Queues
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject,
IN PKSERVICE_ROUTINE ServiceRoutine,
IN PVOID ServiceContext,
IN PKSPIN_LOCK SpinLock,
IN ULONG Vector,
IN KIRQL Irql,
IN KIRQL SynchronizeIrql,
IN KINTERRUPT_MODE InterruptMode,
IN BOOLEAN ShareVector,
IN KAFFINITY ProcessorEnableMask,
IN BOOLEAN FloatingSave)
{
PKINTERRUPT Interrupt;
PKINTERRUPT InterruptUsed;
PIO_INTERRUPT IoInterrupt;
BOOLEAN FirstRun;
CCHAR Count = 0;
KAFFINITY Affinity;
PAGED_CODE();
/* Assume failure */
*InterruptObject = NULL;
/* Get the affinity */
Affinity = ProcessorEnableMask & KeActiveProcessors;
while (Affinity)
{
/* Increase count */
if (Affinity & 1) Count++;
Affinity >>= 1;
}
/* Make sure we have a valid CPU count */
if (!Count) return STATUS_INVALID_PARAMETER;
/* Allocate the array of I/O interrupts */
IoInterrupt = ExAllocatePoolZero(NonPagedPool,
(Count - 1) * sizeof(KINTERRUPT) +
sizeof(IO_INTERRUPT),
TAG_KINTERRUPT);
if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES;
/* Use the structure's spinlock, if none was provided */
if (!SpinLock)
{
SpinLock = &IoInterrupt->SpinLock;
KeInitializeSpinLock(SpinLock);
}
/* We first start with a built-in interrupt inside the I/O structure */
Interrupt = (PKINTERRUPT)(IoInterrupt + 1);
FirstRun = TRUE;
/* Now create all the interrupts */
Affinity = ProcessorEnableMask & KeActiveProcessors;
for (Count = 0; Affinity; Count++, Affinity >>= 1)
{
/* Check if it's enabled for this CPU */
if (!(Affinity & 1))
continue;
/* Check which one we will use */
InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt;
/* Initialize it */
KeInitializeInterrupt(InterruptUsed,
ServiceRoutine,
ServiceContext,
SpinLock,
Vector,
Irql,
SynchronizeIrql,
InterruptMode,
ShareVector,
Count,
FloatingSave);
/* Connect it */
if (!KeConnectInterrupt(InterruptUsed))
{
/* Check how far we got */
if (FirstRun)
{
/* We failed early so just free this */
ExFreePoolWithTag(IoInterrupt, TAG_KINTERRUPT);
}
else
{
/* Far enough, so disconnect everything */
IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
}
/* And fail */
return STATUS_INVALID_PARAMETER;
}
/* Now we've used up our First Run */
if (FirstRun)
{
FirstRun = FALSE;
}
else
{
/* Move on to the next one */
IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++;
}
}
/* Return success */
*InterruptObject = &IoInterrupt->FirstInterrupt;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
NTAPI
IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
{
PIO_INTERRUPT IoInterrupt;
ULONG i;
PAGED_CODE();
/* Get the I/O interrupt */
IoInterrupt = CONTAINING_RECORD(InterruptObject,
IO_INTERRUPT,
FirstInterrupt);
/* Disconnect the first one */
KeDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
/* Now disconnect the others */
for (i = 0; i < KeNumberProcessors; i++)
{
/* Make sure one was registered */
if (!IoInterrupt->Interrupt[i])
continue;
/* Disconnect it */
KeDisconnectInterrupt(IoInterrupt->Interrupt[i]);
}
/* Free the I/O interrupt */
ExFreePoolWithTag(IoInterrupt, TAG_KINTERRUPT);
}
NTSTATUS
IopConnectInterruptExFullySpecific(
_Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
{
NTSTATUS Status;
PAGED_CODE();
/* Fallback to standard IoConnectInterrupt */
Status = IoConnectInterrupt(Parameters->FullySpecified.InterruptObject,
Parameters->FullySpecified.ServiceRoutine,
Parameters->FullySpecified.ServiceContext,
Parameters->FullySpecified.SpinLock,
Parameters->FullySpecified.Vector,
Parameters->FullySpecified.Irql,
Parameters->FullySpecified.SynchronizeIrql,
Parameters->FullySpecified.InterruptMode,
Parameters->FullySpecified.ShareVector,
Parameters->FullySpecified.ProcessorEnableMask,
Parameters->FullySpecified.FloatingSave);
DPRINT("IopConnectInterruptEx_FullySpecific: has failed with status %X", Status);
return Status;
}
NTSTATUS
NTAPI
IoConnectInterruptEx(
_Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters)
{
PAGED_CODE();
switch (Parameters->Version)
{
case CONNECT_FULLY_SPECIFIED:
return IopConnectInterruptExFullySpecific(Parameters);
case CONNECT_FULLY_SPECIFIED_GROUP:
//TODO: We don't do anything for the group type
return IopConnectInterruptExFullySpecific(Parameters);
case CONNECT_MESSAGE_BASED:
DPRINT1("FIXME: Message based interrupts are UNIMPLEMENTED\n");
break;
case CONNECT_LINE_BASED:
DPRINT1("FIXME: Line based interrupts are UNIMPLEMENTED\n");
break;
}
return STATUS_SUCCESS;
}
VOID
NTAPI
IoDisconnectInterruptEx(
_In_ PIO_DISCONNECT_INTERRUPT_PARAMETERS Parameters)
{
PAGED_CODE();
//FIXME: This eventually will need to handle more cases
if (Parameters->ConnectionContext.InterruptObject)
IoDisconnectInterrupt(Parameters->ConnectionContext.InterruptObject);
}
/* EOF */