diff --git a/arch/x86/64/mmu.c b/arch/x86/64/mmu.c index 733135e2..f559a3fd 100644 --- a/arch/x86/64/mmu.c +++ b/arch/x86/64/mmu.c @@ -691,9 +691,9 @@ void x86_mmu_early_init(void) { x86_set_cr4(cr4); /* Set NXE bit in MSR_EFER*/ - efer_msr = read_msr(x86_MSR_EFER); - efer_msr |= x86_EFER_NXE; - write_msr(x86_MSR_EFER, efer_msr); + efer_msr = read_msr(X86_MSR_IA32_EFER); + efer_msr |= X86_EFER_NXE; + write_msr(X86_MSR_IA32_EFER, efer_msr); /* getting the address width from CPUID instr */ /* Bits 07-00: Physical Address width info */ diff --git a/arch/x86/arch.c b/arch/x86/arch.c index 0a48dba3..0bf6cc1e 100644 --- a/arch/x86/arch.c +++ b/arch/x86/arch.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,8 @@ void arch_early_init(void) { set_global_desc(TSS_SELECTOR, &system_tss, sizeof(system_tss), 1, 0, 0, SEG_TYPE_TSS, 0, 0); x86_ltr(TSS_SELECTOR); + x86_feature_init(); + x86_mmu_early_init(); } diff --git a/arch/x86/feature.c b/arch/x86/feature.c new file mode 100644 index 00000000..450b4653 --- /dev/null +++ b/arch/x86/feature.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2019 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +enum x86_cpu_vendor __x86_cpu_vendor = X86_CPU_VENDOR_INTEL; +enum x86_cpu_level __x86_cpu_level = X86_CPU_LEVEL_386; // start off assuming 386 +uint32_t max_cpuid_leaf = 0; +uint32_t max_cpuid_leaf_extended = 0; + +static enum x86_cpu_vendor match_cpu_vendor_string(const char *str) { + // from table at https://www.sandpile.org/x86/cpuid.htm#level_0000_0000h + if (!strcmp(str, "GenuineIntel")) { + return X86_CPU_VENDOR_INTEL; + } + if (!strcmp(str, "UMC UMC UMC ")) { + return X86_CPU_VENDOR_UMC; + } + if (!strcmp(str, "AuthenticAMD")) { + return X86_CPU_VENDOR_AMD; + } + if (!strcmp(str, "CyrixInstead")) { + return X86_CPU_VENDOR_CYRIX; + } + if (!strcmp(str, "NexGenDriven")) { + return X86_CPU_VENDOR_NEXGEN; + } + if (!strcmp(str, "CentaurHauls")) { + return X86_CPU_VENDOR_CENTAUR; + } + if (!strcmp(str, "RiseRiseRise")) { + return X86_CPU_VENDOR_RISE; + } + if (!strcmp(str, "SiS SiS SiS ")) { + return X86_CPU_VENDOR_SIS; + } + if (!strcmp(str, "GenuineTMx86")) { + return X86_CPU_VENDOR_TRANSMETA; + } + if (!strcmp(str, "Geode by NSC")) { + return X86_CPU_VENDOR_NSC; + } + return X86_CPU_VENDOR_UNKNOWN; +} + +static void x86_cpu_detect(void) { + bool has_cpuid = false; + +#if X86_LEGACY + // inspired by http://www.rcollins.org/ddj/Sep96/Sep96.html + // try to detect a 486 + // set the EFLAGS.AC bit, see if it sets + uint32_t flags = x86_save_flags(); + x86_restore_flags(flags | X86_FLAGS_AC); + if (x86_save_flags() & X86_FLAGS_AC) { + __x86_cpu_level = X86_CPU_LEVEL_486; + + // test EFLAGS.ID flag + x86_restore_flags(flags | X86_FLAGS_ID); + if (x86_save_flags() & X86_FLAGS_ID) { + has_cpuid = true; + } + } +#else + // at least a pentium and has cpuid + __x86_cpu_level = X86_CPU_LEVEL_PENTIUM; + has_cpuid = true; + uint32_t a, b, c, d; + + // read the max basic cpuid leaf + cpuid(0, &a, &b, &c, &d); + max_cpuid_leaf = a; + + // read the vendor string + union { + uint32_t reg[3]; + char str[13]; + } vs; + vs.reg[0] = b; + vs.reg[1] = d; + vs.reg[2] = c; + vs.str[12] = 0; + __x86_cpu_vendor = match_cpu_vendor_string(vs.str); + + // read max extended cpuid leaf + cpuid(0x80000000, &a, &b, &c, &d); + if (a >= 0x80000000) { + max_cpuid_leaf_extended = a; + } + + dprintf(SPEW, "x86: vendor string '%s'\n", vs.str); + + // do a quick cpu level detection using cpuid + if (max_cpuid_leaf >= 1) { + cpuid(1, &a, &b, &c, &d); + + LTRACEF("cpuid leaf 1: %#x %#x %#x %#x\n", a, b, c, d); + + uint32_t ext_family = BITS_SHIFT(a, 27, 20); + uint32_t ext_model = BITS_SHIFT(a, 19, 16); + uint32_t family = BITS_SHIFT(a, 11, 8); + uint32_t model = BITS_SHIFT(a, 7, 4); + LTRACEF("raw family %#x model %#x ext_family %#x ext_model %#x\n", family, model, ext_family, ext_model); + + switch (family) { + case 4: + __x86_cpu_level = X86_CPU_LEVEL_486; + break; + case 5: + __x86_cpu_level = X86_CPU_LEVEL_PENTIUM; + break; + case 6: + __x86_cpu_level = X86_CPU_LEVEL_PENTIUM_PRO; + if (x86_get_cpu_vendor() == X86_CPU_VENDOR_INTEL) { + model |= ext_model << 4; // extended model field extends the regular model + } + break; + case 0xf: + __x86_cpu_level = X86_CPU_LEVEL_PENTIUM_PRO; + family += ext_family; // family 0xf stuff is extended by bits 27:20 + model |= ext_model << 4; // extended model field extends the regular model + break; + default: + // unhandled decode, assume ppro+ level + __x86_cpu_level = X86_CPU_LEVEL_PENTIUM_PRO; + break; + } + dprintf(SPEW, "x86: family %#x model %#x\n", family, model); + + // TODO: save this information for future use + } +#endif + + dprintf(SPEW, "x86: detected cpu level %d has_cpuid %d\n", x86_get_cpu_level(), has_cpuid); + if (has_cpuid) { + dprintf(SPEW, "x86: max cpuid leaf %#x ext %#x\n", max_cpuid_leaf, max_cpuid_leaf_extended); + } +} + +void x86_feature_init(void) { + x86_cpu_detect(); +} + diff --git a/arch/x86/include/arch/x86.h b/arch/x86/include/arch/x86.h index d57a1c18..2d7dc673 100644 --- a/arch/x86/include/arch/x86.h +++ b/arch/x86/include/arch/x86.h @@ -2,6 +2,8 @@ * Copyright (c) 2009 Corey Tabaka * Copyright (c) 2015 Intel Corporation * Copyright (c) 2016 Travis Geiselbrecht + * Copyright 2016 The Fuchsia Authors + * * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at @@ -121,24 +123,117 @@ typedef tss_32_t tss_t; typedef tss_64_t tss_t; #endif -#define X86_CR0_PE 0x00000001 /* protected mode enable */ -#define X86_CR0_MP 0x00000002 /* monitor coprocessor */ -#define X86_CR0_EM 0x00000004 /* emulation */ -#define X86_CR0_TS 0x00000008 /* task switched */ -#define X86_CR0_NE 0x00000020 /* enable x87 exception */ -#define X86_CR0_WP 0x00010000 /* supervisor write protect */ -#define X86_CR0_NW 0x20000000 /* not write-through */ -#define X86_CR0_CD 0x40000000 /* cache disable */ -#define X86_CR0_PG 0x80000000 /* enable paging */ -#define X86_CR4_PAE 0x00000020 /* PAE paging */ -#define X86_CR4_OSFXSR 0x00000200 /* os supports fxsave */ -#define X86_CR4_OSXMMEXPT 0x00000400 /* os supports xmm exception */ -#define X86_CR4_OSXSAVE 0x00040000 /* os supports xsave */ -#define X86_CR4_SMEP 0x00100000 /* SMEP protection enabling */ -#define X86_CR4_SMAP 0x00200000 /* SMAP protection enabling */ -#define x86_EFER_NXE 0x00000800 /* to enable execute disable bit */ -#define x86_MSR_EFER 0xc0000080 /* EFER Model Specific Register id */ -#define X86_CR4_PSE 0xffffffef /* Disabling PSE bit in the CR4 */ +/* x86 register bits */ +#define X86_CR0_PE 0x00000001 /* protected mode enable */ +#define X86_CR0_MP 0x00000002 /* monitor coprocessor */ +#define X86_CR0_EM 0x00000004 /* emulation */ +#define X86_CR0_TS 0x00000008 /* task switched */ +#define X86_CR0_NE 0x00000020 /* enable x87 exception */ +#define X86_CR0_WP 0x00010000 /* supervisor write protect */ +#define X86_CR0_NW 0x20000000 /* not write-through */ +#define X86_CR0_CD 0x40000000 /* cache disable */ +#define X86_CR0_PG 0x80000000 /* enable paging */ +#define X86_CR4_PAE 0x00000020 /* PAE paging */ +#define X86_CR4_PGE 0x00000080 /* page global enable */ +#define X86_CR4_OSFXSR 0x00000200 /* os supports fxsave */ +#define X86_CR4_OSXMMEXPT 0x00000400 /* os supports xmm exception */ +#define X86_CR4_UMIP 0x00000800 /* User-mode instruction prevention */ +#define X86_CR4_VMXE 0x00002000 /* enable vmx */ +#define X86_CR4_FSGSBASE 0x00010000 /* enable {rd,wr}{fs,gs}base */ +#define X86_CR4_PCIDE 0x00020000 /* Process-context ID enable */ +#define X86_CR4_OSXSAVE 0x00040000 /* os supports xsave */ +#define X86_CR4_SMEP 0x00100000 /* SMEP protection enabling */ +#define X86_CR4_SMAP 0x00200000 /* SMAP protection enabling */ +#define X86_EFER_SCE 0x00000001 /* enable SYSCALL */ +#define X86_EFER_LME 0x00000100 /* long mode enable */ +#define X86_EFER_LMA 0x00000400 /* long mode active */ +#define X86_EFER_NXE 0x00000800 /* to enable execute disable bit */ +#define X86_MSR_IA32_PLATFORM_ID 0x00000017 /* platform id */ +#define X86_MSR_IA32_APIC_BASE 0x0000001b /* APIC base physical address */ +#define X86_MSR_IA32_TSC_ADJUST 0x0000003b /* TSC adjust */ +#define X86_MSR_IA32_BIOS_SIGN_ID 0x0000008b /* BIOS update signature */ +#define X86_MSR_IA32_MTRRCAP 0x000000fe /* MTRR capability */ +#define X86_MSR_IA32_SYSENTER_CS 0x00000174 /* SYSENTER CS */ +#define X86_MSR_IA32_SYSENTER_ESP 0x00000175 /* SYSENTER ESP */ +#define X86_MSR_IA32_SYSENTER_EIP 0x00000176 /* SYSENTER EIP */ +#define X86_MSR_IA32_MCG_CAP 0x00000179 /* global machine check capability */ +#define X86_MSR_IA32_MCG_STATUS 0x0000017a /* global machine check status */ +#define X86_MSR_IA32_MISC_ENABLE 0x000001a0 /* enable/disable misc processor features */ +#define X86_MSR_IA32_TEMPERATURE_TARGET 0x000001a2 /* Temperature target */ +#define X86_MSR_IA32_MTRR_PHYSBASE0 0x00000200 /* MTRR PhysBase0 */ +#define X86_MSR_IA32_MTRR_PHYSMASK0 0x00000201 /* MTRR PhysMask0 */ +#define X86_MSR_IA32_MTRR_PHYSMASK9 0x00000213 /* MTRR PhysMask9 */ +#define X86_MSR_IA32_MTRR_DEF_TYPE 0x000002ff /* MTRR default type */ +#define X86_MSR_IA32_MTRR_FIX64K_00000 0x00000250 /* MTRR FIX64K_00000 */ +#define X86_MSR_IA32_MTRR_FIX16K_80000 0x00000258 /* MTRR FIX16K_80000 */ +#define X86_MSR_IA32_MTRR_FIX16K_A0000 0x00000259 /* MTRR FIX16K_A0000 */ +#define X86_MSR_IA32_MTRR_FIX4K_C0000 0x00000268 /* MTRR FIX4K_C0000 */ +#define X86_MSR_IA32_MTRR_FIX4K_F8000 0x0000026f /* MTRR FIX4K_F8000 */ +#define X86_MSR_IA32_PAT 0x00000277 /* PAT */ +#define X86_MSR_IA32_TSC_DEADLINE 0x000006e0 /* TSC deadline */ +#define X86_MSR_IA32_EFER 0xc0000080 /* EFER */ +#define X86_MSR_IA32_STAR 0xc0000081 /* system call address */ +#define X86_MSR_IA32_LSTAR 0xc0000082 /* long mode call address */ +#define X86_MSR_IA32_CSTAR 0xc0000083 /* ia32-e compat call address */ +#define X86_MSR_IA32_FMASK 0xc0000084 /* system call flag mask */ +#define X86_MSR_IA32_FS_BASE 0xc0000100 /* fs base address */ +#define X86_MSR_IA32_GS_BASE 0xc0000101 /* gs base address */ +#define X86_MSR_IA32_KERNEL_GS_BASE 0xc0000102 /* kernel gs base */ +#define X86_MSR_IA32_TSC_AUX 0xc0000103 /* TSC aux */ +#define X86_MSR_IA32_PM_ENABLE 0x00000770 /* enable/disable HWP */ +#define X86_MSR_IA32_HWP_CAPABILITIES 0x00000771 /* HWP performance range enumeration */ +#define X86_MSR_IA32_HWP_REQUEST 0x00000774 /* power manage control hints */ +#define X86_CR4_PSE 0xffffffef /* Disabling PSE bit in the CR4 */ + +// Non-architectural MSRs +#define X86_MSR_RAPL_POWER_UNIT 0x00000606 /* RAPL unit multipliers */ +#define X86_MSR_PKG_POWER_LIMIT 0x00000610 /* Package power limits */ +#define X86_MSR_PKG_POWER_LIMIT_PL1_CLAMP (1 << 16) +#define X86_MSR_PKG_POWER_LIMIT_PL1_ENABLE (1 << 15) +#define X86_MSR_PKG_ENERGY_STATUS 0x00000611 /* Package energy status */ +#define X86_MSR_PKG_POWER_INFO 0x00000614 /* Package power range info */ +#define X86_MSR_DRAM_POWER_LIMIT 0x00000618 /* DRAM RAPL power limit control */ +#define X86_MSR_DRAM_ENERGY_STATUS 0x00000619 /* DRAM energy status */ +#define X86_MSR_PP0_POWER_LIMIT 0x00000638 /* PP0 RAPL power limit control */ +#define X86_MSR_PP0_ENERGY_STATUS 0x00000639 /* PP0 energy status */ +#define X86_MSR_PP1_POWER_LIMIT 0x00000640 /* PP1 RAPL power limit control */ +#define X86_MSR_PP1_ENERGY_STATUS 0x00000641 /* PP1 energy status */ +#define X86_MSR_PLATFORM_ENERGY_COUNTER 0x0000064d /* Platform energy counter */ +#define X86_MSR_PLATFORM_POWER_LIMIT 0x0000065c /* Platform power limit control */ + +/* EFLAGS/RFLAGS */ +#define X86_FLAGS_CF (1<<0) +#define X86_FLAGS_PF (1<<2) +#define X86_FLAGS_AF (1<<4) +#define X86_FLAGS_ZF (1<<6) +#define X86_FLAGS_SF (1<<7) +#define X86_FLAGS_TF (1<<8) +#define X86_FLAGS_IF (1<<9) +#define X86_FLAGS_DF (1<<10) +#define X86_FLAGS_OF (1<<11) +#define X86_FLAGS_STATUS_MASK (0xfff) +#define X86_FLAGS_IOPL_MASK (3<<12) +#define X86_FLAGS_IOPL_SHIFT (12) +#define X86_FLAGS_NT (1<<14) +#define X86_FLAGS_RF (1<<16) +#define X86_FLAGS_VM (1<<17) +#define X86_FLAGS_AC (1<<18) +#define X86_FLAGS_VIF (1<<19) +#define X86_FLAGS_VIP (1<<20) +#define X86_FLAGS_ID (1<<21) +#define X86_FLAGS_RESERVED_ONES 0x2 +#define X86_FLAGS_RESERVED 0xffc0802a +#define X86_FLAGS_USER (X86_FLAGS_CF | \ + X86_FLAGS_PF | \ + X86_FLAGS_AF | \ + X86_FLAGS_ZF | \ + X86_FLAGS_SF | \ + X86_FLAGS_TF | \ + X86_FLAGS_DF | \ + X86_FLAGS_OF | \ + X86_FLAGS_NT | \ + X86_FLAGS_AC | \ + X86_FLAGS_ID) static inline void x86_clts(void) { __asm__ __volatile__("clts"); } static inline void x86_hlt(void) { __asm__ __volatile__("hlt"); } diff --git a/arch/x86/include/arch/x86/feature.h b/arch/x86/include/arch/x86/feature.h new file mode 100644 index 00000000..e720dc54 --- /dev/null +++ b/arch/x86/include/arch/x86/feature.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include + +__BEGIN_CDECLS + +void x86_feature_init(void); + +enum x86_cpu_level { + X86_CPU_LEVEL_386 = 3, + X86_CPU_LEVEL_486 = 4, + X86_CPU_LEVEL_PENTIUM = 5, + X86_CPU_LEVEL_PENTIUM_PRO = 6, + // everything after this is PPRO+ for now +}; +extern enum x86_cpu_level __x86_cpu_level; + +enum x86_cpu_vendor { + X86_CPU_VENDOR_UNKNOWN, + X86_CPU_VENDOR_INTEL, + X86_CPU_VENDOR_AMD, + X86_CPU_VENDOR_UMC, + X86_CPU_VENDOR_CYRIX, + X86_CPU_VENDOR_NEXGEN, + X86_CPU_VENDOR_CENTAUR, + X86_CPU_VENDOR_RISE, + X86_CPU_VENDOR_SIS, + X86_CPU_VENDOR_TRANSMETA, + X86_CPU_VENDOR_NSC, +}; +extern enum x86_cpu_vendor __x86_cpu_vendor; + +static inline enum x86_cpu_level x86_get_cpu_level(void) { + + return __x86_cpu_level; +} + +static inline enum x86_cpu_vendor x86_get_cpu_vendor(void) { + return __x86_cpu_vendor; +} + + +__END_CDECLS + diff --git a/arch/x86/rules.mk b/arch/x86/rules.mk index db18b5b3..cff427cd 100644 --- a/arch/x86/rules.mk +++ b/arch/x86/rules.mk @@ -43,6 +43,7 @@ GLOBAL_DEFINES += \ MODULE_SRCS += \ $(SUBARCH_DIR)/start.S \ +\ $(SUBARCH_DIR)/asm.S \ $(SUBARCH_DIR)/exceptions.S \ $(SUBARCH_DIR)/mmu.c \ @@ -50,10 +51,11 @@ MODULE_SRCS += \ \ $(LOCAL_DIR)/arch.c \ $(LOCAL_DIR)/cache.c \ + $(LOCAL_DIR)/descriptor.c \ + $(LOCAL_DIR)/faults.c \ + $(LOCAL_DIR)/feature.c \ $(LOCAL_DIR)/gdt.S \ $(LOCAL_DIR)/thread.c \ - $(LOCAL_DIR)/faults.c \ - $(LOCAL_DIR)/descriptor.c \ # legacy x86's dont have fpu support ifneq ($(CPU),legacy)