mirror of https://gitlab.com/nakst/essence
move ArchStartupApplicationProcessors to x86_pc.cpp
This commit is contained in:
parent
ed038d1059
commit
cd51bf4d6c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <kernel/terminal.cpp>
|
||||
|
||||
#endif
|
||||
|
|
109
arch/x86_pc.cpp
109
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue