diff --git a/app/config.c b/app/config.c index 6a7f238..5547be4 100644 --- a/app/config.c +++ b/app/config.c @@ -66,16 +66,12 @@ #define SEL_AREA (SEL_W * SEL_H) -static const char *cpu_mode_str[] = { "PAR", "SEQ", "RR " }; - //------------------------------------------------------------------------------ // Private Variables //------------------------------------------------------------------------------ static uint16_t popup_save_buffer[POP_W * POP_H]; -static bool smp_enabled = true; - //------------------------------------------------------------------------------ // Public Variables //------------------------------------------------------------------------------ @@ -91,6 +87,8 @@ error_mode_t error_mode = ERROR_MODE_NONE; cpu_state_t cpu_state[MAX_CPUS]; +bool smp_enabled = true; + bool enable_temperature = true; bool enable_trace = false; @@ -867,7 +865,7 @@ void config_menu(bool initial) } if (cpu_mode != old_cpu_mode) { - display_cpu_mode(cpu_mode_str[cpu_mode]); + display_cpu_topology(); restart = true; } diff --git a/app/config.h b/app/config.h index bc9b31d..82c37af 100644 --- a/app/config.h +++ b/app/config.h @@ -45,6 +45,8 @@ extern error_mode_t error_mode; extern cpu_state_t cpu_state[MAX_CPUS]; +extern bool smp_enabled; + extern bool enable_temperature; extern bool enable_trace; diff --git a/app/display.c b/app/display.c index d97a34a..055de39 100644 --- a/app/display.c +++ b/app/display.c @@ -37,6 +37,8 @@ static const char spin_state[NUM_SPIN_STATES] = { '|', '/', '-', '\\' }; +static const char *cpu_mode_str[] = { "PAR", "SEQ", "RR " }; + //------------------------------------------------------------------------------ // Private Variables //------------------------------------------------------------------------------ @@ -91,8 +93,8 @@ void display_init(void) prints(4, 0, "L3 Cache: N/A | Testing: "); prints(5, 0, "Memory : N/A | Pattern: "); prints(6, 0, "-------------------------------------------------------------------------------"); - prints(7, 0, "CPU cores: available, enabled | Time: Status: Init. "); - prints(8, 0, "Run mode : PAR Using: | Pass: Errors: "); + prints(7, 0, "CPU: SMP: N/A | Time: Status: Init. "); + prints(8, 0, "Using: | Pass: Errors: "); prints(9, 0, "-------------------------------------------------------------------------------"); // Redraw lines using box drawing characters. @@ -133,11 +135,6 @@ void display_init(void) if (clks_per_msec) { display_cpu_clk((int)(clks_per_msec / 1000)); } - if (cpuid_info.flags.lm) { - display_cpu_addr_mode("(x64)"); - } else if (cpuid_info.flags.pae) { - display_cpu_addr_mode("(PAE)"); - } if (l1_cache) { display_l1_cache_size(l1_cache); } @@ -167,6 +164,55 @@ void display_init(void) scroll_message_row = ROW_SCROLL_T; } +void display_cpu_topology(void) +{ + extern int num_enabled_cpus; + int num_cpu_sockets = 1; + + if(smp_enabled) { + printf(7,30, "%uT (%s)", num_enabled_cpus, cpu_mode_str[cpu_mode]); + } else { + prints(7,30, "Disabled"); + } + + // If topology failed, assume topology according to APIC + if(cpuid_info.topology.core_count <= 0) { + + cpuid_info.topology.core_count = num_enabled_cpus; + cpuid_info.topology.thread_count = num_enabled_cpus; + + if(cpuid_info.flags.htt && num_enabled_cpus >= 2 && num_enabled_cpus % 2 == 0) { + cpuid_info.topology.core_count /= 2; + } + } + + // Compute number of sockets according to individual CPU core count + if(num_enabled_cpus > cpuid_info.topology.thread_count && + num_enabled_cpus % cpuid_info.topology.thread_count == 0) { + + num_cpu_sockets = num_enabled_cpus / cpuid_info.topology.thread_count; + } + + // Temporary workaround for Hybrid CPUs. + // TODO: run cpuid on each core to get correct P+E topology + if(cpuid_info.topology.is_hybrid) { + printf(7, 5, "%u Threads (%s)", cpuid_info.topology.thread_count, + cpuid_info.flags.lm ? "X64" : "PAE"); + return; + } + + if(num_cpu_sockets < 2) { + printf(7, 5, "%uC/%uT (%s)", cpuid_info.topology.core_count, + cpuid_info.topology.thread_count, + cpuid_info.flags.lm ? "X64" : "PAE"); + } else { + printf(7, 5, "%uS/%uC/%uT (%s)", num_cpu_sockets, + num_cpu_sockets * cpuid_info.topology.core_count, + num_cpu_sockets * cpuid_info.topology.thread_count, + cpuid_info.flags.lm ? "X64" : "PAE"); + } +} + void post_display_init(void) { print_smbios_startup_info(); diff --git a/app/display.h b/app/display.h index b166edf..3905078 100644 --- a/app/display.h +++ b/app/display.h @@ -38,9 +38,6 @@ #define display_cpu_clk(freq) \ printf(1, 10, "%i MHz", freq) -#define display_cpu_addr_mode(str) \ - prints(1, 20, str) - #define display_l1_cache_size(size) \ printf(2, 9, "%6kB", (uintptr_t)(size)); @@ -72,21 +69,12 @@ dmicol = prints(23, dmicol, sys_man); \ prints(23, dmicol + 1, sys_sku); -#define display_available_cpus(count) \ - printi(7, 10, count, 4, false, false) - -#define display_enabled_cpus(count) \ - printi(7, 25, count, 4, false, false) - -#define display_cpu_mode(str) \ - prints(8, 11, str) - #define display_active_cpu(cpu_num) \ - prints(8, 25, "core #"); \ - printi(8, 31, cpu_num, 3, false, true) + prints(8, 7, "Core #"); \ + printi(8, 13, cpu_num, 3, false, true) #define display_all_active \ - prints(8, 25, "all cores") + prints(8, 7, "All Cores") #define display_spinner(spin_state) \ printc(7, 76, spin_state) @@ -196,6 +184,8 @@ extern int scroll_message_row; void display_init(void); +void display_cpu_topology(void); + void post_display_init(void); void display_start_run(void); diff --git a/app/main.c b/app/main.c index 53ba1b2..8769668 100644 --- a/app/main.c +++ b/app/main.c @@ -67,8 +67,6 @@ static volatile int init_state = 0; -static int num_enabled_cpus = 1; - static uintptr_t low_load_addr; static uintptr_t high_load_addr; @@ -100,6 +98,7 @@ efi_info_t saved_efi_info; uint8_t chunk_index[MAX_CPUS]; int num_active_cpus = 0; +int num_enabled_cpus = 1; int master_cpu = 0; @@ -230,8 +229,6 @@ static void global_init(void) clear_message_area(); - display_available_cpus(num_available_cpus); - num_enabled_cpus = 0; for (int i = 0; i < num_available_cpus; i++) { if (cpu_state[i] == CPU_STATE_ENABLED) { @@ -239,7 +236,7 @@ static void global_init(void) num_enabled_cpus++; } } - display_enabled_cpus(num_enabled_cpus); + display_cpu_topology(); master_cpu = 0; diff --git a/system/cpuid.c b/system/cpuid.c index 4aedb95..f954f36 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. // // Derived from memtest86+ cpuid.h -// (original contained no copyright statement) + #include #include "cpuid.h" +#include "display.h" //------------------------------------------------------------------------------ // Public Variables @@ -20,7 +22,7 @@ cpuid_info_t cpuid_info; void cpuid_init(void) { - uint32_t dummy[3]; + uint32_t reg[4]; char *p, *q; // Get the max standard cpuid & vendor ID. @@ -46,26 +48,26 @@ void cpuid_init(void) if (cpuid_info.max_cpuid >= 6) { cpuid(0x6, 0, &cpuid_info.dts_pmp, - &dummy[0], - &dummy[1], - &dummy[2] + ®[0], + ®[1], + ®[2] ); } // Get the max extended cpuid. cpuid(0x80000000, 0, &cpuid_info.max_xcpuid, - &dummy[0], - &dummy[1], - &dummy[2] + ®[0], + ®[1], + ®[2] ); // Get extended feature flags, only save EDX. if (cpuid_info.max_xcpuid >= 0x80000001) { cpuid(0x80000001, 0, - &dummy[0], - &dummy[1], - &dummy[2], + ®[0], + ®[1], + ®[2], &cpuid_info.flags.raw[2] ); } @@ -112,16 +114,16 @@ void cpuid_init(void) // AMD Processors if (cpuid_info.max_xcpuid >= 0x80000005) { cpuid(0x80000005, 0, - &dummy[0], - &dummy[1], + ®[0], + ®[1], &cpuid_info.cache_info.raw[0], &cpuid_info.cache_info.raw[1] ); } if (cpuid_info.max_xcpuid >= 0x80000006) { cpuid(0x80000006, 0, - &dummy[0], - &dummy[1], + ®[0], + ®[1], &cpuid_info.cache_info.raw[2], &cpuid_info.cache_info.raw[3] ); @@ -132,4 +134,84 @@ void cpuid_init(void) // No cpuid info to read. break; } + + // Detect CPU Topology (Core/Thread) infos + cpuid_info.topology.core_count = -1; + cpuid_info.topology.thread_count = -1; + cpuid_info.topology.is_hybrid = 0; + cpuid_info.topology.ecore_count = -1; + cpuid_info.topology.pcore_count = -1; + + int thread_per_core = 1; + + switch (cpuid_info.vendor_id.str[0]) { + case 'A': + // AMD Processors + if (cpuid_info.max_xcpuid >= 0x80000008) { + + cpuid(0x80000008, 0, ®[0], ®[1], ®[2], ®[3]); + cpuid_info.topology.thread_count = (reg[2] & 0xFF) + 1; + + if (cpuid_info.max_xcpuid >= 0x8000001E) { + cpuid(0x8000001E, 0, ®[0], ®[1], ®[2], ®[3]); + + if (((reg[1] >> 8) & 0x3) > 0) { + thread_per_core = 2; + } + } else if (cpuid_info.flags.htt) { + thread_per_core = 2; + } + cpuid_info.topology.core_count = cpuid_info.topology.thread_count / thread_per_core; + } + break; + case 'C': + // VIA / CentaurHauls + break; + case 'G': + if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta + // Intel + if (cpuid_info.max_cpuid >= 0xB) { + + // Populate Hybrid Status (CPUID 7.EDX[15]) for Alder Lake+ + cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]); + if (reg[3] & (1 << 15)) { + cpuid_info.topology.is_hybrid = 1; + } + + for (int i=0; i < 4; i++) { + cpuid(0xB, i, ®[0], ®[1], ®[2], ®[3]); + + switch((reg[2] >> 8) & 0xFF) { + case 1: // SMT + thread_per_core = reg[1] & 0xFF; + break; + case 2: // Cores + cpuid_info.topology.thread_count = reg[1] & 0xFFFF; + break; + default: + continue; + } + } + + cpuid_info.topology.core_count = cpuid_info.topology.thread_count / thread_per_core; + + } else if (cpuid_info.max_cpuid >= 0x4) { + cpuid(4, 0, ®[0], ®[1], ®[2], ®[3]); + + cpuid_info.topology.core_count = (reg[0] >> 26) + 1; + cpuid_info.topology.thread_count = cpuid_info.topology.core_count; + + if (cpuid_info.flags.htt){ + cpuid_info.topology.thread_count *= 2; + } + } else if (cpuid_info.max_cpuid >= 0x2) { + if(cpuid_info.flags.htt){ + cpuid_info.topology.core_count = 1; + cpuid_info.topology.thread_count = 2; + } + } + break; + default: + break; + } } diff --git a/system/cpuid.h b/system/cpuid.h index de4ced0..f4be953 100644 --- a/system/cpuid.h +++ b/system/cpuid.h @@ -8,9 +8,9 @@ * *//* * Copyright (C) 2020-2022 Martin Whitaker. + * Copyright (C) 2004-2022 Sam Demeulemeester. * * Derived from memtest86+ cpuid.h - * (original contained no copyright statement) */ #include @@ -133,6 +133,14 @@ typedef union { }; } cpuid_custom_features; +typedef struct { + int core_count; + int thread_count; + int is_hybrid; + int ecore_count; + int pcore_count; +} topology_t; + typedef struct { uint32_t max_cpuid; uint32_t max_xcpuid; @@ -144,6 +152,7 @@ typedef struct { cpuid_brand_string_t brand_id; cpuid_cache_info_t cache_info; cpuid_custom_features custom; + topology_t topology; } cpuid_info_t; typedef union {