[HAL] Implement IPI support functions

This commit is contained in:
Timo Kreuzer 2023-11-26 17:32:27 +02:00
parent 4bccb6e6c9
commit 40b6b1dab3
7 changed files with 270 additions and 11 deletions

View file

@ -106,14 +106,6 @@ ApicRequestGlobalInterrupt(
/* SMP SUPPORT FUNCTIONS ******************************************************/
VOID
NTAPI
HalpRequestIpi(_In_ KAFFINITY TargetProcessors)
{
UNIMPLEMENTED;
__debugbreak();
}
VOID
ApicStartApplicationProcessor(
_In_ ULONG NTProcessorNumber,
@ -138,3 +130,172 @@ ApicStartApplicationProcessor(
ApicRequestGlobalInterrupt(HalpProcessorIdentity[NTProcessorNumber].LapicId, (StartupLoc.LowPart) >> 12,
APIC_MT_Startup, APIC_TGM_Edge, APIC_DSH_Destination);
}
/* HAL IPI FUNCTIONS **********************************************************/
/*!
* \brief Broadcasts an IPI with a specified vector to all processors.
*
* \param Vector - Specifies the interrupt vector to be delivered.
* \param IncludeSelf - Specifies whether to include the current processor.
*/
VOID
NTAPI
HalpBroadcastIpiSpecifyVector(
_In_ UCHAR Vector,
_In_ BOOLEAN IncludeSelf)
{
APIC_DSH DestinationShortHand = IncludeSelf ?
APIC_DSH_AllIncludingSelf : APIC_DSH_AllExcludingSelf;
/* Request the interrupt targeted at all processors */
ApicRequestGlobalInterrupt(0, // Ignored
Vector,
APIC_MT_Fixed,
APIC_TGM_Edge,
DestinationShortHand);
}
/*!
* \brief Requests an IPI with a specified vector on the specified processors.
*
* \param TargetSet - Specifies the set of processors to send the IPI to.
* \param Vector - Specifies the interrupt vector to be delivered.
*
* \remarks This function is exported on Windows 10.
*/
VOID
NTAPI
HalRequestIpiSpecifyVector(
_In_ KAFFINITY TargetSet,
_In_ UCHAR Vector)
{
KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
KAFFINITY RemainingSet, SetMember;
ULONG ProcessorIndex;
ULONG LApicId;
/* Sanitize the target set */
TargetSet &= ActiveProcessors;
/* Check if all processors are requested */
if (TargetSet == ActiveProcessors)
{
/* Send an IPI to all processors, including this processor */
HalpBroadcastIpiSpecifyVector(Vector, TRUE);
return;
}
/* Check if all processors except the current one are requested */
if (TargetSet == (ActiveProcessors & ~KeGetCurrentPrcb()->SetMember))
{
/* Send an IPI to all processors, excluding this processor */
HalpBroadcastIpiSpecifyVector(Vector, FALSE);
return;
}
/* Loop while we have more processors */
RemainingSet = TargetSet;
while (RemainingSet != 0)
{
NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
ASSERT(ProcessorIndex < KeNumberProcessors);
SetMember = AFFINITY_MASK(ProcessorIndex);
RemainingSet &= ~SetMember;
/* Send the interrupt to the target processor */
LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
ApicRequestGlobalInterrupt(LApicId,
Vector,
APIC_MT_Fixed,
APIC_TGM_Edge,
APIC_DSH_Destination);
}
}
/*!
* \brief Requests an IPI interrupt on the specified processors.
*
* \param TargetSet - Specifies the set of processors to send the IPI to.
*/
VOID
NTAPI
HalpRequestIpi(
_In_ KAFFINITY TargetSet)
{
/* Request the IPI vector */
HalRequestIpiSpecifyVector(TargetSet, APIC_IPI_VECTOR);
}
#ifdef _M_AMD64
/*!
* \brief Requests a software interrupt on the specified processors.
*
* \param TargetSet - Specifies the set of processors to send the IPI to.
* \param Irql - Specifies the IRQL of the software interrupt.
*/
VOID
NTAPI
HalpSendSoftwareInterrupt(
_In_ KAFFINITY TargetSet,
_In_ KIRQL Irql)
{
UCHAR Vector;
/* Get the vector for the requested IRQL */
if (Irql == APC_LEVEL)
{
Vector = APC_VECTOR;
}
else if (Irql == DISPATCH_LEVEL)
{
Vector = DISPATCH_VECTOR;
}
else
{
ASSERT(FALSE);
return;
}
/* Request the IPI with the specified vector */
HalRequestIpiSpecifyVector(TargetSet, Vector);
}
/*!
* \brief Requests an NMI interrupt on the specified processors.
*
* \param TargetSet - Specifies the set of processors to send the IPI to.
*/
VOID
NTAPI
HalpSendNMI(
_In_ KAFFINITY TargetSet)
{
KAFFINITY RemainingSet, SetMember;
ULONG ProcessorIndex;
ULONG LApicId;
/* Make sure we do not send an NMI to ourselves */
ASSERT((TargetSet & ~KeGetCurrentPrcb()->SetMember) == 0);
/* Loop while we have more processors */
RemainingSet = TargetSet;
while (RemainingSet != 0)
{
NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
ASSERT(ProcessorIndex < KeNumberProcessors);
SetMember = AFFINITY_MASK(ProcessorIndex);
RemainingSet &= ~SetMember;
/* Send and NMI to the target processor */
LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
ApicRequestGlobalInterrupt(LApicId,
0,
APIC_MT_NMI,
APIC_TGM_Edge,
APIC_DSH_Destination);
}
}
#endif // _M_AMD64