exectos/xtoskrnl/hl/x86/cpu.c

166 lines
5.1 KiB
C

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtoskrnl/hl/x86/cpu.c
* DESCRIPTION: HAL x86 (i686/AMD64) processor support
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtos.h>
/**
* Initializes the processor.
*
* @param CpuNumber
* Supplies the number of the CPU, that is being initialized.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
HlInitializeProcessor(VOID)
{
PKPROCESSOR_BLOCK ProcessorBlock;
KAFFINITY Affinity;
/* Get current processor block */
ProcessorBlock = KeGetCurrentProcessorBlock();
/* Set initial stall factor, CPU number and mask interrupts */
ProcessorBlock->StallScaleFactor = INITIAL_STALL_FACTOR;
ProcessorBlock->Idr = 0xFFFFFFFF;
/* Set processor affinity */
Affinity = (KAFFINITY) 1 << ProcessorBlock->CpuNumber;
/* Apply affinity to a set of processors */
HlpActiveProcessors |= Affinity;
/* Initialize APIC for this processor */
HlpInitializePic();
/* Set the APIC running level */
HlSetRunLevel(KeGetCurrentProcessorBlock()->RunLevel);
}
XTAPI
XTSTATUS
HlStartProcessor(IN ULONG CpuId,
IN PHYSICAL_ADDRESS EntryPoint)
{
UCHAR Attempt;
/* Wait until command register is clear */
while((HlReadApicRegister(APIC_ICR0) & APIC_DELIVERY_PENDING) != 0);
/* Trigger INIT IPI and wait for delivery bit to be cleared */
HlpSendIpi(CpuId, APIC_DM_INIT | APIC_DM_LEVEL | APIC_DM_ASSERT);
while((HlReadApicRegister(APIC_ICR0) & APIC_DELIVERY_PENDING) != 0);
/* Deassert INIT IPI to take CPU out of reset and wait for delivery bit to be cleared */
HlpSendIpi(CpuId, APIC_DM_INIT | APIC_DM_LEVEL);
while((HlReadApicRegister(APIC_ICR0) & APIC_DELIVERY_PENDING) != 0);
/* Two attempts to send STARTUP IPI */
for(Attempt = 0; Attempt < 2; Attempt++)
{
/* Trigger STARTUP IPI and wait for delivery bit to be cleared */
HlpSendIpi(CpuId, APIC_DM_STARTUP | (EntryPoint.LowPart >> 12));
while((HlReadApicRegister(APIC_ICR0) & APIC_DELIVERY_PENDING) != 0);
}
/* Memory barrier */
ArMemoryBarrier();
/* Return success */
return STATUS_SUCCESS;
}
extern ULONG_PTR ArBootstrapPageMap;
XTAPI
XTSTATUS
HlStartAllProcessors(VOID)
{
PHYSICAL_ADDRESS ApPhysicalAddress;
PVOID ApVirtualAddress;
BOOLEAN Interrupts;
XTSTATUS Status;
USHORT Cpu;
/* Temp bootstrap code size */
#define AP_SPINUP_PAGE_COUNT 5
/* Check if at least one AP is present */
if(HlpSystemInfo.CpuCount > 1)
{
/* Save page map address in the bootstrap code */
ArBootstrapPageMap = ArReadControlRegister(3);
/* Allocate 5 pages for AP bootstrap code and ensure it is low memory */
Status = MmAllocateHardwareMemory(AP_SPINUP_PAGE_COUNT, FALSE, &ApPhysicalAddress);
if(Status != STATUS_SUCCESS || ApPhysicalAddress.QuadPart > (0x100000 - AP_SPINUP_PAGE_COUNT * MM_PAGE_SIZE))
{
/* Not enough free pages at low memory available, return error */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Map AP bootstrap code */
Status = MmMapHardwareMemory(ApPhysicalAddress, AP_SPINUP_PAGE_COUNT, TRUE, &ApVirtualAddress);
if(Status != STATUS_SUCCESS)
{
/* Failed to map AP bootstrap code, return error */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy AP bootstrap code into low memory */
RtlCopyMemory(ApVirtualAddress, &ArStartApplicationProcessor, AP_SPINUP_PAGE_COUNT * MM_PAGE_SIZE);
/* Iterate over all CPUs and start them */
for(Cpu = 0; Cpu < HlpSystemInfo.CpuCount; Cpu++)
{
/* Check if this CPU is the BSP */
if(HlpSystemInfo.CpuInfo[Cpu].ApicId == HlpGetCpuApicId())
{
/* This is the BSP, set proper flag and mark as started */
HlpSystemInfo.CpuInfo[Cpu].Bsp = TRUE;
HlpSystemInfo.CpuInfo[Cpu].Started = TRUE;
/* Continue with next CPU */
continue;
}
/* Temp debugging */
DebugPrint(L"Starting CPU #%lu (ACPI ID: %u, APIC ID: %u)\n", Cpu, HlpSystemInfo.CpuInfo[Cpu].AcpiId, HlpSystemInfo.CpuInfo[Cpu].ApicId);
/* Check if interrupts are enabled and disable them */
Interrupts = ArInterruptsEnabled();
ArClearInterruptFlag();
/* Start the AP */
Status = HlStartProcessor(HlpSystemInfo.CpuInfo[Cpu].ApicId, ApPhysicalAddress);
if(Status == STATUS_SUCCESS)
{
/* Mark AP as started */
HlpSystemInfo.CpuInfo[Cpu].Started = TRUE;
}
/* Check if interrupts were originally enabled */
if(Interrupts)
{
/* Re-enable interrupts */
ArSetInterruptFlag();
}
}
/* Unmap AP bootstrap code */
MmUnmapHardwareMemory(ApVirtualAddress, AP_SPINUP_PAGE_COUNT, TRUE);
}
/* Return success */
return STATUS_SUCCESS;
}