Implement targeted IPI broadcasting using processor block array
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, debug) (push) Successful in -59m29s
Builds / ExectOS (i686, release) (push) Successful in -59m30s

This commit is contained in:
2026-05-11 00:07:21 +02:00
parent 897d9d4099
commit 5a92173586
9 changed files with 244 additions and 38 deletions

View File

@@ -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.
*

View File

@@ -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,58 +784,53 @@ 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);
return;
}
else
{
/* Nothing to do */
return;
}
/* Processor block not available, return */
return;
}
/* Get the ACPI system information */
HL::Acpi::GetSystemInformation(&SysInfo);
/* Check whether interrupts are enabled */
Interrupts = AR::CpuFunc::InterruptsEnabled();
/* 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;
/* Iterate over all logical CPUs */
for(Index = 0; Index < SysInfo->CpuCount; Index++)
{
/* Retrieve the target processor block by its Logical CPU Number */
TargetProcessorBlock = KE::Processor::GetProcessorBlock(Index);
/* Check current APIC mode */
if(ApicMode == APIC_MODE_X2APIC)
{
/* In x2APIC mode, writing the full 64-bit value to the ICR MSR is sufficient */
WriteApicRegister(APIC_ICR0, Register.LongLong);
}
else
{
/* Wait for the APIC to clear the delivery status */
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
/* Only send to processors that exist and have successfully started */
if(TargetProcessorBlock != NULLPTR && TargetProcessorBlock->Started)
{
/* Yield the processor */
AR::CpuFunc::YieldProcessor();
/* 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
{
/* 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 */

View File

@@ -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);

View File

@@ -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);
};
}

View File

@@ -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.
*

View File

@@ -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;

View File

@@ -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.
*