mirror of https://gitlab.com/nakst/essence
kernel cleanup 3
This commit is contained in:
parent
7a0b832c36
commit
3ca9b4724b
243
drivers/acpi.cpp
243
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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue