diff options
author | Richard Braun <rbraun@sceen.net> | 2018-07-07 18:58:33 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-07-07 18:58:33 +0200 |
commit | 2c55123b8ce46aaf10d7ebda16cb46252e8facc5 (patch) | |
tree | 3e751b367d053c6419037d483a9bf9abca3cac81 | |
parent | 29c42a7d4f82f9d8f4af5ed96e56274851977978 (diff) |
x86/cpu: improve CPU flags handling
-rw-r--r-- | arch/x86/machine/boot_asm.S | 8 | ||||
-rw-r--r-- | arch/x86/machine/cpu.c | 109 | ||||
-rw-r--r-- | arch/x86/machine/cpu.h | 52 | ||||
-rw-r--r-- | arch/x86/machine/cpu_i.h | 19 | ||||
-rw-r--r-- | arch/x86/machine/pmap.c | 12 |
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 */ |