/* * @author xamidev * @brief x86 architecture-dependant initialization * @license GPL-3.0-only */ #include #include #include #include #include /* * x86_overwrite_pat - Set PAT to WC * * This function overwrites the 1st Page Attribute * Table entry, to enable the Write-Combining property * when we map memory regions later on. * The framebuffer will be mapped with WC, which makes * memory access significantly faster by using burst * operations. */ static void x86_overwrite_pat() { uint64_t pat = rdmsr(0x277); pat &= ~(0xFFULL << 8); // Clear PAT1 pat |= (0x01ULL << 8); // PAT1 = 0x01 (WC) wrmsr(0x277, pat); } /* * x86_enable_fpu - Enable Floating Point Unit * * This function enables the Floating Point Unit, * which allows the CPU to do floating point * operations. * * Here we do not check for FPU support but we * should. However most processors support it. */ static void x86_enable_fpu() { size_t cr4; __asm__ volatile("mov %%cr4, %0" : "=r"(cr4)); cr4 |= 0x200; __asm__ volatile("mov %0, %%cr4" :: "r"(cr4)); uint16_t cw = 0x37F; // control word asm volatile("fldcw %0" :: "m"(cw)); } /* * x86_arch_init - Initialize x86 CPU structures * * This function is responsible for overriding a PAT entry * (to put the framebuffer area in WC mode) only. * * Later, all architecture-dependant init (GDT, IDT, TSS, ...) * should be initialized here, and separate function pointers * should be set up for each arch. */ void x86_arch_init() { x86_overwrite_pat(); x86_enable_fpu(); x86_cpu_identification(); idt_init(); gdt_init(); } /* * cpu_supports_brandstring - Does the CPU support brand strings? * * Return: * true - if it does * false - if it doesn't */ bool cpu_supports_brandstring() { uint32_t eax, ebx, ecx, edx; cpuid(0x80000000, &eax, &ebx, &ecx, &edx); if (eax < 0x80000004) { return false; } else { return true; } } /* * x86_cpu_idenfitication - get info about the CPU * * This function displays the CPU vendor name or the * extended "brand string" if it's supported, on * debug output. */ void x86_cpu_identification() { if (cpu_supports_brandstring()) { uint32_t regs[12]; // Some CPUs don't return null-terminated values so we do it as a failsafe default char str[sizeof(regs)+1] = {0}; cpuid(0x80000002, ®s[0], ®s[1], ®s[2], ®s[3]); cpuid(0x80000003, ®s[4], ®s[5], ®s[6], ®s[7]); cpuid(0x80000004, ®s[8], ®s[9], ®s[10], ®s[11]); memcpy(str, regs, sizeof(regs)); str[sizeof(regs)] = '\0'; DEBUG("CPU: %s", str); } else { char vendor_string[13] = {0}; cpuid_get_vendor_string(vendor_string); DEBUG("CPU vendor is: %s", vendor_string); } }