Cucumber/Kernel/src/Tier0/system.c

228 lines
6.7 KiB
C

// Basic information gathere about system
#include "types.h"
#include "Tier0/system.h"
#include "Tier0/panic.h"
#include "Tier0/kstdio.h"
#include "Tier0/physmem.h"
T_SYSTEM_INFO g_SystemInfo;
extern u64 _end;
extern u64 _start;
#define NOTIFY_ABOUT_FEATURE(f) if (g_SystemInfo.CPUFeatures.Flags.f) \
kprintf(" " #f);
void system_parse_cpu_features(void)
{
g_SystemInfo.CPUFeatures.FlagsU64 = system_cpuid(1);
kprintf("[i] CPU features:");
NOTIFY_ABOUT_FEATURE(ACPI);
NOTIFY_ABOUT_FEATURE(AES);
NOTIFY_ABOUT_FEATURE(APIC);
NOTIFY_ABOUT_FEATURE(FPU);
NOTIFY_ABOUT_FEATURE(IA64);
NOTIFY_ABOUT_FEATURE(MMX);
NOTIFY_ABOUT_FEATURE(MSR);
NOTIFY_ABOUT_FEATURE(PAE);
NOTIFY_ABOUT_FEATURE(SSE);
NOTIFY_ABOUT_FEATURE(SSE2);
NOTIFY_ABOUT_FEATURE(SSE3);
NOTIFY_ABOUT_FEATURE(SSSE3);
NOTIFY_ABOUT_FEATURE(SSE4_1);
NOTIFY_ABOUT_FEATURE(SSE4_2);
kprintf("\n");
}
void system_parse_load_context(T_LOAD_CONTEXT *LoadContext)
{
void *Header = (void *)LoadContext->MultibootHeader;
u8 Flags = *((u8*)Header);
// Lower & Upper memory limits from Multiboot header
// The upper memory limit is not required to specify all the available RAM
if (Flags & 1)
{
g_SystemInfo.MemoryLower = (u64)((u8*)Header)[4];
g_SystemInfo.MemoryUpper = (u64)((u8*)Header)[8];
}
// Bootloader name from Multiboot header
if ((Flags >> 9) & 1)
g_SystemInfo.BootloaderName = (s8*)(u64)((u32*)Header)[16];
else
g_SystemInfo.BootloaderName = LoadContext->LoaderName;
u64 HighestUnavailable = 0;
// First, chew through what Multiboot gave us...
if ((Flags >> 6) & 1)
{
// Memory map from bootloader...
u64 MapStart = ((u32*)Header)[12];
u64 MapLength = ((u32*)Header)[11];
g_SystemInfo.NumInvalidAreas = 0;
u64 AvailableMemory = 0;
T_SYSTEM_MLTBT_MMAP *Node = (T_SYSTEM_MLTBT_MMAP*)MapStart;
while ((u64)Node + 4 - MapStart < MapLength)
{
u32 Size = Node->Size;
if (Size == 0)
Size = sizeof(T_SYSTEM_MLTBT_MMAP);
if (Node->Type == 1)
AvailableMemory += Node->Length;
else
{
// Not available!
T_SYSTEM_INVALID_RAM *Area = \
&g_SystemInfo.InvalidMemoryAreas[g_SystemInfo.NumInvalidAreas];
Area->Base = Node->Base;
Area->Size = Node->Length;
kprintf("[i] Unavailable memory: %x - %x\n", Node->Base, Node->Base + Node->Length);
if (Area->Base > HighestUnavailable)
HighestUnavailable = Area->Base;
g_SystemInfo.NumInvalidAreas++;
}
Node = (T_SYSTEM_MLTBT_MMAP*)((u64)Node + Size + 4);
}
g_SystemInfo.MemoryUpper = AvailableMemory / 1024;
}
else
PANIC("Not implemented: Memory Map Probing");
// Now, mark the BIOS area (lowest megabyte) as unavailable
T_SYSTEM_INVALID_RAM *BIOSArea = &g_SystemInfo.InvalidMemoryAreas[g_SystemInfo.NumInvalidAreas];
BIOSArea->Base = 0;
BIOSArea->Size = 1024 *1024;
g_SystemInfo.NumInvalidAreas++;
// Mark the loader physical location as unavailable.
T_SYSTEM_INVALID_RAM *LoaderArea = &g_SystemInfo.InvalidMemoryAreas[g_SystemInfo.NumInvalidAreas];
LoaderArea->Base = LoadContext->ReservedPhysicalStart;
LoaderArea->Size = LoadContext->ReservedPhysicalEnd - LoadContext->ReservedPhysicalStart;
g_SystemInfo.NumInvalidAreas++;
// ...and the IOAPIC
T_SYSTEM_INVALID_RAM *IOAPICArea = &g_SystemInfo.InvalidMemoryAreas[g_SystemInfo.NumInvalidAreas];
IOAPICArea->Base = 0xFEC00000;
IOAPICArea->Size = 0xFECFFFFF - 0xFEC00000;
g_SystemInfo.NumInvalidAreas++;
/// ...and the LAPIC
T_SYSTEM_INVALID_RAM *LAPICArea = &g_SystemInfo.InvalidMemoryAreas[g_SystemInfo.NumInvalidAreas];
LAPICArea->Base = 0xFEE00000;
LAPICArea->Size = 0xFEEFFFFF - 0xFEE00000;
g_SystemInfo.NumInvalidAreas++;
// Parse the kernel ELF
TELF *ELF = &g_SystemInfo.KernelELF;
if (elf_open(ELF, LoadContext->KernelELF, LoadContext->KernelELFSize))
PANIC("Error parsing kernel ELF file.\n");
else
{
kprintf("[i] Kernel has the following sections:\n");
for (u32 i = 0; i < ELF->SectionCount; i++)
{
u64 Virtual = elf_section_get_virtual_address(ELF, i);
u64 HasBits = elf_section_has_bits(ELF, i);
if (Virtual && HasBits)
kprintf(" - %s (virt: 0x%X, phys: 0x%x, %i bytes)\n",
elf_section_get_name(ELF, i),
Virtual,
elf_section_get_physical_address(ELF, i),
elf_section_get_size(ELF, i));
else if (Virtual)
kprintf(" - %s (virt: 0x%X, (zero'd bits), %i bytes)\n",
elf_section_get_name(ELF, i),
Virtual,
elf_section_get_size(ELF, i));
}
}
kprintf("[i] Highest unavailable address is %x.\n", HighestUnavailable);
g_SystemInfo.MemoryTop = HighestUnavailable;
}
u64 system_get_memory_upper(void)
{
return g_SystemInfo.MemoryUpper;
}
u64 system_get_memory_lower(void)
{
return g_SystemInfo.MemoryLower;
}
s8 *system_get_bootloader_name(void)
{
return g_SystemInfo.BootloaderName;
}
u8 system_memory_available(u64 Start, u64 Length)
{
for (u8 i = 0; i < g_SystemInfo.NumInvalidAreas; i++)
{
T_SYSTEM_INVALID_RAM Area = g_SystemInfo.InvalidMemoryAreas[i];
// If the start address is somwhere in the invalid area
if (Area.Base <= Start && Area.Base + Area.Size > Start)
return 0;
// If the end address is somewhere in the invalid area
if (Area.Base <= Start + Length && Area.Base + Area.Size > Start + Length)
return 0;
// If the request spans accross an invalid area
if (Area.Base >= Start && Start + Length > Area.Base + Area.Size)
return 0;
}
return 1;
}
u64 system_cpuid(u32 Code)
{
u32 Low;
u32 High;
__asm__ volatile ("cpuid" : "=a"(Low), "=d"(High) : "0"(Code) : "ecx", "ebx");
return (u64)High | ((u64)Low << 32);
}
u8 system_msr_available(void)
{
return CPUID_HAS(MSR);
}
u64 system_msr_get(u32 MSR)
{
u32 Low;
u32 High;
__asm__ volatile("rdmsr" : "=a"(Low), "=d"(High) : "c"(MSR));
return (u64)Low | ((u64)High << 32);
}
void system_msr_set(u32 MSR, u64 Data)
{
__asm__ volatile("wrmsr" :: "a"((u32)(Data & 0xFFFFFFFF)), "d"((u32)(Data >> 32)), "c"(MSR));
}
u64 system_get_memory_top(void)
{
return g_SystemInfo.MemoryTop;
}