[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

@ -41,8 +41,8 @@
@ stdcall HalRequestIpi(long)
@ fastcall HalRequestSoftwareInterrupt(long)
@ stdcall HalReturnToFirmware(long)
;@ stdcall -arch=x86_64 HalSendNMI()
;@ stdcall -arch=x86_64 HalSendSoftwareInterrupt()
@ stdcall -arch=x86_64 HalSendNMI(int64)
@ stdcall -arch=x86_64 HalSendSoftwareInterrupt(int64 long)
@ stdcall HalSetBusData(long long long ptr long)
@ stdcall HalSetBusDataByOffset(long long long ptr long long)
@ stdcall HalSetDisplayParameters(long long)

View file

@ -151,7 +151,7 @@ typedef enum _APIC_DSH
APIC_DSH_Destination,
APIC_DSH_Self,
APIC_DSH_AllIncludingSelf,
APIC_DSH_AllExclusingSelf
APIC_DSH_AllExcludingSelf
} APIC_DSH;
/* Write Constants */

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

View file

@ -32,3 +32,22 @@ HalStartNextProcessor(
/* Always return false on UP systems */
return FALSE;
}
#ifdef _M_AMD64
VOID
NTAPI
HalSendNMI(
_In_ KAFFINITY TargetSet)
{
}
VOID
NTAPI
HalSendSoftwareInterrupt(
_In_ KAFFINITY TargetSet,
_In_ KIRQL Irql)
{
}
#endif // _M_AMD64

View file

@ -7,6 +7,15 @@
#pragma once
#define AFFINITY_MASK(Id) ((KAFFINITY)1 << (Id))
/* Helper to find the lowest CPU in a KAFFINITY */
#ifdef _WIN64
#define BitScanForwardAffinity BitScanForward64
#else
#define BitScanForwardAffinity BitScanForward
#endif
/* This table is filled for each physical processor on system */
typedef struct _PROCESSOR_IDENTITY
{
@ -53,3 +62,32 @@ VOID
NTAPI
HalpRequestIpi(
_In_ KAFFINITY TargetProcessors);
VOID
NTAPI
HalpBroadcastIpiSpecifyVector(
_In_ UCHAR Vector,
_In_ BOOLEAN IncludeSelf);
VOID
NTAPI
HalRequestIpiSpecifyVector(
_In_ KAFFINITY TargetSet,
_In_ UCHAR Vector);
#ifdef _M_AMD64
NTHALAPI
VOID
NTAPI
HalpSendNMI(
_In_ KAFFINITY TargetSet);
NTHALAPI
VOID
NTAPI
HalpSendSoftwareInterrupt(
_In_ KAFFINITY TargetSet,
_In_ KIRQL Irql);
#endif // _M_AMD64

View file

@ -22,3 +22,27 @@ HalRequestIpi(
{
HalpRequestIpi(TargetProcessors);
}
#ifdef _M_AMD64
VOID
NTAPI
HalSendNMI(
_In_ KAFFINITY TargetSet)
{
HalpSendNMI(TargetSet);
}
// See:
// - https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h#L53
// https://github.com/mirror/vbox/blob/b9657cd5351cf17432b664009cc25bb480dc64c1/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp#L683
VOID
NTAPI
HalSendSoftwareInterrupt(
_In_ KAFFINITY TargetSet,
_In_ KIRQL Irql)
{
HalpSendSoftwareInterrupt(TargetSet, Irql);
}
#endif // _M_AMD64

View file

@ -192,6 +192,23 @@ HalRequestSoftwareInterrupt(
_In_ KIRQL SoftwareInterruptRequested
);
#ifdef _M_AMD64
NTHALAPI
VOID
NTAPI
HalSendNMI(
_In_ KAFFINITY TargetSet);
NTHALAPI
VOID
NTAPI
HalSendSoftwareInterrupt(
_In_ KAFFINITY TargetSet,
_In_ KIRQL Irql);
#endif // _M_AMD64
NTHALAPI
VOID
NTAPI