[arch][x86] start of cpu detection and feature detection

This commit is contained in:
Travis Geiselbrecht
2019-01-03 23:42:31 -08:00
parent 4d276a2406
commit 18330c5948
6 changed files with 359 additions and 23 deletions

View File

@@ -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 */

View File

@@ -13,6 +13,7 @@
#include <arch/x86.h>
#include <arch/x86/mmu.h>
#include <arch/x86/descriptor.h>
#include <arch/x86/feature.h>
#include <arch/fpu.h>
#include <arch/mmu.h>
#include <platform.h>
@@ -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();
}

170
arch/x86/feature.c Normal file
View File

@@ -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 <arch/x86/feature.h>
#include <lk/bits.h>
#include <lk/debug.h>
#include <lk/trace.h>
#include <arch/x86.h>
#include <string.h>
#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();
}

View File

@@ -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"); }

View File

@@ -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 <lk/compiler.h>
__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

View File

@@ -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)