// Copyright (c) 2023-2026 Chris (boreddevnl) // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. #include #include "limine.h" #include #include "platform.h" #include "kutils.h" static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = { .id = LIMINE_HHDM_REQUEST, .revision = 0, .response = NULL }; static volatile struct limine_kernel_address_request kernel_addr_request __attribute__((used, section(".requests"))) = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0, .response = NULL }; uint64_t hhdm_offset = 0; uint64_t kernel_phys_base = 0; uint64_t kernel_virt_base = 0; void platform_init(void) { if (hhdm_request.response) { hhdm_offset = hhdm_request.response->offset; } if (kernel_addr_request.response) { kernel_phys_base = kernel_addr_request.response->physical_base; kernel_virt_base = kernel_addr_request.response->virtual_base; } // Enable FPU and SSE uint64_t cr0; asm volatile("mov %%cr0, %0" : "=r"(cr0)); cr0 &= ~(1ULL << 2); // Clear EM (Emulation) cr0 |= (1ULL << 1); // Set MP (Monitor Coprocessor) cr0 |= (1ULL << 5); // Set NE (Numeric Error) asm volatile("mov %0, %%cr0" : : "r"(cr0)); uint64_t cr4; asm volatile("mov %%cr4, %0" : "=r"(cr4)); cr4 |= (1ULL << 9); // Set OSFXSR (FXSAVE/FXRSTOR support) cr4 |= (1ULL << 10); // Set OSXMMEXCPT (SIMD exception support) asm volatile("mov %0, %%cr4" : : "r"(cr4)); // Initialize FPU asm volatile("fninit"); } uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; } uint64_t v2p(uint64_t virt) { if (kernel_virt_base && virt >= kernel_virt_base) { return virt - kernel_virt_base + kernel_phys_base; } if (hhdm_offset && virt >= hhdm_offset) { return virt - hhdm_offset; } return virt; } void platform_get_cpu_model(char *model) { uint32_t brand[12]; uint32_t eax, ebx, ecx, edx; for (uint32_t i = 0; i < 3; i++) { asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000002 + i)); brand[i * 4 + 0] = eax; brand[i * 4 + 1] = ebx; brand[i * 4 + 2] = ecx; brand[i * 4 + 3] = edx; } char *p = (char *)brand; for (int i = 0; i < 48; i++) { model[i] = p[i]; } model[48] = '\0'; } void platform_get_cpu_vendor(char *vendor) { uint32_t eax, ebx, ecx, edx; asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0)); char *p = (char *)vendor; *((uint32_t *)&p[0]) = ebx; *((uint32_t *)&p[4]) = edx; *((uint32_t *)&p[8]) = ecx; p[12] = '\0'; } void platform_get_cpu_info(cpu_info_t *info) { uint32_t eax, ebx, ecx, edx; // CPUID leaf 1: basic feature information asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1)); info->stepping = eax & 0xF; info->model = (eax >> 4) & 0xF; info->family = (eax >> 8) & 0xF; info->microcode = (ebx >> 8) & 0xFF; info->flags = ((uint64_t)ecx << 32) | edx; // ECX and EDX contain feature flags info->cache_size = (ebx >> 16) & 0xFF; // Cache line size in bytes } void platform_get_cpu_flags(char *flags_str) { uint32_t eax, ebx, ecx, edx; flags_str[0] = '\0'; // CPUID leaf 1 asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1)); // ECX flags if (ecx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "sse3 "); if (ecx & (1 << 1)) k_strcpy(flags_str + k_strlen(flags_str), "pclmulqdq "); if (ecx & (1 << 3)) k_strcpy(flags_str + k_strlen(flags_str), "monitor "); if (ecx & (1 << 6)) k_strcpy(flags_str + k_strlen(flags_str), "ssse3 "); if (ecx & (1 << 9)) k_strcpy(flags_str + k_strlen(flags_str), "sdbg "); if (ecx & (1 << 12)) k_strcpy(flags_str + k_strlen(flags_str), "fma "); if (ecx & (1 << 13)) k_strcpy(flags_str + k_strlen(flags_str), "cx16 "); if (ecx & (1 << 19)) k_strcpy(flags_str + k_strlen(flags_str), "sse4_1 "); if (ecx & (1 << 20)) k_strcpy(flags_str + k_strlen(flags_str), "sse4_2 "); if (ecx & (1 << 23)) k_strcpy(flags_str + k_strlen(flags_str), "popcnt "); if (ecx & (1 << 25)) k_strcpy(flags_str + k_strlen(flags_str), "aes "); if (ecx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "xsave "); if (ecx & (1 << 28)) k_strcpy(flags_str + k_strlen(flags_str), "avx "); // EDX flags if (edx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "fpu "); if (edx & (1 << 3)) k_strcpy(flags_str + k_strlen(flags_str), "pse "); if (edx & (1 << 4)) k_strcpy(flags_str + k_strlen(flags_str), "tsc "); if (edx & (1 << 6)) k_strcpy(flags_str + k_strlen(flags_str), "pae "); if (edx & (1 << 8)) k_strcpy(flags_str + k_strlen(flags_str), "cx8 "); if (edx & (1 << 9)) k_strcpy(flags_str + k_strlen(flags_str), "apic "); if (edx & (1 << 11)) k_strcpy(flags_str + k_strlen(flags_str), "sep "); if (edx & (1 << 15)) k_strcpy(flags_str + k_strlen(flags_str), "cmov "); if (edx & (1 << 23)) k_strcpy(flags_str + k_strlen(flags_str), "mmx "); if (edx & (1 << 24)) k_strcpy(flags_str + k_strlen(flags_str), "fxsr "); if (edx & (1 << 25)) k_strcpy(flags_str + k_strlen(flags_str), "sse "); if (edx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "sse2 "); // Extended leaf 0x80000001 for advanced flags asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000001)); if (edx & (1 << 11)) k_strcpy(flags_str + k_strlen(flags_str), "syscall "); if (edx & (1 << 20)) k_strcpy(flags_str + k_strlen(flags_str), "nx "); if (edx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "pdpe1gb "); if (edx & (1 << 27)) k_strcpy(flags_str + k_strlen(flags_str), "rdtscp "); if (edx & (1 << 29)) k_strcpy(flags_str + k_strlen(flags_str), "lm "); if (ecx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "lahf_lm "); if (ecx & (1 << 5)) k_strcpy(flags_str + k_strlen(flags_str), "abm "); // Remove trailing space int len = k_strlen(flags_str); if (len > 0 && flags_str[len-1] == ' ') { flags_str[len-1] = '\0'; } }