Implement targeted IPI broadcasting using processor block array
All checks were successful
All checks were successful
This commit is contained in:
@@ -524,6 +524,8 @@ typedef struct _KPROCESSOR_BLOCK
|
||||
KAFFINITY SetMember;
|
||||
ULONG StallScaleFactor;
|
||||
UCHAR CpuNumber;
|
||||
ULONG HardwareId;
|
||||
VOLATILE BOOLEAN Started;
|
||||
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
||||
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
||||
|
||||
|
||||
@@ -483,6 +483,8 @@ typedef struct _KPROCESSOR_BLOCK
|
||||
KAFFINITY SetMember;
|
||||
ULONG StallScaleFactor;
|
||||
UCHAR CpuNumber;
|
||||
ULONG HardwareId;
|
||||
VOLATILE BOOLEAN Started;
|
||||
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
||||
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
||||
|
||||
|
||||
@@ -127,6 +127,24 @@ HL::Acpi::GetAcpiTimerInfo(OUT PACPI_TIMER_INFO *AcpiTimerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ACPI system information structure containing processor and topology data.
|
||||
*
|
||||
* @param SystemInfo
|
||||
* Supplies a pointer to the memory area where the pointer to the system information structure will be stored.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
HL::Acpi::GetSystemInformation(OUT PACPI_SYSTEM_INFO *SystemInfo)
|
||||
{
|
||||
/* Return a pointer to the ACPI system information */
|
||||
*SystemInfo = &HL::Acpi::SystemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an initialization of the ACPI subsystem.
|
||||
*
|
||||
|
||||
@@ -402,6 +402,9 @@ HL::Pic::InitializeApic(VOID)
|
||||
WriteApicRegister(APIC_LDR, (1UL << CpuNumber) << 24);
|
||||
}
|
||||
|
||||
/* Report the APIC ID to the kernel logic */
|
||||
KE::Processor::RegisterHardwareId(GetCpuApicId());
|
||||
|
||||
/* Configure the spurious interrupt vector */
|
||||
SpuriousRegister.Long = ReadApicRegister(APIC_SIVR);
|
||||
SpuriousRegister.Vector = APIC_VECTOR_SPURIOUS;
|
||||
@@ -781,25 +784,21 @@ VOID
|
||||
HL::Pic::SendBroadcastIpi(IN ULONG Vector,
|
||||
IN BOOLEAN Self)
|
||||
{
|
||||
APIC_COMMAND_REGISTER Register;
|
||||
PKPROCESSOR_BLOCK CurrentProcessorBlock, TargetProcessorBlock;
|
||||
PACPI_SYSTEM_INFO SysInfo;
|
||||
BOOLEAN Interrupts;
|
||||
ULONG Index;
|
||||
|
||||
/* SMP not implemented */
|
||||
if(TRUE)
|
||||
/* Get the current processor block */
|
||||
CurrentProcessorBlock = KE::Processor::GetCurrentProcessorBlock();
|
||||
if(CurrentProcessorBlock == NULLPTR)
|
||||
{
|
||||
/* Check if IPI is addressed to the current CPU */
|
||||
if(Self)
|
||||
{
|
||||
/* Send IPI to the current CPU */
|
||||
SendSelfIpi(Vector);
|
||||
/* Processor block not available, return */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to do */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the ACPI system information */
|
||||
HL::Acpi::GetSystemInformation(&SysInfo);
|
||||
|
||||
/* Check whether interrupts are enabled */
|
||||
Interrupts = AR::CpuFunc::InterruptsEnabled();
|
||||
@@ -807,32 +806,31 @@ HL::Pic::SendBroadcastIpi(IN ULONG Vector,
|
||||
/* Disable interrupts */
|
||||
AR::CpuFunc::ClearInterruptFlag();
|
||||
|
||||
/* Prepare the APIC command register */
|
||||
Register.LongLong = 0;
|
||||
Register.DeliveryMode = APIC_DM_FIXED;
|
||||
Register.DestinationShortHand = Self ? APIC_DSH_AllIncludingSelf : APIC_DSH_AllExclusingSelf;
|
||||
Register.Level = 1;
|
||||
Register.TriggerMode = APIC_TGM_EDGE;
|
||||
Register.Vector = Vector;
|
||||
|
||||
/* Check current APIC mode */
|
||||
if(ApicMode == APIC_MODE_X2APIC)
|
||||
/* Iterate over all logical CPUs */
|
||||
for(Index = 0; Index < SysInfo->CpuCount; Index++)
|
||||
{
|
||||
/* In x2APIC mode, writing the full 64-bit value to the ICR MSR is sufficient */
|
||||
WriteApicRegister(APIC_ICR0, Register.LongLong);
|
||||
/* Retrieve the target processor block by its Logical CPU Number */
|
||||
TargetProcessorBlock = KE::Processor::GetProcessorBlock(Index);
|
||||
|
||||
/* Only send to processors that exist and have successfully started */
|
||||
if(TargetProcessorBlock != NULLPTR && TargetProcessorBlock->Started)
|
||||
{
|
||||
/* Check if this processor originated the broadcast */
|
||||
if(TargetProcessorBlock->HardwareId == CurrentProcessorBlock->HardwareId)
|
||||
{
|
||||
/* Check if this is a self broadcast */
|
||||
if(Self)
|
||||
{
|
||||
/* Dispatch the IPI to the current processor */
|
||||
SendSelfIpi(Vector);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for the APIC to clear the delivery status */
|
||||
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
|
||||
{
|
||||
/* Yield the processor */
|
||||
AR::CpuFunc::YieldProcessor();
|
||||
/* Dispatch the IPI to the target processor */
|
||||
SendIpi(TargetProcessorBlock->HardwareId, Vector);
|
||||
}
|
||||
}
|
||||
|
||||
/* In xAPIC compatibility mode, write the command to the ICR registers */
|
||||
WriteApicRegister(APIC_ICR1, Register.Long1);
|
||||
WriteApicRegister(APIC_ICR0, Register.Long0);
|
||||
}
|
||||
|
||||
/* Check whether interrupts need to be re-enabled */
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace HL
|
||||
STATIC XTAPI XTSTATUS GetAcpiTable(IN ULONG Signature,
|
||||
OUT PACPI_DESCRIPTION_HEADER *AcpiTable);
|
||||
STATIC XTAPI VOID GetAcpiTimerInfo(OUT PACPI_TIMER_INFO *AcpiTimerInfo);
|
||||
STATIC XTAPI VOID GetSystemInformation(OUT PACPI_SYSTEM_INFO *SystemInfo);
|
||||
STATIC XTAPI XTSTATUS InitializeAcpi(VOID);
|
||||
STATIC XTAPI XTSTATUS InitializeAcpiSystemInformation(VOID);
|
||||
|
||||
|
||||
@@ -17,11 +17,18 @@ namespace KE
|
||||
{
|
||||
class Processor
|
||||
{
|
||||
private:
|
||||
STATIC ULONG InstalledCpus;
|
||||
STATIC PKPROCESSOR_BLOCK *ProcessorBlocks;
|
||||
|
||||
public:
|
||||
STATIC XTAPI PKPROCESSOR_BLOCK GetCurrentProcessorBlock(VOID);
|
||||
STATIC XTAPI PKPROCESSOR_CONTROL_BLOCK GetCurrentProcessorControlBlock(VOID);
|
||||
STATIC XTAPI ULONG GetCurrentProcessorNumber(VOID);
|
||||
STATIC XTAPI PKTHREAD GetCurrentThread(VOID);
|
||||
STATIC XTAPI PKPROCESSOR_BLOCK GetProcessorBlock(IN ULONG CpuNumber);
|
||||
STATIC XTAPI XTSTATUS InitializeProcessorStructures(IN ULONG CpuCount);
|
||||
STATIC XTAPI VOID RegisterHardwareId(IN ULONG HardwareId);
|
||||
STATIC XTAPI VOID SaveProcessorState(OUT PKPROCESSOR_STATE CpuState);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,6 +66,92 @@ KE::Processor::GetCurrentThread(VOID)
|
||||
return (PKTHREAD)AR::CpuFunc::ReadGSQuadWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the processor block for the specified processor number.
|
||||
*
|
||||
* @param CpuNumber
|
||||
* Supplies the zero-indexed processor number.
|
||||
*
|
||||
* @return This routine returns a pointer to the processor block, or NULLPTR if invalid.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PKPROCESSOR_BLOCK
|
||||
KE::Processor::GetProcessorBlock(IN ULONG CpuNumber)
|
||||
{
|
||||
/* Check if the requested CPU number is within dynamic bounds */
|
||||
if(ProcessorBlocks == NULLPTR || CpuNumber >= InstalledCpus)
|
||||
{
|
||||
/* Invalid CPU number, return NULLPTR */
|
||||
return NULLPTR;
|
||||
}
|
||||
|
||||
/* Return requested processor block */
|
||||
return ProcessorBlocks[CpuNumber];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the global processor structures by allocating an array of processor block pointers.
|
||||
*
|
||||
* @param CpuCount
|
||||
* Supplies the total number of processors present in the system.
|
||||
*
|
||||
* @return This routine returns a status code indicating the success or failure of the allocation.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
KE::Processor::InitializeProcessorStructures(IN ULONG CpuCount)
|
||||
{
|
||||
XTSTATUS Status;
|
||||
|
||||
/* Save number of CPUs installed */
|
||||
InstalledCpus = CpuCount;
|
||||
|
||||
/* Allocate an array of pointers */
|
||||
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||
CpuCount * sizeof(PKPROCESSOR_BLOCK),
|
||||
(PVOID*)&ProcessorBlocks);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory, return error */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Zero the array initially */
|
||||
RTL::Memory::ZeroMemory(ProcessorBlocks, CpuCount * sizeof(PKPROCESSOR_BLOCK));
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the hardware APIC ID for the currently executing processor.
|
||||
*
|
||||
* @param ApicId
|
||||
* Supplies the hardware APIC ID to register in the processor block.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
KE::Processor::RegisterHardwareId(IN ULONG HardwareId)
|
||||
{
|
||||
PKPROCESSOR_BLOCK CurrentBlock;
|
||||
|
||||
/* Retrieve the processor block for the executing core */
|
||||
CurrentBlock = GetCurrentProcessorBlock();
|
||||
if(CurrentBlock != NULLPTR)
|
||||
{
|
||||
/* Register the hardware identifier for IPI targeting */
|
||||
CurrentBlock->HardwareId = HardwareId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current processor state.
|
||||
*
|
||||
|
||||
@@ -21,6 +21,12 @@ ETHREAD KE::KThread::InitialThread = {};
|
||||
/* Kernel UBSAN active frame flag */
|
||||
BOOLEAN KE::KUbsan::ActiveFrame = FALSE;
|
||||
|
||||
/* Total number of installed processors in the system */
|
||||
ULONG KE::Processor::InstalledCpus;
|
||||
|
||||
/* Array of pointers to processor control blocks */
|
||||
PKPROCESSOR_BLOCK *KE::Processor::ProcessorBlocks;
|
||||
|
||||
/* Kernel shared data (KSD) */
|
||||
PKSHARED_DATA KE::SharedData::KernelSharedData;
|
||||
|
||||
|
||||
@@ -66,6 +66,92 @@ KE::Processor::GetCurrentThread(VOID)
|
||||
return (PKTHREAD)AR::CpuFunc::ReadFSDualWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the processor block for the specified processor number.
|
||||
*
|
||||
* @param CpuNumber
|
||||
* Supplies the zero-indexed processor number.
|
||||
*
|
||||
* @return This routine returns a pointer to the processor block, or NULLPTR if invalid.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PKPROCESSOR_BLOCK
|
||||
KE::Processor::GetProcessorBlock(IN ULONG CpuNumber)
|
||||
{
|
||||
/* Check if the requested CPU number is within dynamic bounds */
|
||||
if(ProcessorBlocks == NULLPTR || CpuNumber >= InstalledCpus)
|
||||
{
|
||||
/* Invalid CPU number, return NULLPTR */
|
||||
return NULLPTR;
|
||||
}
|
||||
|
||||
/* Return requested processor block */
|
||||
return ProcessorBlocks[CpuNumber];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the global processor structures by allocating an array of processor block pointers.
|
||||
*
|
||||
* @param CpuCount
|
||||
* Supplies the total number of processors present in the system.
|
||||
*
|
||||
* @return This routine returns a status code indicating the success or failure of the allocation.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
KE::Processor::InitializeProcessorStructures(IN ULONG CpuCount)
|
||||
{
|
||||
XTSTATUS Status;
|
||||
|
||||
/* Save number of CPUs installed */
|
||||
InstalledCpus = CpuCount;
|
||||
|
||||
/* Allocate an array of pointers */
|
||||
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||
CpuCount * sizeof(PKPROCESSOR_BLOCK),
|
||||
(PVOID*)&ProcessorBlocks);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory, return error */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Zero the array initially */
|
||||
RTL::Memory::ZeroMemory(ProcessorBlocks, CpuCount * sizeof(PKPROCESSOR_BLOCK));
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the hardware APIC ID for the currently executing processor.
|
||||
*
|
||||
* @param ApicId
|
||||
* Supplies the hardware APIC ID to register in the processor block.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
KE::Processor::RegisterHardwareId(IN ULONG HardwareId)
|
||||
{
|
||||
PKPROCESSOR_BLOCK CurrentBlock;
|
||||
|
||||
/* Retrieve the processor block for the executing core */
|
||||
CurrentBlock = GetCurrentProcessorBlock();
|
||||
if(CurrentBlock != NULLPTR)
|
||||
{
|
||||
/* Register the hardware identifier for IPI targeting */
|
||||
CurrentBlock->HardwareId = HardwareId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current processor state.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user