Hallo zusammen,
habe mir mal ein wenig Code zusammen gebastelt, um die AP-Prozessoren zu starten.
Leider bekomme ich bei den IPIs immer Fehlercodes zurück.
Hier ist meine LAPIC-Initialisierung des BSP:
static __inline int __MaskLVT(ApicRegister i_register) {
UInt32 value;
int retval = CPU_ApicRead(i_register, &value);
if (ESuccess != retval)
return retval;
return CPU_ApicWrite(i_register, value | (1 << 16));
}
static __inline int __CleanLApic() {
UInt32 maxLvt;
int retval = CPU_ApicRead(LocalApicVersion, &maxLvt);
if (ESuccess != retval)
return retval;
maxLvt = (maxLvt >> 16) & 0xff;
if (3 <= maxLvt) {
retval = CPU_ApicWrite(LvtError, 0xfe | (1 << 16));
if (ESuccess != retval)
return retval;
}
retval = __MaskLVT(LvtTimer);
if (ESuccess != retval)
return retval;
retval = __MaskLVT(LvtLInt0);
if (ESuccess != retval)
return retval;
retval = __MaskLVT(LvtLInt1);
if (ESuccess != retval)
return retval;
if (4 <= maxLvt) {
retval = __MaskLVT(LvtPerformanceMonitoringCounters);
if (ESuccess != retval)
return retval;
}
retval = CPU_ApicWrite(LvtTimer, 1 << 16);
if (ESuccess != retval)
return retval;
retval = CPU_ApicWrite(LvtLInt0, 1 << 16);
if (ESuccess != retval)
return retval;
retval = CPU_ApicWrite(LvtLInt1, 1 << 16);
if (ESuccess != retval)
return retval;
if (3 <= maxLvt) {
retval = CPU_ApicWrite(LvtError, 1 << 16);
if (ESuccess != retval)
return retval;
}
if (4 <= maxLvt) {
retval = CPU_ApicWrite(LvtPerformanceMonitoringCounters, 1 << 16);
if (ESuccess != retval)
return retval;
}
return ESuccess;
}
static __inline int __InitializeLogicDestination() {
UInt32 value;
int retval = CPU_ApicWrite(DestinationFormat, 0xffffffff);
if (ESuccess != retval)
return retval;
retval = CPU_ApicRead(LogicalDestination, &value);
if (ESuccess != retval)
return retval;
value &= ~(0xff << 24);
UInt32 cpuId;
retval = CPU_GetProcessorId(&cpuId);
if (ESuccess != retval)
return retval;
value |= ((1 << cpuId) << 24);
return CPU_ApicWrite(LogicalDestination, value);
}
int CPU_ApicInitialize() {
UInt32 value;
/* disable the PIC */
CPU_IOPortWriteByte(0xa1, 0xff);
CPU_IOPortWriteByte(0x21, 0xff);
int retval = __CleanLApic();
if (ESuccess != retval)
return retval;
retval = __InitializeLogicDestination();
if (ESuccess != retval)
return retval;
/* set the task priority */
retval = CPU_ApicRead(TaskPriority, &value);
if (ESuccess != retval)
return retval;
value &= ~0xff;
retval = CPU_ApicWrite(TaskPriority, value);
if (ESuccess != retval)
return retval;
/* all done - activate the lapic */
retval = CPU_ApicRead(SpuriousInterruptVector, &value);
if (ESuccess != retval)
return retval;
value &= ~0xff;
value |= (1 << 8) | 0xff;
retval = CPU_ApicWrite(SpuriousInterruptVector, value);
if (ESuccess != retval)
return retval;
return ESuccess;
}
Wenn ich über das MSR prüfe, ob die LAPIC aktiv ist, bekomme ich auch eine positive Rückmeldung.
Hier mein SMP-Init-Code (dabei verwende ich INIT-INIT-STARTUP):
static __inline int __BootApplicationProcessor(UInt16 i_cpuCount, UInt32 i_stacks[]) {
UIntPtr size = (UIntPtr)__trampoline_smp_end - (UIntPtr)__trampoline_smp_start;
UInt32* stackPtr = (UInt32*)(0x7000 + size - 8);
UInt8 acpis[i_cpuCount];
UInt32 status;
int retval = ACPI_GetProcessorInformation(acpis);
if (ESuccess != retval) {
KLog(Error, "Unable to get processor information: %d\n", retval);
return retval;
}
UInt32 ownId;
retval = CPU_GetProcessorId(&ownId);
if (ESuccess != retval) {
KLog(Error, "Unable to get the own CPU-ID: %d\n", retval);
return retval;
}
UInt32 low, high;
CPU_ReadMsr(0x1B, &low, &high);
if (0 == (0x800 & low)) {
KLog(Error, "LAPIC is not disabled\n");
return -ENoPermission;
}
UInt32 value;
retval = CPU_ApicRead(ErrorStatus, &value);
for (UInt16 i = 0, c = 0; i < i_cpuCount; i++) {
if (ownId == acpis[i])
continue;
*stackPtr = i_stacks[c++];
KLog(Info, "Bringing up CPU #%u...", acpis[i]);
currentBootId = acpis[i];
KLog(Debug, "Sending INIT-IPI-1...");
retval = __SendIPI(0xc500, &status);
if (ESuccess != retval)
return retval;
KLog(Debug, "%#x\n", status);
__UDelay(10000);
KLog(Debug, "Sending INIT-IPI-2...");
retval = __SendIPI(0x8500, &status);
if (ESuccess != retval)
return retval;
KLog(Debug, "%#x\n", status);
retval = CPU_ApicRead(ErrorStatus, &value);
if (ESuccess != retval)
return retval;
KLog(Debug, "Sending STARTUP-IPI...");
retval = __SendIPI(0x600 | (0x7000 >> 12), &status);
if (ESuccess != retval)
return retval;
KLog(Debug, "%#x\n", status);
__UDelay(300);
__WaitForApic(&status);
__UDelay(200);
retval = CPU_ApicRead(ErrorStatus, &value);
UInt32 accept = value & 0xef;
if (0 == accept && 0 == status) {
while ((UInt32)~0x0 != currentBootId) ;
continue;
}
if (0 != accept)
KLog(Error, "APIC-delivery: %#x\n", accept);
if (0 != status)
KLog(Error, "APIC not delivered: %#x\n", status);
return -EBusy;
}
return ESuccess;
}
status innerhalb der __SendIPI-Aufrufe gibt immer 0x1000 zurück.
Ich sorge durch io_delay auch dafür, dass ich die erforderliche Zeit warte, damit die APs genug Zeit bekommen.
Getestet ist der Code unter QEmu.
Sieht einer von euch den Fehler?
Die APIC-IDs hole ich mir über die ACPI-MADT-Tabelle.
Viele Grüße
rizor