summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-07-07 18:58:33 +0200
committerRichard Braun <rbraun@sceen.net>2018-07-07 18:58:33 +0200
commit2c55123b8ce46aaf10d7ebda16cb46252e8facc5 (patch)
tree3e751b367d053c6419037d483a9bf9abca3cac81
parent29c42a7d4f82f9d8f4af5ed96e56274851977978 (diff)
x86/cpu: improve CPU flags handling
-rw-r--r--arch/x86/machine/boot_asm.S8
-rw-r--r--arch/x86/machine/cpu.c109
-rw-r--r--arch/x86/machine/cpu.h52
-rw-r--r--arch/x86/machine/cpu_i.h19
-rw-r--r--arch/x86/machine/pmap.c12
5 files changed, 154 insertions, 46 deletions
diff --git a/arch/x86/machine/boot_asm.S b/arch/x86/machine/boot_asm.S
index bfec4483..2b350f25 100644
--- a/arch/x86/machine/boot_asm.S
+++ b/arch/x86/machine/boot_asm.S
@@ -132,13 +132,13 @@ ASM_END(boot_gdtr)
ASM_ENTRY(boot_check_long_mode)
pushl %eax
pushl %ebx
- movl $0x80000000, %eax
+ movl $CPU_CPUID_EXT_BIT, %eax
cpuid
- cmpl $0x80000000, %eax
+ cmpl $CPU_CPUID_EXT_BIT, %eax
jbe boot_no_long_mode
- movl $0x80000001, %eax
+ movl $(CPU_CPUID_EXT_BIT | 1), %eax
cpuid
- testl $CPU_FEATURE4_LM, %edx
+ testl $CPU_CPUID_EXT1_EDX_LM, %edx
jz boot_no_long_mode
popl %ebx
popl %eax
diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c
index e8cdb19d..7edcc805 100644
--- a/arch/x86/machine/cpu.c
+++ b/arch/x86/machine/cpu.c
@@ -253,6 +253,18 @@ static const struct cpu_vendor cpu_vendors[] = {
{ CPU_VENDOR_AMD, "AuthenticAMD" },
};
+static const char *cpu_feature_names[] = {
+ [CPU_FEATURE_FPU] = "fpu",
+ [CPU_FEATURE_PSE] = "pse",
+ [CPU_FEATURE_PAE] = "pae",
+ [CPU_FEATURE_MSR] = "msr",
+ [CPU_FEATURE_CX8] = "cx8",
+ [CPU_FEATURE_APIC] = "apic",
+ [CPU_FEATURE_PGE] = "pge",
+ [CPU_FEATURE_1GP] = "1gp",
+ [CPU_FEATURE_LM] = "lm",
+};
+
static void __init
cpu_exc_handler_init(struct cpu_exc_handler *handler, cpu_exc_handler_fn_t fn)
{
@@ -851,6 +863,40 @@ cpu_tss_init_i386_double_fault(struct cpu_tss *tss, const void *df_stack_top)
}
#endif /* __LP64__ */
+static void __init
+cpu_feature_map_init(struct cpu_feature_map *map)
+{
+ bitmap_zero(map->flags, CPU_NR_FEATURES);
+}
+
+static void __init
+cpu_feature_map_cset(struct cpu_feature_map *map, unsigned int word,
+ unsigned int mask, enum cpu_feature feature)
+{
+ if (word & mask) {
+ bitmap_set(map->flags, feature);
+ }
+}
+
+static void __init
+cpu_feature_map_basic1_edx(struct cpu_feature_map *map, unsigned int edx)
+{
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_FPU, CPU_FEATURE_FPU);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_PSE, CPU_FEATURE_PSE);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_PAE, CPU_FEATURE_PAE);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_MSR, CPU_FEATURE_MSR);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_CX8, CPU_FEATURE_CX8);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_APIC, CPU_FEATURE_APIC);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_BASIC1_EDX_PGE, CPU_FEATURE_PGE);
+}
+
+static void __init
+cpu_feature_map_ext1_edx(struct cpu_feature_map *map, unsigned int edx)
+{
+ cpu_feature_map_cset(map, edx, CPU_CPUID_EXT1_EDX_1GP, CPU_FEATURE_1GP);
+ cpu_feature_map_cset(map, edx, CPU_CPUID_EXT1_EDX_LM, CPU_FEATURE_LM);
+}
+
static struct cpu_tss * __init
cpu_get_tss(struct cpu *cpu)
{
@@ -1021,13 +1067,13 @@ cpu_build(struct cpu *cpu)
>> CPU_CPUID_CLFLUSH_SHIFT) * 8;
cpu->initial_apic_id = (ebx & CPU_CPUID_APIC_ID_MASK)
>> CPU_CPUID_APIC_ID_SHIFT;
- cpu->features1 = ecx;
- cpu->features2 = edx;
+ cpu_feature_map_init(&cpu->feature_map);
+ cpu_feature_map_basic1_edx(&cpu->feature_map, edx);
- eax = 0x80000000;
+ eax = CPU_CPUID_EXT_BIT;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
- if (eax <= 0x80000000) {
+ if (eax <= CPU_CPUID_EXT_BIT) {
max_extended = 0;
} else {
max_extended = eax;
@@ -1035,32 +1081,28 @@ cpu_build(struct cpu *cpu)
cpu->cpuid_max_extended = max_extended;
- if (max_extended < 0x80000001) {
- cpu->features3 = 0;
- cpu->features4 = 0;
- } else {
- eax = 0x80000001;
+ if (max_extended >= (CPU_CPUID_EXT_BIT | 1)) {
+ eax = CPU_CPUID_EXT_BIT | 1;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
- cpu->features3 = ecx;
- cpu->features4 = edx;
+ cpu_feature_map_ext1_edx(&cpu->feature_map, edx);
}
- if (max_extended >= 0x80000004) {
- eax = 0x80000002;
+ if (max_extended >= (CPU_CPUID_EXT_BIT | 4)) {
+ eax = CPU_CPUID_EXT_BIT | 2;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
memcpy(cpu->model_name, &eax, sizeof(eax));
memcpy(cpu->model_name + 4, &ebx, sizeof(ebx));
memcpy(cpu->model_name + 8, &ecx, sizeof(ecx));
memcpy(cpu->model_name + 12, &edx, sizeof(edx));
- eax = 0x80000003;
+ eax = CPU_CPUID_EXT_BIT | 3;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
memcpy(cpu->model_name + 16, &eax, sizeof(eax));
memcpy(cpu->model_name + 20, &ebx, sizeof(ebx));
memcpy(cpu->model_name + 24, &ecx, sizeof(ecx));
memcpy(cpu->model_name + 28, &edx, sizeof(edx));
- eax = 0x80000004;
+ eax = CPU_CPUID_EXT_BIT | 4;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
memcpy(cpu->model_name + 32, &eax, sizeof(eax));
memcpy(cpu->model_name + 36, &ebx, sizeof(ebx));
@@ -1070,8 +1112,8 @@ cpu_build(struct cpu *cpu)
cpu->model_name[sizeof(cpu->model_name) - 1] = '\0';
}
- if (max_extended >= 0x80000008) {
- eax = 0x80000008;
+ if (max_extended >= (CPU_CPUID_EXT_BIT | 8)) {
+ eax = CPU_CPUID_EXT_BIT | 8;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
cpu->phys_addr_width = (unsigned short)eax & 0xff;
cpu->virt_addr_width = ((unsigned short)eax >> 8) & 0xff;
@@ -1122,7 +1164,7 @@ cpu_panic_on_missing_feature(const char *feature)
static void __init
cpu_check(const struct cpu *cpu)
{
- if (!(cpu->features2 & CPU_FEATURE2_FPU)) {
+ if (!cpu_has_feature(cpu, CPU_FEATURE_FPU)) {
cpu_panic_on_missing_feature("fpu");
}
@@ -1133,7 +1175,7 @@ cpu_check(const struct cpu *cpu)
* just disabled when building with it.
*/
#if !defined(__LP64__) && !defined(__clang__)
- if (!(cpu->features2 & CPU_FEATURE2_CX8)) {
+ if (!cpu_has_feature(cpu, CPU_FEATURE_CX8)) {
cpu_panic_on_missing_feature("cx8");
}
#endif
@@ -1154,6 +1196,9 @@ INIT_OP_DEFINE(cpu_check_bsp,
void __init
cpu_log_info(const struct cpu *cpu)
{
+ char features[60], *ptr;
+ size_t size, bytes;
+
log_info("cpu%u: %s, type %u, family %u, model %u, stepping %u",
cpu->id, cpu->vendor_str, cpu->type, cpu->family, cpu->model,
cpu->stepping);
@@ -1170,6 +1215,32 @@ cpu_log_info(const struct cpu *cpu)
log_info("cpu%u: frequency: %llu.%02llu MHz", cpu->id,
(unsigned long long)cpu_freq / 1000000,
(unsigned long long)cpu_freq % 1000000);
+
+ ptr = features;
+ size = sizeof(features);
+
+ for (size_t i = 0; i < ARRAY_SIZE(cpu_feature_names); i++) {
+ if (!cpu_has_feature(cpu, i)) {
+ continue;
+ }
+
+ assert(strlen(cpu_feature_names[i]) < sizeof(features));
+ bytes = snprintf(ptr, size, " %s", cpu_feature_names[i]);
+
+ if (bytes >= size) {
+ *ptr = '\0';
+ log_info("cpu%u:%s", cpu->id, features);
+ ptr = features;
+ size = sizeof(features);
+ i--;
+ continue;
+ }
+
+ ptr += bytes;
+ size -= bytes;
+ }
+
+ log_info("cpu%u:%s", cpu->id, features);
}
void __init
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h
index 94291acc..033c17dc 100644
--- a/arch/x86/machine/cpu.h
+++ b/arch/x86/machine/cpu.h
@@ -138,26 +138,46 @@
#define CPU_EFER_LME 0x00000100
/*
- * Feature2 flags.
- *
- * TODO Better names.
+ * Bit used to make extended CPUID requests.
+ */
+#define CPU_CPUID_EXT_BIT 0x80000000
+
+/*
+ * CPU feature flags as returned by CPUID.
*/
-#define CPU_FEATURE2_FPU 0x00000001
-#define CPU_FEATURE2_PSE 0x00000008
-#define CPU_FEATURE2_PAE 0x00000040
-#define CPU_FEATURE2_MSR 0x00000020
-#define CPU_FEATURE2_CX8 0x00000100
-#define CPU_FEATURE2_APIC 0x00000200
-#define CPU_FEATURE2_PGE 0x00002000
+#define CPU_CPUID_BASIC1_EDX_FPU 0x00000001
+#define CPU_CPUID_BASIC1_EDX_PSE 0x00000008
+#define CPU_CPUID_BASIC1_EDX_PAE 0x00000040
+#define CPU_CPUID_BASIC1_EDX_MSR 0x00000020
+#define CPU_CPUID_BASIC1_EDX_CX8 0x00000100
+#define CPU_CPUID_BASIC1_EDX_APIC 0x00000200
+#define CPU_CPUID_BASIC1_EDX_PGE 0x00002000
+#define CPU_CPUID_EXT1_EDX_1GP 0x04000000
+#define CPU_CPUID_EXT1_EDX_LM 0x20000000
+
+#ifndef __ASSEMBLER__
-#define CPU_FEATURE4_1GP 0x04000000
-#define CPU_FEATURE4_LM 0x20000000
+enum cpu_feature {
+ CPU_FEATURE_FPU,
+ CPU_FEATURE_PSE,
+ CPU_FEATURE_PAE,
+ CPU_FEATURE_MSR,
+ CPU_FEATURE_CX8,
+ CPU_FEATURE_APIC,
+ CPU_FEATURE_PGE,
+ CPU_FEATURE_1GP,
+ CPU_FEATURE_LM,
+ CPU_NR_FEATURES
+};
+
+#endif /* __ASSEMBLER__ */
#include <machine/cpu_i.h>
#ifndef __ASSEMBLER__
#include <stdalign.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdnoreturn.h>
@@ -429,6 +449,12 @@ cpu_from_id(unsigned int cpu)
return percpu_ptr(cpu_desc, cpu);
}
+static inline bool
+cpu_has_feature(const struct cpu *cpu, enum cpu_feature feature)
+{
+ return cpu_feature_map_test(&cpu->feature_map, feature);
+}
+
static __always_inline void
cpu_enable_pse(void)
{
@@ -444,7 +470,7 @@ cpu_enable_pae(void)
static inline int
cpu_has_global_pages(void)
{
- return cpu_current()->features2 & CPU_FEATURE2_PGE;
+ return cpu_has_feature(cpu_current(), CPU_FEATURE_PGE);
}
/*
diff --git a/arch/x86/machine/cpu_i.h b/arch/x86/machine/cpu_i.h
index 66fe5f51..d3cc4a38 100644
--- a/arch/x86/machine/cpu_i.h
+++ b/arch/x86/machine/cpu_i.h
@@ -47,8 +47,11 @@
#ifndef __ASSEMBLER__
#include <stdalign.h>
+#include <stdbool.h>
#include <stdint.h>
+#include <kern/bitmap.h>
+
struct cpu_tss {
#ifdef __LP64__
uint32_t reserved0;
@@ -108,6 +111,10 @@ struct cpu_gdt {
#define CPU_VENDOR_ID_SIZE 13
#define CPU_MODEL_NAME_SIZE 49
+struct cpu_feature_map {
+ BITMAP_DECLARE(flags, CPU_NR_FEATURES);
+};
+
struct cpu {
unsigned int id;
unsigned int apic_id;
@@ -122,10 +129,7 @@ struct cpu {
unsigned int stepping;
unsigned int clflush_size;
unsigned int initial_apic_id;
- unsigned int features1; // TODO Use a struct bitmap
- unsigned int features2;
- unsigned int features3;
- unsigned int features4;
+ struct cpu_feature_map feature_map;
unsigned short phys_addr_width;
unsigned short virt_addr_width;
@@ -163,6 +167,13 @@ struct cpu {
*/
extern void *cpu_local_area;
+static inline bool
+cpu_feature_map_test(const struct cpu_feature_map *map,
+ enum cpu_feature feature)
+{
+ return bitmap_test(map->flags, feature);
+}
+
/*
* Return the content of the EFLAGS register.
*
diff --git a/arch/x86/machine/pmap.c b/arch/x86/machine/pmap.c
index 73c31ca4..f77c6aa5 100644
--- a/arch/x86/machine/pmap.c
+++ b/arch/x86/machine/pmap.c
@@ -342,17 +342,17 @@ pmap_boot_get_pgsize(void)
unsigned int eax, ebx, ecx, edx;
#ifdef __LP64__
- eax = 0x80000000;
+ eax = CPU_CPUID_EXT_BIT;
cpu_cpuid(&eax, &ebx, &ecx, &edx);
- if (eax <= 0x80000000) {
+ if (eax <= CPU_CPUID_EXT_BIT) {
goto out;
}
- eax = 0x80000001;
+ eax = (CPU_CPUID_EXT_BIT | 1);
cpu_cpuid(&eax, &ebx, &ecx, &edx);
- if (edx & CPU_FEATURE4_1GP) {
+ if (edx & CPU_CPUID_EXT1_EDX_1GP) {
return (1 << PMAP_L2_SKIP);
}
@@ -370,13 +370,13 @@ out:
cpu_cpuid(&eax, &ebx, &ecx, &edx);
#ifdef CONFIG_X86_PAE
- if (!(edx & CPU_FEATURE2_PAE)) {
+ if (!(edx & CPU_CPUID_BASIC1_EDX_PAE)) {
boot_panic(pmap_panic_no_pae);
}
return (1 << PMAP_L1_SKIP);
#else /* CONFIG_X86_PAE */
- if (edx & CPU_FEATURE2_PSE) {
+ if (edx & CPU_CPUID_BASIC1_EDX_PSE) {
return (1 << PMAP_L1_SKIP);
}
#endif /* CONFIG_X86_PAE */