/** * 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 */ #include /** * 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; } 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) { /* 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; }