diff --git a/drivers/acpi.cpp b/drivers/acpi.cpp index caad73a..7c66ded 100644 --- a/drivers/acpi.cpp +++ b/drivers/acpi.cpp @@ -98,23 +98,6 @@ void ACPIIoApicWriteRegister(ACPIIoApic *apic, uint32_t reg, uint32_t value) { apic->address[4] = value; } -uint32_t ACPILapicReadRegister(uint32_t reg) { - return acpi.lapicAddress[reg]; -} - -void ACPILapicWriteRegister(uint32_t reg, uint32_t value) { - acpi.lapicAddress[reg] = value; -} - -void ACPILapicNextTimer(size_t ms) { - ACPILapicWriteRegister(0x320 >> 2, TIMER_INTERRUPT | (1 << 17)); - ACPILapicWriteRegister(0x380 >> 2, acpi.lapicTicksPerMs * ms); -} - -void ACPILapicEndOfInterrupt() { - ACPILapicWriteRegister(0xB0 >> 2, 0); -} - void ACPICheckTable(const ACPIDescriptorTable *table) { if (!EsMemorySumBytes((uint8_t *) table, table->length)) { return; @@ -126,71 +109,15 @@ void ACPICheckTable(const ACPIDescriptorTable *table) { table->oemRevision, 4, &table->creatorID, table->creatorRevision); } -#ifdef ARCH_X86_COMMON -uint64_t ArchGetTimeMs() { - // Update the time stamp counter synchronization value. - timeStampCounterSynchronizationValue = ((timeStampCounterSynchronizationValue & 0x8000000000000000) - ^ 0x8000000000000000) | ProcessorReadTimeStamp(); - - if (acpi.hpetBaseAddress && acpi.hpetPeriod) { - __int128 fsToMs = 1000000000000; - __int128 reading = acpi.hpetBaseAddress[30]; - return (uint64_t) (reading * (__int128) acpi.hpetPeriod / fsToMs); - } else { - return ArchGetTimeFromPITMs(); - } -} - -RootSystemDescriptorPointer *ACPIFindRootSystemDescriptorPointer() { - PhysicalMemoryRegion searchRegions[2]; - - searchRegions[0].baseAddress = (uintptr_t) (((uint16_t *) LOW_MEMORY_MAP_START)[0x40E] << 4) + LOW_MEMORY_MAP_START; - searchRegions[0].pageCount = 0x400; - searchRegions[1].baseAddress = (uintptr_t) 0xE0000 + LOW_MEMORY_MAP_START; - searchRegions[1].pageCount = 0x20000; - - for (uintptr_t i = 0; i < 2; i++) { - for (uintptr_t address = searchRegions[i].baseAddress; - address < searchRegions[i].baseAddress + searchRegions[i].pageCount; - address += 16) { - RootSystemDescriptorPointer *rsdp = (RootSystemDescriptorPointer *) address; - - if (rsdp->signature != SIGNATURE_RSDP) { - continue; - } - - if (rsdp->revision == 0) { - if (EsMemorySumBytes((uint8_t *) rsdp, 20)) { - continue; - } - - return rsdp; - } else if (rsdp->revision == 2) { - if (EsMemorySumBytes((uint8_t *) rsdp, sizeof(RootSystemDescriptorPointer))) { - continue; - } - - return rsdp; - } - } - } - - return nullptr; -} -#endif - void *ACPIMapPhysicalMemory(uintptr_t physicalAddress, size_t length) { -#ifdef ARCH_X86_COMMON - if ((uintptr_t) physicalAddress + (uintptr_t) length < (uintptr_t) LOW_MEMORY_LIMIT) { - return (void *) (LOW_MEMORY_MAP_START + physicalAddress); - } -#endif - - void *address = MMMapPhysical(kernelMMSpace, physicalAddress, length, MM_REGION_NOT_CACHEABLE); - return address; + return MMMapPhysical(kernelMMSpace, physicalAddress, length, MM_REGION_NOT_CACHEABLE); } void KPS2SafeToInitialise() { + // This is only called when either: + // - the PCI driver determines there are no USB controllers + // - the USB controller disables USB emulation + // TODO Qemu sets this to true? #if 0 if (acpi.ps2ControllerUnavailable) { @@ -198,10 +125,9 @@ void KPS2SafeToInitialise() { } #endif - // This is only called when either: - // - the PCI driver determines there are no USB controllers - // - the USB controller disables USB emulation - KThreadCreate("InitPS2", [] (uintptr_t) { KDeviceAttachByName(acpi.computer, "PS2"); }); + KThreadCreate("InitPS2", [] (uintptr_t) { + KDeviceAttachByName(acpi.computer, "PS2"); + }); } void *ACPIGetRSDP() { @@ -212,14 +138,8 @@ uint8_t ACPIGetCenturyRegisterIndex() { return acpi.centuryRegisterIndex; } -void ArchInitialise() { - uint64_t uefiRSDP = *((uint64_t *) (LOW_MEMORY_MAP_START + GetBootloaderInformationOffset() + 0x7FE8)); - - if (!uefiRSDP) { - acpi.rsdp = ACPIFindRootSystemDescriptorPointer(); - } else { - acpi.rsdp = (RootSystemDescriptorPointer *) MMMapPhysical(kernelMMSpace, (uintptr_t) uefiRSDP, 16384, ES_FLAGS_DEFAULT); - } +void ACPIParseTables() { + acpi.rsdp = (RootSystemDescriptorPointer *) MMMapPhysical(kernelMMSpace, ArchFindRootSystemDescriptorPointer(), 16384, ES_FLAGS_DEFAULT); ACPIDescriptorTable *madtHeader = nullptr; ACPIDescriptorTable *sdt = nullptr; @@ -315,8 +235,6 @@ void ArchInitialise() { MMFree(kernelMMSpace, header); } - // Set up the APIC. - MultipleAPICDescriptionTable *madt = (MultipleAPICDescriptionTable *) ((uint8_t *) madtHeader + ACPI_DESCRIPTOR_TABLE_HEADER_LENGTH); if (!madt) { @@ -391,143 +309,6 @@ void ArchInitialise() { " and LAPIC NMIs (%d/%d)\n", acpi.processorCount, 256, acpi.ioapicCount, 16, acpi.interruptOverrideCount, 256, acpi.lapicNMICount, 32); } - - uint8_t bootstrapLapicID = (ACPILapicReadRegister(0x20 >> 2) >> 24); - - ArchCPU *currentCPU = nullptr; - - for (uintptr_t i = 0; i < acpi.processorCount; i++) { - if (acpi.processors[i].apicID == bootstrapLapicID) { - // That's us! - currentCPU = acpi.processors + i; - currentCPU->bootProcessor = true; - break; - } - } - - if (!currentCPU) { - KernelPanic("ACPIInitialise - Could not find the bootstrap processor\n"); - } - - // Calibrate the LAPIC's timer and processor's timestamp counter. - ProcessorDisableInterrupts(); - uint64_t start = ProcessorReadTimeStamp(); - ACPILapicWriteRegister(0x380 >> 2, (uint32_t) -1); - for (int i = 0; i < 8; i++) ArchDelay1Ms(); // Average over 8ms - acpi.lapicTicksPerMs = ((uint32_t) -1 - ACPILapicReadRegister(0x390 >> 2)) >> 4; - EsRandomAddEntropy(ACPILapicReadRegister(0x390 >> 2)); - uint64_t end = ProcessorReadTimeStamp(); - timeStampTicksPerMs = (end - start) >> 3; - ProcessorEnableInterrupts(); - // EsPrint("timeStampTicksPerMs = %d\n", timeStampTicksPerMs); - - // Finish processor initialisation. - // This sets up interrupts, the timer, CPULocalStorage, the GDT and TSS, - // and registers the processor with the scheduler. - - NewProcessorStorage storage = AllocateNewProcessorStorage(currentCPU); - SetupProcessor2(&storage); -} - -void ACPIStartupApplicationProcessors() { -#ifdef USE_SMP - // 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... - ACPILapicWriteRegister(0x310 >> 2, processor->apicID << 24); - ACPILapicWriteRegister(0x300 >> 2, 0x4500); - ProcessorEnableInterrupts(); - KEventWait(&delay, 10); - - // Send a startup IPI. - ProcessorDisableInterrupts(); - ACPILapicWriteRegister(0x310 >> 2, processor->apicID << 24); - ACPILapicWriteRegister(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(); - ACPILapicWriteRegister(0x310 >> 2, processor->apicID << 24); - ACPILapicWriteRegister(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); -#endif } size_t KGetCPUCount() { @@ -558,7 +339,9 @@ void ACPIDeviceAttach(KDevice *parentDevice) { #ifdef USE_ACPICA ACPICAInitialise(); #endif - ACPIStartupApplicationProcessors(); +#ifdef USE_SMP + ArchStartupApplicationProcessors(); +#endif }); if (!acpi.vgaControllerUnavailable) { diff --git a/drivers/acpica.cpp b/drivers/acpica.cpp index ea6956f..0a47b24 100644 --- a/drivers/acpica.cpp +++ b/drivers/acpica.cpp @@ -36,16 +36,7 @@ ES_EXTERN_C ACPI_STATUS AcpiOsTerminate() { } ES_EXTERN_C ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer() { - ACPI_PHYSICAL_ADDRESS address = 0; - - uint64_t uefiRSDP = *((uint64_t *) (LOW_MEMORY_MAP_START + GetBootloaderInformationOffset() + 0x7FE8)); - - if (uefiRSDP) { - return uefiRSDP; - } - - AcpiFindRootPointer(&address); - return address; + return ArchFindRootSystemDescriptorPointer(); } ES_EXTERN_C ACPI_STATUS AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *predefinedObject, ACPI_STRING *newValue) { @@ -72,12 +63,6 @@ ES_EXTERN_C void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS physicalAddress, ACPI_SI } ES_EXTERN_C void AcpiOsUnmapMemory(void *address, ACPI_SIZE length) { -#ifdef ARCH_X86_COMMON - if ((uintptr_t) address - (uintptr_t) LOW_MEMORY_MAP_START < (uintptr_t) LOW_MEMORY_LIMIT) { - return; - } -#endif - (void) length; MMFree(kernelMMSpace, address); } diff --git a/kernel/kernel.h b/kernel/kernel.h index 64809f7..051136f 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -174,7 +174,7 @@ extern "C" { // - MM_CORE_REGIONS_START and MM_CORE_REGIONS_COUNT. // - MM_KERNEL_SPACE_START and MM_KERNEL_SPACE_SIZE. // - MM_MODULES_START and MM_MODULES_SIZE. - // - ArchCheckBundleHeader, ArchCheckELFHeader and ArchIsAddressInKernelSpace. + // - ArchCheckBundleHeader and ArchCheckELFHeader. // - K_ARCH_STACK_GROWS_DOWN or K_ARCH_STACK_GROWS_UP. // - K_ARCH_NAME. } diff --git a/kernel/x86_64.cpp b/kernel/x86_64.cpp index e76a3fe..28689d9 100644 --- a/kernel/x86_64.cpp +++ b/kernel/x86_64.cpp @@ -37,7 +37,6 @@ struct MMArchVAS { #define ArchCheckBundleHeader() (header.mapAddress > 0x800000000000UL || header.mapAddress < 0x1000 || fileSize > 0x1000000000000UL) #define ArchCheckELFHeader() (header->virtualAddress > 0x800000000000UL || header->virtualAddress < 0x1000 || header->segmentSize > 0x1000000000000UL) -#define ArchIsAddressInKernelSpace(x) ((uintptr_t) (x) >= 0xFFFF800000000000) #define K_ARCH_STACK_GROWS_DOWN #define K_ARCH_NAME "x86_64" @@ -50,6 +49,8 @@ struct MMArchVAS { #define MM_CORE_SPACE_SIZE (0xFFFF8001F0000000 - 0xFFFF800100000000) #define MM_USER_SPACE_START (0x100000000000) #define MM_USER_SPACE_SIZE (0xF00000000000 - 0x100000000000) +#define LOW_MEMORY_MAP_START (0xFFFFFE0000000000) +#define LOW_MEMORY_LIMIT (0x100000000) // The first 4GB is mapped here. struct MSIHandler { KIRQHandler callback; @@ -96,6 +97,23 @@ volatile uintptr_t callFunctionOnAllProcessorsRemaining; #define ENTRIES_PER_PAGE_TABLE (512) #define ENTRIES_PER_PAGE_TABLE_BITS (9) +uint32_t LapicReadRegister(uint32_t reg) { + return acpi.lapicAddress[reg]; +} + +void LapicWriteRegister(uint32_t reg, uint32_t value) { + acpi.lapicAddress[reg] = value; +} + +void LapicNextTimer(size_t ms) { + LapicWriteRegister(0x320 >> 2, TIMER_INTERRUPT | (1 << 17)); + LapicWriteRegister(0x380 >> 2, acpi.lapicTicksPerMs * ms); +} + +void LapicEndOfInterrupt() { + LapicWriteRegister(0xB0 >> 2, 0); +} + void ArchSetPCIIRQLine(uint8_t slot, uint8_t pin, uint8_t line) { pciIRQLines[slot][pin] = line; } @@ -207,8 +225,7 @@ bool MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualA uintptr_t cr3 = space->data.cr3; - if (!ArchIsAddressInKernelSpace(virtualAddress) - && ProcessorReadCR3() != cr3) { + if (virtualAddress < 0xFFFF800000000000 && ProcessorReadCR3() != cr3) { KernelPanic("MMArchMapPage - Attempt to map page into other address space.\n"); } else if (!physicalAddress) { KernelPanic("MMArchMapPage - Attempt to map physical page 0.\n"); @@ -331,7 +348,7 @@ bool MMArchHandlePageFault(uintptr_t address, uint32_t flags) { } if (address < K_PAGE_SIZE) { - } else if (address >= LOW_MEMORY_MAP_START && address < LOW_MEMORY_MAP_START + 0x100000000 && forSupervisor) { + } else if (address >= LOW_MEMORY_MAP_START && address < LOW_MEMORY_MAP_START + LOW_MEMORY_LIMIT && forSupervisor) { // We want to access a physical page within the first 4GB. // This is used for device IO, so the page can't be cacheable. MMArchMapPage(kernelMMSpace, address - LOW_MEMORY_MAP_START, address, MM_MAP_PAGE_NOT_CACHEABLE | MM_MAP_PAGE_COMMIT_TABLES_NOW); @@ -843,11 +860,11 @@ size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi, int processorID) { uint32_t destination = acpi.processors[i].apicID << 24; uint32_t command = interrupt | (1 << 14) | (nmi ? 0x400 : 0); - ACPILapicWriteRegister(0x310 >> 2, destination); - ACPILapicWriteRegister(0x300 >> 2, command); + LapicWriteRegister(0x310 >> 2, destination); + LapicWriteRegister(0x300 >> 2, command); // Wait for the interrupt to be sent. - while (ACPILapicReadRegister(0x300 >> 2) & (1 << 12)); + while (LapicReadRegister(0x300 >> 2) & (1 << 12)); } return ignored; @@ -864,7 +881,7 @@ void ProcessorSendYieldIPI(Thread *thread) { void ArchNextTimer(size_t ms) { while (!scheduler.started); // Wait until the scheduler is ready. GetLocalStorage()->schedulerReady = true; // Make sure this CPU can be scheduled. - ACPILapicNextTimer(ms); // Set the next timer. + LapicNextTimer(ms); // Set the next timer. } NewProcessorStorage AllocateNewProcessorStorage(ArchCPU *archCPU) { @@ -888,19 +905,19 @@ void SetupProcessor2(NewProcessorStorage *storage) { uint32_t value = 2 | (1 << 10); // NMI exception interrupt vector. if (acpi.lapicNMIs[i].activeLow) value |= 1 << 13; if (acpi.lapicNMIs[i].levelTriggered) value |= 1 << 15; - ACPILapicWriteRegister(registerIndex, value); + LapicWriteRegister(registerIndex, value); } } - ACPILapicWriteRegister(0x350 >> 2, ACPILapicReadRegister(0x350 >> 2) & ~(1 << 16)); - ACPILapicWriteRegister(0x360 >> 2, ACPILapicReadRegister(0x360 >> 2) & ~(1 << 16)); - ACPILapicWriteRegister(0x080 >> 2, 0); - if (ACPILapicReadRegister(0x30 >> 2) & 0x80000000) ACPILapicWriteRegister(0x410 >> 2, 0); - ACPILapicEndOfInterrupt(); + LapicWriteRegister(0x350 >> 2, LapicReadRegister(0x350 >> 2) & ~(1 << 16)); + LapicWriteRegister(0x360 >> 2, LapicReadRegister(0x360 >> 2) & ~(1 << 16)); + LapicWriteRegister(0x080 >> 2, 0); + if (LapicReadRegister(0x30 >> 2) & 0x80000000) LapicWriteRegister(0x410 >> 2, 0); + LapicEndOfInterrupt(); // Configure the LAPIC's timer. - ACPILapicWriteRegister(0x3E0 >> 2, 2); // Divisor = 16 + LapicWriteRegister(0x3E0 >> 2, 2); // Divisor = 16 // Create the processor's local storage. @@ -1136,7 +1153,7 @@ extern "C" void InterruptHandler(InterruptContext *context) { __sync_fetch_and_sub(&callFunctionOnAllProcessorsRemaining, 1); } - ACPILapicEndOfInterrupt(); + LapicEndOfInterrupt(); } else if (interrupt >= INTERRUPT_VECTOR_MSI_START && interrupt < INTERRUPT_VECTOR_MSI_START + INTERRUPT_VECTOR_MSI_COUNT && local) { KSpinlockAcquire(&irqHandlersLock); MSIHandler handler = msiHandlers[interrupt - INTERRUPT_VECTOR_MSI_START]; @@ -1149,7 +1166,7 @@ extern "C" void InterruptHandler(InterruptContext *context) { handler.callback(interrupt - INTERRUPT_VECTOR_MSI_START, handler.context); } - ACPILapicEndOfInterrupt(); + LapicEndOfInterrupt(); if (local->irqSwitchThread && scheduler.started && local->schedulerReady) { scheduler.Yield(context); @@ -1209,7 +1226,7 @@ extern "C" void InterruptHandler(InterruptContext *context) { GetLocalStorage()->inIRQ = false; } - ACPILapicEndOfInterrupt(); + LapicEndOfInterrupt(); if (local->irqSwitchThread && scheduler.started && local->schedulerReady) { scheduler.Yield(context); @@ -1241,7 +1258,7 @@ extern "C" bool PostContextSwitch(InterruptContext *context, MMSpace *oldAddress KernelLog(LOG_VERBOSE, "Arch", "executing new thread", "Executing new thread %x at %x\n", currentThread, context->rip); } - ACPILapicEndOfInterrupt(); + LapicEndOfInterrupt(); ContextSanityCheck(context); if (ProcessorAreInterruptsEnabled()) { @@ -1361,4 +1378,200 @@ uintptr_t MMArchGetPhysicalMemoryHighest() { return physicalMemoryHighest; } +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); +} + +uint64_t ArchGetTimeMs() { + // Update the time stamp counter synchronization value. + timeStampCounterSynchronizationValue = ((timeStampCounterSynchronizationValue & 0x8000000000000000) + ^ 0x8000000000000000) | ProcessorReadTimeStamp(); + + if (acpi.hpetBaseAddress && acpi.hpetPeriod) { + __int128 fsToMs = 1000000000000; + __int128 reading = acpi.hpetBaseAddress[30]; + return (uint64_t) (reading * (__int128) acpi.hpetPeriod / fsToMs); + } else { + return ArchGetTimeFromPITMs(); + } +} + +uintptr_t ArchFindRootSystemDescriptorPointer() { + uint64_t uefiRSDP = *((uint64_t *) (LOW_MEMORY_MAP_START + GetBootloaderInformationOffset() + 0x7FE8)); + + if (uefiRSDP) { + return uefiRSDP; + } + + PhysicalMemoryRegion searchRegions[2]; + + searchRegions[0].baseAddress = (uintptr_t) (((uint16_t *) LOW_MEMORY_MAP_START)[0x40E] << 4) + LOW_MEMORY_MAP_START; + searchRegions[0].pageCount = 0x400; + searchRegions[1].baseAddress = (uintptr_t) 0xE0000 + LOW_MEMORY_MAP_START; + searchRegions[1].pageCount = 0x20000; + + for (uintptr_t i = 0; i < 2; i++) { + for (uintptr_t address = searchRegions[i].baseAddress; + address < searchRegions[i].baseAddress + searchRegions[i].pageCount; + address += 16) { + RootSystemDescriptorPointer *rsdp = (RootSystemDescriptorPointer *) address; + + if (rsdp->signature != SIGNATURE_RSDP) { + continue; + } + + if (rsdp->revision == 0) { + if (EsMemorySumBytes((uint8_t *) rsdp, 20)) { + continue; + } + + return (uintptr_t) rsdp - LOW_MEMORY_MAP_START; + } else if (rsdp->revision == 2) { + if (EsMemorySumBytes((uint8_t *) rsdp, sizeof(RootSystemDescriptorPointer))) { + continue; + } + + return (uintptr_t) rsdp - LOW_MEMORY_MAP_START; + } + } + } + + return 0; +} + +void ArchInitialise() { + ACPIParseTables(); + + uint8_t bootstrapLapicID = (LapicReadRegister(0x20 >> 2) >> 24); + + ArchCPU *currentCPU = nullptr; + + for (uintptr_t i = 0; i < acpi.processorCount; i++) { + if (acpi.processors[i].apicID == bootstrapLapicID) { + // That's us! + currentCPU = acpi.processors + i; + currentCPU->bootProcessor = true; + break; + } + } + + if (!currentCPU) { + KernelPanic("ACPIInitialise - Could not find the bootstrap processor\n"); + } + + // Calibrate the LAPIC's timer and processor's timestamp counter. + ProcessorDisableInterrupts(); + uint64_t start = ProcessorReadTimeStamp(); + LapicWriteRegister(0x380 >> 2, (uint32_t) -1); + for (int i = 0; i < 8; i++) ArchDelay1Ms(); // Average over 8ms + acpi.lapicTicksPerMs = ((uint32_t) -1 - LapicReadRegister(0x390 >> 2)) >> 4; + EsRandomAddEntropy(LapicReadRegister(0x390 >> 2)); + uint64_t end = ProcessorReadTimeStamp(); + timeStampTicksPerMs = (end - start) >> 3; + ProcessorEnableInterrupts(); + // EsPrint("timeStampTicksPerMs = %d\n", timeStampTicksPerMs); + + // Finish processor initialisation. + // This sets up interrupts, the timer, CPULocalStorage, the GDT and TSS, + // and registers the processor with the scheduler. + + NewProcessorStorage storage = AllocateNewProcessorStorage(currentCPU); + SetupProcessor2(&storage); +} + #endif diff --git a/kernel/x86_64.h b/kernel/x86_64.h index 17f1195..5363ad4 100644 --- a/kernel/x86_64.h +++ b/kernel/x86_64.h @@ -1,9 +1,6 @@ #ifndef ARCH_X86_64_HEADER #define ARCH_X86_64_HEADER -#define LOW_MEMORY_MAP_START (0xFFFFFE0000000000) -#define LOW_MEMORY_LIMIT (0x100000) // The first 1MB is mapped here. - // --------------------------------- Standardised IO ports. #define IO_PIC_1_COMMAND (0x0020) @@ -108,6 +105,8 @@ void *ACPIGetRSDP(); uint8_t ACPIGetCenturyRegisterIndex(); size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi = false, int processorID = -1); // Returns the number of processors the IPI was *not* sent to. void ArchSetPCIIRQLine(uint8_t slot, uint8_t pin, uint8_t line); +uintptr_t ArchFindRootSystemDescriptorPointer(); +void ArchStartupApplicationProcessors(); struct InterruptContext { uint64_t cr2, ds; diff --git a/kernel/x86_64.s b/kernel/x86_64.s index 0a4518e..bf7703a 100644 --- a/kernel/x86_64.s +++ b/kernel/x86_64.s @@ -412,22 +412,20 @@ EnableAPIC: ; Since we're on AMD64, we know that the APIC will be present. mov ecx,0x1B rdmsr + or eax,0x800 + wrmsr and eax,~0xFFF mov edi,eax - test eax,1 << 8 - jne $ - or eax,0x900 - wrmsr ; Set the spurious interrupt vector to 0xFF - mov rax,0xFFFFFE00000000F0 + mov rax,0xFFFFFE00000000F0 ; LOW_MEMORY_MAP_START + 0xF0 add rax,rdi mov ebx,[rax] or ebx,0x1FF mov [rax],ebx ; Use the flat processor addressing model - mov rax,0xFFFFFE00000000E0 + mov rax,0xFFFFFE00000000E0 ; LOW_MEMORY_MAP_START + 0xE0 add rax,rdi mov dword [rax],0xFFFFFFFF