// 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; } TELF *system_get_kernel_elf(void) { return &g_SystemInfo.KernelELF; }