diff --git a/arch/x86_32/kernel.cpp b/arch/x86_32/kernel.cpp index fccddab..936c7b6 100755 --- a/arch/x86_32/kernel.cpp +++ b/arch/x86_32/kernel.cpp @@ -189,10 +189,6 @@ void MMArchFinalizeVAS(MMSpace *space) { KernelPanic("Unimplemented!\n"); } -void ArchStartupApplicationProcessors() { - // TODO. -} - bool MMArchHandlePageFault(uintptr_t address, uint32_t flags) { address &= ~(K_PAGE_SIZE - 1); bool forSupervisor = flags & MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR; diff --git a/arch/x86_32/kernel.s b/arch/x86_32/kernel.s index 05feeba..3f00a70 100644 --- a/arch/x86_32/kernel.s +++ b/arch/x86_32/kernel.s @@ -21,10 +21,12 @@ [global ProcessorFakeTimerInterrupt] [global ProcessorSetAddressSpace] [global ProcessorFlushCodeCache] +[global ProcessorAPStartup] [global GetLocalStorage] [global GetCurrentThread] [global ArchSwitchContext] [global processorGDTR] +[global gdt_data] [global timeStampCounterSynchronizationValue] [extern ArchNextTimer] @@ -551,3 +553,35 @@ ProcessorSetAddressSpace: ProcessorFlushCodeCache: wbinvd ret + +SynchronizeTimeStampCounter: + ; TODO + ret + +[bits 16] +ProcessorAPStartup: ; This function must be less than 4KB in length (see drivers/acpi.cpp) + mov ax,0x1000 + mov ds,ax + mov byte [0xFC0],1 ; Indicate we've started. + mov eax,[0xFF0] + mov cr3,eax + lgdt [0x1000 + gdt_data.gdt - gdt_data] + mov eax,cr0 + or eax,1 + mov cr0,eax + jmp 0x8:dword (.pmode - ProcessorAPStartup + 0x10000) +[bits 32] + .pmode: + mov eax,0x10 + mov ds,ax + mov es,ax + mov ss,ax + lgdt [gdt_data.gdt] + mov esp,[0x10FD0] + call SetupProcessor1 + call SynchronizeTimeStampCounter + mov edi,[0x10FB0] + push edi + call SetupProcessor2 + mov byte [0x10FC0],2 ; Indicate the BSP can start the next processor. + jmp ProcessorReady diff --git a/arch/x86_64/kernel.cpp b/arch/x86_64/kernel.cpp index 06695fe..cd2f149 100644 --- a/arch/x86_64/kernel.cpp +++ b/arch/x86_64/kernel.cpp @@ -62,15 +62,10 @@ struct MMArchVAS { uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)]; -extern "C" void gdt_data(); -extern "C" void processorGDTR(); - -extern "C" uint64_t ProcessorReadCR3(); extern "C" uintptr_t ProcessorGetRSP(); extern "C" uintptr_t ProcessorGetRBP(); extern "C" uint64_t ProcessorReadMXCSR(); extern "C" void ProcessorInstallTSS(uint32_t *gdt, uint32_t *tss); -extern "C" void ProcessorAPStartup(); extern "C" void SSSE3Framebuffer32To24Copy(volatile uint8_t *destination, volatile uint8_t *source, size_t pixelGroups); extern "C" uintptr_t _KThreadTerminate; @@ -655,105 +650,6 @@ EsError ArchApplyRelocation(uintptr_t type, uint8_t *buffer, uintptr_t offset, u return ES_SUCCESS; } -void ArchStartupApplicationProcessors() { - // TODO How do we know that this address is usable? -#define AP_TRAMPOLINE 0x10000 - - KEvent delay = {}; - - uint8_t *startupData = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE); - - // Put the trampoline code in memory. - EsMemoryCopy(startupData, (void *) ProcessorAPStartup, 0x1000); // Assume that the AP trampoline code <=4KB. - - // Put the paging table location at AP_TRAMPOLINE + 0xFF0. - *((uint64_t *) (startupData + 0xFF0)) = ProcessorReadCR3(); - - // Put the 64-bit GDTR at AP_TRAMPOLINE + 0xFE0. - EsMemoryCopy(startupData + 0xFE0, (void *) processorGDTR, 0x10); - - // Put the GDT at AP_TRAMPOLINE + 0x1000. - EsMemoryCopy(startupData + 0x1000, (void *) gdt_data, 0x1000); - - // Put the startup flag at AP_TRAMPOLINE + 0xFC0 - uint8_t volatile *startupFlag = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE + 0xFC0); - - // Temporarily identity map 2 pages in at 0x10000. - MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE, AP_TRAMPOLINE, MM_MAP_PAGE_COMMIT_TABLES_NOW); - MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE + 0x1000, AP_TRAMPOLINE + 0x1000, MM_MAP_PAGE_COMMIT_TABLES_NOW); - - for (uintptr_t i = 0; i < acpi.processorCount; i++) { - ArchCPU *processor = acpi.processors + i; - if (processor->bootProcessor) continue; - - // Allocate state for the processor. - NewProcessorStorage storage = AllocateNewProcessorStorage(processor); - - // Clear the startup flag. - *startupFlag = 0; - - // Put the stack at AP_TRAMPOLINE + 0xFD0, and the address of the NewProcessorStorage at AP_TRAMPOLINE + 0xFB0. - void *stack = (void *) ((uintptr_t) MMStandardAllocate(kernelMMSpace, 0x1000, MM_REGION_FIXED) + 0x1000); - *((void **) (startupData + 0xFD0)) = stack; - *((NewProcessorStorage **) (startupData + 0xFB0)) = &storage; - - KernelLog(LOG_INFO, "ACPI", "starting processor", "Starting processor %d with local storage %x...\n", i, storage.local); - - // Send an INIT IPI. - ProcessorDisableInterrupts(); // Don't be interrupted between writes... - LapicWriteRegister(0x310 >> 2, processor->apicID << 24); - LapicWriteRegister(0x300 >> 2, 0x4500); - ProcessorEnableInterrupts(); - KEventWait(&delay, 10); - - // Send a startup IPI. - ProcessorDisableInterrupts(); - LapicWriteRegister(0x310 >> 2, processor->apicID << 24); - LapicWriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); - ProcessorEnableInterrupts(); - for (uintptr_t i = 0; i < 100 && *startupFlag == 0; i++) KEventWait(&delay, 1); - - if (*startupFlag) { - // The processor started correctly. - } else { - // Send a startup IPI, again. - ProcessorDisableInterrupts(); - LapicWriteRegister(0x310 >> 2, processor->apicID << 24); - LapicWriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); - ProcessorEnableInterrupts(); - for (uintptr_t i = 0; i < 1000 && *startupFlag == 0; i++) KEventWait(&delay, 1); // Wait longer this time. - - if (*startupFlag) { - // The processor started correctly. - } else { - // The processor could not be started. - KernelLog(LOG_ERROR, "ACPI", "processor startup failure", - "ACPIInitialise - Could not start processor %d\n", processor->processorID); - continue; - } - } - - // EsPrint("Startup flag 1 reached!\n"); - - for (uintptr_t i = 0; i < 10000 && *startupFlag != 2; i++) KEventWait(&delay, 1); - - if (*startupFlag == 2) { - // The processor started! - } else { - // The processor did not report it completed initilisation, worringly. - // Don't let it continue. - - KernelLog(LOG_ERROR, "ACPI", "processor startup failure", - "ACPIInitialise - Could not initialise processor %d\n", processor->processorID); - - // TODO Send IPI to stop the processor. - } - } - - // Remove the identity pages needed for the trampoline code. - MMArchUnmapPages(kernelMMSpace, AP_TRAMPOLINE, 2, ES_FLAGS_DEFAULT); -} - #include #endif diff --git a/arch/x86_pc.cpp b/arch/x86_pc.cpp index 5641cf1..1ae7686 100644 --- a/arch/x86_pc.cpp +++ b/arch/x86_pc.cpp @@ -2,6 +2,10 @@ extern "C" uint64_t ProcessorReadCR3(); +extern "C" void gdt_data(); +extern "C" void processorGDTR(); +extern "C" void ProcessorAPStartup(); + struct MSIHandler { KIRQHandler callback; void *context; @@ -576,7 +580,7 @@ uintptr_t ArchFindRootSystemDescriptorPointer() { } uint64_t ArchGetTimeFromPITMs() { - // TODO This isn't working on real hardware, but ArchDelay1Ms is? + // TODO This isn't working on real hardware, but EarlyDelay1Ms is? // NOTE This will only work if called at least once every 50 ms. // (The PIT only stores a 16-bit counter, which is depleted every 50 ms.) @@ -602,7 +606,7 @@ uint64_t ArchGetTimeFromPITMs() { } } -void ArchDelay1Ms() { +void EarlyDelay1Ms() { ProcessorOut8(IO_PIT_COMMAND, 0x30); ProcessorOut8(IO_PIT_DATA, 0xA9); ProcessorOut8(IO_PIT_DATA, 0x04); @@ -693,7 +697,7 @@ void ArchInitialise() { ProcessorDisableInterrupts(); uint64_t start = ProcessorReadTimeStamp(); LapicWriteRegister(0x380 >> 2, (uint32_t) -1); - for (int i = 0; i < 8; i++) ArchDelay1Ms(); // Average over 8ms + for (int i = 0; i < 8; i++) EarlyDelay1Ms(); // Average over 8ms acpi.lapicTicksPerMs = ((uint32_t) -1 - LapicReadRegister(0x390 >> 2)) >> 4; EsRandomAddEntropy(LapicReadRegister(0x390 >> 2)); uint64_t end = ProcessorReadTimeStamp(); @@ -988,3 +992,102 @@ bool KRegisterIRQ(intptr_t line, KIRQHandler handler, void *context, const char return true; } + +void ArchStartupApplicationProcessors() { + // TODO How do we know that this address is usable? +#define AP_TRAMPOLINE 0x10000 + + KEvent delay = {}; + + uint8_t *startupData = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE); + + // Put the trampoline code in memory. + EsMemoryCopy(startupData, (void *) ProcessorAPStartup, 0x1000); // Assume that the AP trampoline code <=4KB. + + // Put the paging table location at AP_TRAMPOLINE + 0xFF0. + *((uint64_t *) (startupData + 0xFF0)) = ProcessorReadCR3(); + + // Put the 64-bit GDTR at AP_TRAMPOLINE + 0xFE0. + EsMemoryCopy(startupData + 0xFE0, (void *) processorGDTR, 0x10); + + // Put the GDT at AP_TRAMPOLINE + 0x1000. + EsMemoryCopy(startupData + 0x1000, (void *) gdt_data, 0x1000); + + // Put the startup flag at AP_TRAMPOLINE + 0xFC0 + uint8_t volatile *startupFlag = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE + 0xFC0); + + // Temporarily identity map 2 pages in at 0x10000. + MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE, AP_TRAMPOLINE, MM_MAP_PAGE_COMMIT_TABLES_NOW); + MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE + 0x1000, AP_TRAMPOLINE + 0x1000, MM_MAP_PAGE_COMMIT_TABLES_NOW); + + for (uintptr_t i = 0; i < acpi.processorCount; i++) { + ArchCPU *processor = acpi.processors + i; + if (processor->bootProcessor) continue; + + // Allocate state for the processor. + NewProcessorStorage storage = AllocateNewProcessorStorage(processor); + + // Clear the startup flag. + *startupFlag = 0; + + // Put the stack at AP_TRAMPOLINE + 0xFD0, and the address of the NewProcessorStorage at AP_TRAMPOLINE + 0xFB0. + void *stack = (void *) ((uintptr_t) MMStandardAllocate(kernelMMSpace, 0x1000, MM_REGION_FIXED) + 0x1000); + *((void **) (startupData + 0xFD0)) = stack; + *((NewProcessorStorage **) (startupData + 0xFB0)) = &storage; + + KernelLog(LOG_INFO, "ACPI", "starting processor", "Starting processor %d with local storage %x...\n", i, storage.local); + + // Send an INIT IPI. + ProcessorDisableInterrupts(); // Don't be interrupted between writes... + LapicWriteRegister(0x310 >> 2, processor->apicID << 24); + LapicWriteRegister(0x300 >> 2, 0x4500); + ProcessorEnableInterrupts(); + KEventWait(&delay, 10); + + // Send a startup IPI. + ProcessorDisableInterrupts(); + LapicWriteRegister(0x310 >> 2, processor->apicID << 24); + LapicWriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); + ProcessorEnableInterrupts(); + for (uintptr_t i = 0; i < 100 && *startupFlag == 0; i++) KEventWait(&delay, 1); + + if (*startupFlag) { + // The processor started correctly. + } else { + // Send a startup IPI, again. + ProcessorDisableInterrupts(); + LapicWriteRegister(0x310 >> 2, processor->apicID << 24); + LapicWriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); + ProcessorEnableInterrupts(); + for (uintptr_t i = 0; i < 1000 && *startupFlag == 0; i++) KEventWait(&delay, 1); // Wait longer this time. + + if (*startupFlag) { + // The processor started correctly. + } else { + // The processor could not be started. + KernelLog(LOG_ERROR, "ACPI", "processor startup failure", + "ACPIInitialise - Could not start processor %d\n", processor->processorID); + continue; + } + } + + // EsPrint("Startup flag 1 reached!\n"); + + for (uintptr_t i = 0; i < 10000 && *startupFlag != 2; i++) KEventWait(&delay, 1); + + if (*startupFlag == 2) { + // The processor started! + } else { + // The processor did not report it completed initilisation, worringly. + // Don't let it continue. + + KernelLog(LOG_ERROR, "ACPI", "processor startup failure", + "ACPIInitialise - Could not initialise processor %d\n", processor->processorID); + + // TODO Send IPI to stop the processor. + } + } + + // Remove the identity pages needed for the trampoline code. + MMArchUnmapPages(kernelMMSpace, AP_TRAMPOLINE, 2, ES_FLAGS_DEFAULT); +} diff --git a/arch/x86_pc.h b/arch/x86_pc.h index 2a04f5a..6e5a5b6 100644 --- a/arch/x86_pc.h +++ b/arch/x86_pc.h @@ -86,7 +86,6 @@ uint32_t LapicReadRegister(uint32_t reg); void LapicWriteRegister(uint32_t reg, uint32_t value); NewProcessorStorage AllocateNewProcessorStorage(struct ArchCPU *archCPU); extern "C" void SetupProcessor2(struct NewProcessorStorage *); -void ArchDelay1Ms(); // Spin for approximately 1ms. Use only during initialisation. Not thread-safe. uint64_t ArchGetTimeFromPITMs(); void *ACPIGetRSDP(); size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi = false, int processorID = -1); // Returns the number of processors the IPI was *not* sent to. diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index 0470a45..31106b4 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -785,7 +785,6 @@ void Thread::SetAddressSpace(MMSpace *space) { KSpinlockAcquire(&scheduler.lock); MMSpace *oldSpace = temporaryAddressSpace ?: kernelMMSpace; - EsPrint("space = %x, oldSpace = %x\n", space, oldSpace); temporaryAddressSpace = space; MMSpace *newSpace = space ?: kernelMMSpace; MMSpaceOpenReference(newSpace);