166 lines
5.1 KiB
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;
|
|
}
|