Cucumber/Kernel/src/Tier0/smp.c

239 lines
6.7 KiB
C
Executable File

#include "Tier0/smp.h"
#include "Tier0/paging.h"
#include "Tier0/physmem.h"
#include "Tier0/kstdio.h"
#include "Tier0/kstdlib.h"
#include "Tier0/panic.h"
#define SMP_TESMP_BUFFER_LENGTH 1024
u8 g_EntriesBuffer[SMP_TESMP_BUFFER_LENGTH];
#define SMP_MAX_CPU 32
#define SMP_MAX_IOAPIC 9
struct {
T_SMP_CPU CPUs[SMP_MAX_CPU];
u8 NumCPUs;
T_SMP_IOAPIC IOAPICs[SMP_MAX_IOAPIC];
u8 NumIOAPICs;
} g_SMP;
u64 smp_find_pointer(u64 Start, u64 End)
{
for (u64 i = Start & ~((u64)0x10); i < End; i += 16)
{
u8 Pointer[16];
physmem_read(i, 16, Pointer);
if (kmemcmp(Pointer, (u8 *)"_MP_", 4) < 0)
{
// Found something! Let's calculate the checksum, just to be sure.
u8 Sum = 0;
for (u8 j = 0; j < 16; j++)
Sum += Pointer[j];
if (Sum)
{
kprintf("[w] Found SMP pointer, but its checksum was invalid.");
continue;
}
else
{
kprintf("[i] Found SMP pointer @0x%x\n", i);
return i;
}
}
}
return 0;
}
void smp_initialize(void)
{
kprintf("[i] Looking for SMP Pointer:\n");
// According to the Intel spec, we must look for the SMP Pointer in four
// places:
// EBDA
u32 EBDAStart;
physmem_read(0x40e, 2, &EBDAStart);
EBDAStart = EBDAStart << 4;
kprintf(" EBDA @0x%x.\n", EBDAStart);
u64 Pointer = smp_find_pointer(EBDAStart, 0x0009FFFF);
// Last kilobyte of base memory
if (!Pointer)
{
u32 BaseMemoryEnd;
physmem_read(0x413, 2, &BaseMemoryEnd);
kprintf(" Base memory end @0x%x.\n", BaseMemoryEnd - 1024);
Pointer = smp_find_pointer(BaseMemoryEnd - 1024, BaseMemoryEnd);
}
// BIOS ROM
if (!Pointer)
{
kprintf(" BIOS ROM @0x00E00000.\n");
Pointer = smp_find_pointer(0x000F0000, 0x000FFFFF);
}
// Just give up already.
if (!Pointer)
PANIC("No SMP pointer found! Boo.");
T_SMP_POINTER PointerTable;
physmem_read(Pointer, 16, &PointerTable);
if (PointerTable.Specification != 4)
PANIC("Unsupported SMP spec!");
if (PointerTable.TablePhysical)
{
kprintf("[i] SMP Configuration Table present.\n");
smp_parse_configuration_table(PointerTable.TablePhysical);
}
else
{
kprintf("[i] SMP Configuration Type present.\n");
// do something else... like panic.
PANIC("SMP types not ismplemented!");
}
}
u8 smp_parse_io_interrupt(u32 EntryAddress)
{
//T_SMP_ENTRY_IO_INTERRUPT *Interrupt = (T_SMP_ENTRY_IO_INTERRUPT *)&g_EntriesBuffer[EntryAddress];
//kprintf(" IO Interrupt %i %i %i %i %i %i %i\n", Interrupt->InterruptType, Interrupt->Polarity, Interrupt->TriggerMode, Interrupt->SourceBusID, Interrupt->SourceBusIRQ, Interrupt->DestinationIOAPICID, Interrupt->DestinationIOAPICINTIN);
return 8;
}
u8 smp_parse_local_interrupt(u32 EntryAddress)
{
//T_SMP_ENTRY_LOCAL_INTERRUPT *Interrupt = (T_SMP_ENTRY_LOCAL_INTERRUPT *)&g_EntriesBuffer[EntryAddress];
//kprintf(" L Interrupt %i %i %i %i %i %i %i\n", Interrupt->InterruptType, Interrupt->Polarity, Interrupt->TriggerMode, Interrupt->SourceBusID, Interrupt->SourceBusIRQ, Interrupt->DestinationLAPICID, Interrupt->DestinationLAPICLINTIN);
return 8;
}
u8 smp_parse_ioapic(u32 EntryAddress)
{
T_SMP_ENTRY_IOAPIC *IOAPIC = (T_SMP_ENTRY_IOAPIC *)&g_EntriesBuffer[EntryAddress];
if (IOAPIC->Available)
{
g_SMP.IOAPICs[g_SMP.NumIOAPICs].ID = IOAPIC->ID;
g_SMP.IOAPICs[g_SMP.NumIOAPICs].Address = IOAPIC->Address;
kprintf(" IOAPIC ID %i, @0x%x\n", IOAPIC->ID, IOAPIC->Address);
}
else
kprintf(" IOAPIC ID %i, unavailable!!!", IOAPIC->ID);
return 8;
}
u8 smp_parse_bus(u32 EntryAddress)
{
T_SMP_ENTRY_BUS *Bus = (T_SMP_ENTRY_BUS *)&g_EntriesBuffer[EntryAddress];
s8 Name[7];
kmemcpy(Name, Bus->BusType, 6);
Name[6] = 0x00;
kprintf(" Bus #%i, %s\n", Bus->BusID, Name);
return 8;
}
u8 smp_parse_cpu(u32 EntryAddress)
{
u8 i = g_SMP.NumCPUs;
T_SMP_ENTRY_CPU *CPU = (T_SMP_ENTRY_CPU *)&g_EntriesBuffer[EntryAddress];
if (CPU->FlagBootstrap)
{
kprintf(" CPU #%i, LAPIC sig %x, cpuid %x (bootstrap)\n", i, CPU->LAPICID, CPU->CPUID);
g_SMP.CPUs[i].Bootstrap = 1;
g_SMP.CPUs[i].State = E_SMP_CPU_STATE_RUNNING;
}
else if (!CPU->FlagAvailable)
{
kprintf(" CPU #%i, LAPIC sig %x, cpuid %x, (unavailable", i, CPU->LAPICID, CPU->CPUID);
g_SMP.CPUs[i].Bootstrap = 0;
g_SMP.CPUs[i].State = E_SMP_CPU_STATE_DISABLED;
}
else
{
kprintf(" CPU #%i, LAPIC sig %x, cpuid %x (halted)\n", i, CPU->LAPICID, CPU->CPUID);
g_SMP.CPUs[i].Bootstrap = 0;
g_SMP.CPUs[i].State = E_SMP_CPU_STATE_HALTED;
}
g_SMP.CPUs[i].ID = i;
g_SMP.CPUs[i].CPUID = CPU->CPUID;
g_SMP.CPUs[i].LAPICID = CPU->LAPICID;
g_SMP.NumCPUs++;
return sizeof(T_SMP_ENTRY_CPU);
}
void smp_parse_configuration_table(u32 TableAddress)
{
T_SMP_CONFIGURATION_HEADER Header;
physmem_read(TableAddress, 44, &Header);
s8 OEMName[9];
kmemcpy(OEMName, Header.OEMName, 8);
OEMName[8] = 0x00;
s8 ProductName[13];
kmemcpy(ProductName, Header.ProductName, 12);
ProductName[12] = 0x00;
kprintf("[i] SMP OEM: %s\n", OEMName);
kprintf("[i] SMP Product: %s\n", ProductName);
kprintf("[i] SMP Base Configuration Table length: %i bytes.\n", Header.BaseTableLength);
if (Header.BaseTableLength > SMP_TESMP_BUFFER_LENGTH)
PANIC("SMP BCT too big!");
physmem_read(TableAddress + 44, Header.BaseTableLength - 44, g_EntriesBuffer);
u32 EntryAddress = 0;
g_SMP.NumCPUs = 0;
g_SMP.NumIOAPICs = 0;
while (EntryAddress < Header.BaseTableLength - sizeof(T_SMP_CONFIGURATION_HEADER))
{
u8 EntryType = g_EntriesBuffer[EntryAddress];
switch (EntryType)
{
case 0x00:
EntryAddress += smp_parse_cpu(EntryAddress);
break;
case 0x01:
EntryAddress += smp_parse_bus(EntryAddress);
break;
case 0x02:
EntryAddress += smp_parse_ioapic(EntryAddress);
break;
case 0x03:
EntryAddress += smp_parse_io_interrupt(EntryAddress);
break;
case 0x04:
EntryAddress += smp_parse_local_interrupt(EntryAddress);
break;
}
}
}