diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index c8c960d..6833ce4 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: compiler: [gcc, clang] - os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04] + os: [ubuntu-20.04, ubuntu-22.04] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/expired.yml b/.github/workflows/expired.yml index 7e48f6e..d29b395 100644 --- a/.github/workflows/expired.yml +++ b/.github/workflows/expired.yml @@ -6,7 +6,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-milestones: 'future,alpha,beta,release' diff --git a/README.md b/README.md index c9fafcf..896d6a2 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ recognised: * 9600 * 19200 * 38400 - * 54600 + * 57600 * 115200 (default if not specified or invalid) * 230400 diff --git a/app/display.c b/app/display.c index 4e6b14a..27f0e1e 100644 --- a/app/display.c +++ b/app/display.c @@ -409,6 +409,7 @@ void check_input(void) return; } else if (big_status_displayed) { restore_big_status(); + enable_big_status = false; } switch (input_key) { diff --git a/app/main.c b/app/main.c index 19098e6..565ff78 100644 --- a/app/main.c +++ b/app/main.c @@ -251,6 +251,8 @@ static void global_init(void) error_init(); + temperature_init(); + initial_config(); clear_message_area(); @@ -669,7 +671,8 @@ void main(void) if (error_count == 0) { display_status("Pass "); display_big_status(true); - //display_notice("** Pass completed, no errors **"); + } else { + display_big_status(false); } } } diff --git a/app/version.h b/app/version.h index 8b321b9..d409fc8 100644 --- a/app/version.h +++ b/app/version.h @@ -1,2 +1,2 @@ -#define MT_VERSION "6.10" +#define MT_VERSION "6.20" #define GIT_HASH "unknown" diff --git a/boot/efisetup.c b/boot/efisetup.c index 4362215..7e0a510 100644 --- a/boot/efisetup.c +++ b/boot/efisetup.c @@ -502,6 +502,10 @@ static efi_status_t set_screen_info(boot_params_t *boot_params) status = EFI_SUCCESS; } efi_call_bs(free_pool, handles); + } else if (status == EFI_NOT_FOUND) { + // This may be a headless system. We can still output to a serial console. + boot_params->screen_info.orig_video_isVGA = VIDEO_TYPE_NONE; + status = EFI_SUCCESS; } return status; diff --git a/build64/Makefile b/build64/Makefile index ed76db0..799133e 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -78,11 +78,11 @@ boot/header.o : | ../boot/sbat.csv boot/startup.o: ../boot/startup64.S ../boot/boot.h @mkdir -p boot - $(CC) -x assembler-with-cpp -c -I../boot -o $@ $< + $(CC) -m64 -x assembler-with-cpp -c -I../boot -o $@ $< boot/%.o: ../boot/%.S ../boot/boot.h app/build_version.h @mkdir -p boot - $(CC) -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< + $(CC) -m64 -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< boot/efisetup.o: ../boot/efisetup.c @mkdir -p boot diff --git a/system/cpuid.c b/system/cpuid.c index 260f138..2200b56 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -4,7 +4,7 @@ // // Derived from memtest86+ cpuid.h - +#include #include #include "cpuid.h" @@ -36,7 +36,7 @@ void cpuid_init(void) // Get the processor family information & feature flags. if (cpuid_info.max_cpuid >= 1) { cpuid(0x1, 0, - &cpuid_info.version.raw, + &cpuid_info.version.raw[0], &cpuid_info.proc_info.raw, &cpuid_info.flags.raw[1], &cpuid_info.flags.raw[0] @@ -65,8 +65,8 @@ void cpuid_init(void) if (cpuid_info.max_xcpuid >= 0x80000001) { cpuid(0x80000001, 0, ®[0], + &cpuid_info.version.raw[1], ®[1], - ®[2], &cpuid_info.flags.raw[2] ); } @@ -108,30 +108,21 @@ void cpuid_init(void) } // Get cache information. - switch (cpuid_info.vendor_id.str[0]) { - case 'A': - // AMD Processors - if (cpuid_info.max_xcpuid >= 0x80000005) { - cpuid(0x80000005, 0, - ®[0], - ®[1], - &cpuid_info.cache_info.raw[0], - &cpuid_info.cache_info.raw[1] - ); - } - if (cpuid_info.max_xcpuid >= 0x80000006) { - cpuid(0x80000006, 0, - ®[0], - ®[1], - &cpuid_info.cache_info.raw[2], - &cpuid_info.cache_info.raw[3] - ); - } - break; - case 'G': - // Intel Processors - // No cpuid info to read. - break; + if (cpuid_info.max_xcpuid >= 0x80000005) { + cpuid(0x80000005, 0, + ®[0], + ®[1], + &cpuid_info.cache_info.raw[0], + &cpuid_info.cache_info.raw[1] + ); + } + if (cpuid_info.max_xcpuid >= 0x80000006) { + cpuid(0x80000006, 0, + ®[0], + ®[1], + &cpuid_info.cache_info.raw[2], + &cpuid_info.cache_info.raw[3] + ); } // Detect CPU Topology (Core/Thread) infos @@ -176,7 +167,8 @@ void cpuid_init(void) } break; case 'C': - // VIA / CentaurHauls + // Cyrix / VIA / CentaurHauls / Zhaoxin + cpuid_info.flags.htt = false; break; case 'G': if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta diff --git a/system/cpuid.h b/system/cpuid.h index a16c1ae..c84fd27 100644 --- a/system/cpuid.h +++ b/system/cpuid.h @@ -29,7 +29,7 @@ typedef enum { */ typedef union { - uint32_t raw; + uint32_t raw[2]; struct { uint32_t stepping : 4; uint32_t model : 4; @@ -39,6 +39,7 @@ typedef union { uint32_t extendedModel : 4; uint32_t extendedFamily : 8; uint32_t : 4; + uint32_t extendedBrandID : 32; // AMD Only }; } cpuid_version_t; @@ -122,7 +123,7 @@ typedef union { } cpuid_brand_string_t; typedef union { - uint32_t raw[12]; + uint32_t raw[4]; struct { uint32_t : 24; uint32_t l1_i_size : 8; diff --git a/system/cpuinfo.c b/system/cpuinfo.c index a8d1e40..cba579c 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -71,12 +71,45 @@ static void determine_cache_size() l3_cache *= 512; break; case 'C': - // Zhaoxin CPU only - if (cpuid_info.version.family != 7) { + if (cpuid_info.vendor_id.str[5] == 'I') { + // Cyrix + if (cpuid_info.version.family == 5 && cpuid_info.version.model == 4) { + // Media GXm, Geode GXm/GXLV/GX1 + // Cache info in CPUID has a Cyrix-specific encoding so hardcode it + l1_cache = 16; + } + break; + } + // WinChip 2/3, VIA C3/C7/Nano + if (cpuid_info.version.family == 5 || cpuid_info.version.family == 6) { + l1_cache = cpuid_info.cache_info.l1_d_size; + l2_cache = cpuid_info.cache_info.l2_size; + break; + } else if (cpuid_info.version.family != 7) { break; } + // Zhaoxin CPU only /* fall through */ case 'G': + if (cpuid_info.vendor_id.str[9] == 'N') { + // National Semiconductor + if (cpuid_info.version.family == 5) { + switch (cpuid_info.version.model) { + case 4: + // Geode GXm/GXLV/GX1 + // Cache info in CPUID has a Cyrix-specific encoding so hardcode it + l1_cache = 16; + break; + case 5: + // Geode GX2 + l1_cache = cpuid_info.cache_info.l1_d_size; + break; + default: + break; + } + } + break; + } // Intel Processors l1_cache = 0; l2_cache = 0; @@ -460,6 +493,9 @@ static void determine_imc(void) case 0x9: imc_type = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake) break; + case 0xB: + imc_type = IMC_ADL_N; // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only) + break; default: break; } @@ -599,9 +635,9 @@ static void determine_cpu_model(void) // Transmeta Processors - vendor_id starts with "GenuineTMx86" if (cpuid_info.vendor_id.str[7] == 'T' ) { if (cpuid_info.version.family == 5) { - cpu_model = "TM 5x00"; + cpu_model = "Transmeta TM 5x00"; } else if (cpuid_info.version.family == 15) { - cpu_model = "TM 8x00"; + cpu_model = "Transmeta TM 8x00"; } l1_cache = cpuid_info.cache_info.l1_i_size + cpuid_info.cache_info.l1_d_size; l2_cache = cpuid_info.cache_info.l2_size; @@ -647,14 +683,14 @@ static void determine_cpu_model(void) case 2: case 3: case 7: - cpu_model = "Pentium"; + cpu_model = "Intel Pentium"; if (l1_cache == 0) { l1_cache = 8; } break; case 4: case 8: - cpu_model = "Pentium-MMX"; + cpu_model = "Intel Pentium MMX"; if (l1_cache == 0) { l1_cache = 16; } @@ -667,54 +703,54 @@ static void determine_cpu_model(void) switch (cpuid_info.version.model) { case 0: case 1: - cpu_model = "Pentium Pro"; + cpu_model = "Intel Pentium Pro"; break; case 3: case 4: - cpu_model = "Pentium II"; + cpu_model = "Intel Pentium II"; break; case 5: if (l2_cache == 0) { - cpu_model = "Celeron"; + cpu_model = "Intel Celeron"; } else { - cpu_model = "Pentium II"; + cpu_model = "Intel Pentium II"; } break; case 6: if (l2_cache == 128) { - cpu_model = "Celeron"; + cpu_model = "Intel Celeron"; } else { - cpu_model = "Pentium II"; + cpu_model = "Intel Pentium II"; } break; case 7: case 8: case 11: if (l2_cache == 128) { - cpu_model = "Celeron"; + cpu_model = "Intel Celeron"; } else { - cpu_model = "Pentium III"; + cpu_model = "Intel Pentium III"; } break; case 9: if (l2_cache == 512) { - cpu_model = "Celeron M (0.13)"; + cpu_model = "Intel Celeron M (0.13)"; } else { - cpu_model = "Pentium M (0.13)"; + cpu_model = "Intel Pentium M (0.13)"; } break; case 10: - cpu_model = "Pentium III Xeon"; + cpu_model = "Intel Pentium III Xeon"; break; case 12: l1_cache = 24; - cpu_model = "Atom (0.045)"; + cpu_model = "Intel Atom (0.045)"; break; case 13: if (l2_cache == 1024) { - cpu_model = "Celeron M (0.09)"; + cpu_model = "Intel Celeron M (0.09)"; } else { - cpu_model = "Pentium M (0.09)"; + cpu_model = "Intel Pentium M (0.09)"; } break; case 14: @@ -722,7 +758,7 @@ static void determine_cpu_model(void) break; case 15: if (l2_cache == 1024) { - cpu_model = "Pentium E"; + cpu_model = "Intel Pentium E"; } else { cpu_model = "Intel Core 2"; } @@ -737,17 +773,17 @@ static void determine_cpu_model(void) case 1: case 2: if (l2_cache == 128) { - cpu_model = "Celeron"; + cpu_model = "Intel Celeron"; } else { - cpu_model = "Pentium 4"; + cpu_model = "Intel Pentium 4"; } break; case 3: case 4: if (l2_cache == 256) { - cpu_model = "Celeron (0.09)"; + cpu_model = "Intel Celeron (0.09)"; } else { - cpu_model = "Pentium 4 (0.09)"; + cpu_model = "Intel Pentium 4 (0.09)"; } break; case 6: @@ -767,78 +803,40 @@ static void determine_cpu_model(void) // VIA/Cyrix/Centaur Processors with CPUID if (cpuid_info.vendor_id.str[1] == 'e' ) { // CentaurHauls - l1_cache = cpuid_info.cache_info.l1_i_size + cpuid_info.cache_info.l1_d_size; - l2_cache = cpuid_info.cache_info.l2_size >> 8; switch (cpuid_info.version.family) { case 5: - cpu_model = "Centaur 5x86"; + cpu_model = "IDT WinChip C6"; + l1_cache = 32; + // WinChip 2/3 (models 8/9) have brand string break; - case 6: // VIA C3 - switch (cpuid_info.version.model) { - case 10: - cpu_model = "VIA C7 (C5J)"; - l1_cache = 64; - l2_cache = 128; - break; - case 13: - cpu_model = "VIA C7 (C5R)"; - l1_cache = 64; - l2_cache = 128; - break; - case 15: - cpu_model = "VIA Isaiah (CN)"; - l1_cache = 64; - l2_cache = 128; - break; - default: - if (cpuid_info.version.stepping < 8) { - cpu_model = "VIA C3 Samuel2"; - } else { - cpu_model = "VIA C3 Eden"; - } - break; - } default: + // All VIA/Centaur family values >= 6 have brand string break; } } else { /* CyrixInstead */ switch (cpuid_info.version.family) { - case 5: + case 4: switch (cpuid_info.version.model) { - case 0: - cpu_model = "Cyrix 6x86MX/MII"; + case 2: + cpu_model = "Cyrix 5x86"; + l1_cache = 16; break; case 4: - cpu_model = "Cyrix GXm"; + cpu_model = "Cyrix MediaGX/GXi"; + l1_cache = 16; break; default: break; } break; - case 6: // VIA C3 - switch (cpuid_info.version.model) { - case 6: - cpu_model = "Cyrix III"; - break; - case 7: - if (cpuid_info.version.stepping < 8) { - cpu_model = "VIA C3 Samuel2"; - } else { - cpu_model = "VIA C3 Ezra-T"; - } - break; - case 8: - cpu_model = "VIA C3 Ezra-T"; - break; - case 9: - cpu_model = "VIA C3 Nehemiah"; - break; - default: - break; - } - // L1 = L2 = 64 KB from Cyrix III to Nehemiah + case 5: + cpu_model = "Cyrix 6x86/6x86L"; + l1_cache = 16; + // Media GXm (model 4) has brand string + break; + case 6: + cpu_model = "Cyrix 6x86MX/MII"; l1_cache = 64; - l2_cache = 64; break; default: break; @@ -849,10 +847,10 @@ static void determine_cpu_model(void) // Unknown processor - make a guess at the family. switch (cpuid_info.version.family) { case 5: - cpu_model = "586"; + cpu_model = "586-class CPU (unknown)"; break; case 6: - cpu_model = "686"; + cpu_model = "686-class CPU (unknown)"; break; default: cpu_model = "Unidentified Processor"; diff --git a/system/cpuinfo.h b/system/cpuinfo.h index 7e2f97b..5975b0e 100644 --- a/system/cpuinfo.h +++ b/system/cpuinfo.h @@ -8,7 +8,7 @@ * *//* * Copyright (C) 2020-2022 Martin Whitaker. - * Copyright (C) 2004-2022 Sam Demeulemeester. + * Copyright (C) 2004-2023 Sam Demeulemeester. */ #include @@ -47,6 +47,7 @@ #define IMC_KBL_UY 0x3030 // Core 7/8/9th Gen (Kaby/Coffee/Comet/Amber Lake-U/Y) #define IMC_ICL 0x3040 // Core 10th Gen (IceLake-Y) #define IMC_TGL 0x3050 // Core 11th Gen (Tiger Lake-U) +#define IMC_ADL_N 0x3061 // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only) #define IMC_BYT 0x4010 // Atom Bay Trail #define IMC_CDT 0x4020 // Atom Cedar Trail diff --git a/system/hwquirks.c b/system/hwquirks.c index dbff37b..f1fd0ed 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2004-2022 Samuel Demeulemeester +// Copyright (C) 2004-2023 Sam Demeulemeester // // ------------------------ // This file is used to detect quirks on specific hardware @@ -13,6 +13,9 @@ #include "pci.h" #include "unistd.h" #include "cpuinfo.h" +#include "cpuid.h" +#include "config.h" +#include "temperature.h" quirk_t quirk; @@ -64,6 +67,38 @@ static void get_m1541_l2_cache_size(void) if (reg == 0b10) { l2_cache = 1024; } } +static void disable_temp_reporting(void) +{ + enable_temperature = false; +} + +static void amd_k8_revfg_temp(void) +{ + uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8); + + // For Rev F & G, switch sensor if no temperature is reported + if (!((rtcr >> 16) & 0xFF)) { + pci_config_write8(0, 24, 3, AMD_TEMP_REG_K8, rtcr | 0x04); + } + + // K8 Rev G Desktop requires an additional offset. + if (cpuid_info.version.extendedModel < 6 && cpuid_info.version.extendedModel > 7) // Not Rev G + return; + + if (cpuid_info.version.extendedModel == 6 && cpuid_info.version.extendedModel < 9) // Not Desktop + return; + + uint16_t brandID = (cpuid_info.version.extendedBrandID >> 9) & 0x1f; + + if (cpuid_info.version.model == 0xF && (brandID == 0x7 || brandID == 0x9 || brandID == 0xC)) // Mobile (Single Core) + return; + + if (cpuid_info.version.model == 0xB && brandID > 0xB) // Mobile (Dual Core) + return; + + cpu_temp_offset = 21.0f; +} + // --------------------- // -- Public function -- // --------------------- @@ -115,4 +150,53 @@ void quirks_init(void) quirk.process = NULL; } } + + // ------------------------------------------------------ + // -- Early AMD K8 doesn't support temperature reading -- + // ------------------------------------------------------ + // The on-die temperature diode on SH-B0/B3 stepping does not work. + if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF + && cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel == 0) { // Early K8 + if ((cpuid_info.version.model == 4 && cpuid_info.version.stepping == 0) || // SH-B0 ClawHammer (Athlon 64) + (cpuid_info.version.model == 5 && cpuid_info.version.stepping <= 1)) { // SH-B0/B3 SledgeHammer (Opteron) + quirk.id = QUIRK_K8_BSTEP_NOTEMP; + quirk.type |= QUIRK_TYPE_TEMP; + quirk.process = disable_temp_reporting; + } + } + + // --------------------------------------------------- + // -- Late AMD K8 (rev F/G) temp sensor workaround -- + // --------------------------------------------------- + if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF + && cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel >= 4) { // Later K8 + + quirk.id = QUIRK_K8_REVFG_TEMP; + quirk.type |= QUIRK_TYPE_TEMP; + quirk.process = amd_k8_revfg_temp; + } + + // ------------------------------------------------ + // -- AMD K10 CPUs Temp workaround (Errata #319) -- + // ------------------------------------------------ + // Some AMD K10 CPUs on Socket AM2+/F have buggued thermal diode leading + // to inaccurate temperature measurements. Affected steppings: DR-BA/B2/B3, RB-C2 & HY-D0. + if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF + && cpuid_info.version.extendedFamily == 1 && cpuid_info.version.extendedModel == 0) { // AMD K10 + + uint8_t pkg_type = (cpuid_info.version.extendedBrandID >> 28) & 0x0F; + uint32_t dct0_high = pci_config_read32(0, 24, 2, 0x94); // 0x94[8] = 1 for DDR3 + + if (pkg_type == 0b0000 || (pkg_type == 0b0001 && (((dct0_high >> 8) & 1) == 0))) { // Socket F or AM2+ (exclude AM3) + + if (cpuid_info.version.model < 4 || // DR-BA, DR-B2 & DR-B3 + (cpuid_info.version.model == 4 && cpuid_info.version.stepping <= 2) || // RB-C2 + cpuid_info.version.model == 8) { // HY-D0 + + quirk.id = QUIRK_AMD_ERRATA_319; + quirk.type |= QUIRK_TYPE_TEMP; + quirk.process = disable_temp_reporting; + } + } + } } diff --git a/system/hwquirks.h b/system/hwquirks.h index 6005611..daf22b8 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -19,12 +19,16 @@ #define QUIRK_TYPE_SMBUS (1 << 4) #define QUIRK_TYPE_TIMER (1 << 5) #define QUIRK_TYPE_MEM_SIZE (1 << 6) +#define QUIRK_TYPE_TEMP (1 << 7) typedef enum { QUIRK_NONE, QUIRK_TUSL2, QUIRK_ALI_ALADDIN_V, - QUIRK_X10SDV_NOSMP + QUIRK_X10SDV_NOSMP, + QUIRK_K8_BSTEP_NOTEMP, + QUIRK_K8_REVFG_TEMP, + QUIRK_AMD_ERRATA_319 } quirk_id_t; typedef struct { diff --git a/system/jedec_id.h b/system/jedec_id.h index 8e4ec90..83a52f8 100644 --- a/system/jedec_id.h +++ b/system/jedec_id.h @@ -478,7 +478,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0353, "Primarion" }, // { 0x0354, "Picochip Designs Ltd" }, // { 0x0355, "Silverback Systems" }, -// { 0x0356, "Jade Star Technologies" }, + { 0x0356, "Jade Star" }, // { 0x0357, "Pijnenburg Securealink" }, { 0x0358, "takeMS" }, // Ultron AG // { 0x0359, "Cambridge Silicon Radio" }, @@ -882,7 +882,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x066E, "Certicom Corporation" }, // { 0x066F, "JSC ICC Milandr" }, // { 0x0670, "PhotoFast Global Inc" }, -// { 0x0671, "InnoDisk Corporation" }, + { 0x0671, "InnoDisk" }, // { 0x0672, "Muscle Power" }, // { 0x0673, "Energy Micro" }, // { 0x0674, "Innofidei" }, diff --git a/system/msr.h b/system/msr.h index 167cf72..f4b98d8 100644 --- a/system/msr.h +++ b/system/msr.h @@ -30,6 +30,9 @@ #define MSR_AMD64_NB_CFG 0xc001001f #define MSR_AMD64_COFVID_STATUS 0xc0010071 +#define MSR_VIA_TEMP_C7 0x1169 +#define MSR_VIA_TEMP_NANO 0x1423 + #define rdmsr(msr, value1, value2) \ __asm__ __volatile__("rdmsr" \ : "=a" (value1), \ diff --git a/system/smbus.c b/system/smbus.c index 7053c63..a014ea2 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2004-2022 Samuel Demeulemeester +// Copyright (C) 2004-2023 Sam Demeulemeester #include "display.h" @@ -50,9 +50,12 @@ static bool amd_sb_get_smb(void); static bool fch_zen_get_smb(void); static bool piix4_get_smb(uint8_t address); static bool ich5_get_smb(void); +static bool ali_get_smb(uint8_t address); static uint8_t ich5_process(void); static uint8_t ich5_read_spd_byte(uint8_t adr, uint16_t cmd); static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr); +static uint8_t ali_m1563_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr); +static uint8_t ali_m1543_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr); static inline uint8_t bcd_to_ui8(uint8_t bcd) { @@ -1204,7 +1207,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x01B4: // nForce case 0x0064: // nForce 2 // case 0x0084: // nForce 2 Mobile - // case 0x00E4: // nForce 3 + case 0x00E4: // nForce 3 // case 0x0034: // MCP04 // case 0x0052: // nForce 4 case 0x0264: // nForce 410/430 MCP @@ -1251,10 +1254,10 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // SMB base address = 0x90 // viapro SMBus controller, i.e. PIIX4. return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); - // case 0x3074: // 8233_0 - // case 0x3147: // 8233A + case 0x3074: // 8233 + case 0x3147: // 8233A case 0x3177: // 8235 - // case 0x3227: // 8237 + case 0x3227: // 8237 // case 0x3337: // 8237A // case 0x3372: // 8237S // case 0x3287: // 8251 @@ -1282,8 +1285,10 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) case PCI_VID_ALI: switch(did) { - // case 0x1563: // ali1563 (M1563) SMBus controller, nearly compatible with PIIX4 according to Linux i2c-ali1563 driver. - // case 0x7101: // ali1535 (M1535) or ali15x3 (M1533/M1543) SMBus controllers + case 0x7101: // ALi M1533/1535/1543C + return ali_get_smb(PIIX4_SMB_BASE_ADR_ALI1543); + case 0x1563: // ALi M1563 + return piix4_get_smb(PIIX4_SMB_BASE_ADR_ALI1563); default: return false; } @@ -1335,10 +1340,18 @@ static bool ich5_get_smb(void) { uint16_t x; + // Enable SMBus IO Space if disabled + x = pci_config_read16(0, smbdev, smbfun, 0x4); + + if (!(x & 1)) { + pci_config_write16(0, smbdev, smbfun, 0x4, x | 1); + } + + // Read Base Address x = pci_config_read16(0, smbdev, smbfun, 0x20); smbusbase = x & 0xFFF0; - // Enable I2C Bus + // Enable I2C Host Controller Interface if disabled uint8_t temp = pci_config_read8(0, smbdev, smbfun, 0x40); if ((temp & 4) == 0) { pci_config_write8(0, smbdev, smbfun, 0x40, temp | 0x04); @@ -1437,6 +1450,35 @@ static bool nv_mcp_get_smb(void) return false; } +// --------------------------------------- +// ALi SMBUS Controller (M1533/1535/1543C) +// --------------------------------------- + +static bool ali_get_smb(uint8_t address) +{ + // Enable SMB I/O Base Address Register Control (Reg0x5B[2] = 0) + uint16_t temp = pci_config_read8(0, smbdev, smbfun, 0x5B); + pci_config_write8(0, smbdev, smbfun, 0x5B, temp & ~0x06); + + // Enable Response to I/O Access. (Reg0x04[0] = 1) + temp = pci_config_read8(0, smbdev, smbfun, 0x04); + pci_config_write8(0, smbdev, smbfun, 0x04, temp | 0x01); + + // SMB Host Controller Interface Enable (Reg0xE0[0] = 1) + temp = pci_config_read8(0, smbdev, smbfun, 0xE0); + pci_config_write8(0, smbdev, smbfun, 0xE0, temp | 0x01); + + // Read SMBase Register (usually 0xE800) + uint16_t x = pci_config_read16(0, smbdev, smbfun, address) & 0xFFF0; + + if (x != 0) { + smbusbase = x; + return true; + } + + return false; +} + // ------------------ // get_spd() function // ------------------ @@ -1444,6 +1486,11 @@ static bool nv_mcp_get_smb(void) static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) { switch ((smbus_id >> 16) & 0xFFFF) { + case PCI_VID_ALI: + if ((smbus_id & 0xFFFF) == 0x7101) + return ali_m1543_read_spd_byte(slot_idx, (uint8_t)spd_adr); + else + return ali_m1563_read_spd_byte(slot_idx, (uint8_t)spd_adr); case PCI_VID_NVIDIA: return nf_read_spd_byte(slot_idx, (uint8_t)spd_adr); default: @@ -1586,3 +1633,73 @@ static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) return __inb(NVSMBDAT(0)); } + +static uint8_t ali_m1563_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) +{ + int i; + + smbus_adr += 0x50; + + // Reset Status Register + __outb(0xFF, SMBHSTSTS); + + // Set Slave ADR + __outb((smbus_adr << 1 | I2C_READ), SMBHSTADD); + + __outb((__inb(SMBHSTCNT) & ~ALI_SMBHSTCNT_SIZEMASK) | (ALI_SMBHSTCNT_BYTE_DATA << 3), SMBHSTCNT); + + // Set Command (SPD Byte to Read) + __outb(spd_adr, SMBHSTCMD); + + // Start transaction + __outb(__inb(SMBHSTCNT) | SMBHSTCNT_START, SMBHSTCNT); + + // Wait until transaction complete + for (i = 500; i > 0; i--) { + usleep(50); + if (!(__inb(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)) { + break; + } + } + // If timeout or Error Status, exit + if (i == 0 || __inb(SMBHSTSTS) & ALI_SMBHSTSTS_BAD) { + return 0xFF; + } + + return __inb(SMBHSTDAT0); +} + +static uint8_t ali_m1543_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) +{ + int i; + + smbus_adr += 0x50; + + // Reset Status Register + __outb(0xFF, SMBHSTSTS); + + // Set Slave ADR + __outb((smbus_adr << 1 | I2C_READ), ALI_OLD_SMBHSTADD); + + // Set Command (SPD Byte to Read) + __outb(spd_adr, ALI_OLD_SMBHSTCMD); + + // Start transaction + __outb(ALI_OLD_SMBHSTCNT_BYTE_DATA, ALI_OLD_SMBHSTCNT); + __outb(0xFF, ALI_OLD_SMBHSTSTART); + + // Wait until transaction complete + for (i = 500; i > 0; i--) { + usleep(50); + if (!(__inb(SMBHSTSTS) & ALI_OLD_SMBHSTSTS_BUSY)) { + break; + } + } + + // If timeout or Error Status, exit + if (i == 0 || __inb(SMBHSTSTS) & ALI_OLD_SMBHSTSTS_BAD) { + return 0xFF; + } + + return __inb(ALI_OLD_SMBHSTDAT0); +} diff --git a/system/smbus.h b/system/smbus.h index 116ae0c..3925845 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -7,7 +7,7 @@ * * Provides functions for reading SPD via SMBUS * - * Copyright (C) 2004-2022 Samuel Demeulemeester. + * Copyright (C) 2004-2023 Sam Demeulemeester. */ #define I2C_WRITE 0 @@ -74,6 +74,28 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f +/* ALi-Specific constants (M1563 & newer) */ +#define ALI_SMBHSTCNT_SIZEMASK 0x03 +#define ALI_SMBHSTSTS_BAD 0x1C + +#define ALI_SMBHSTCNT_QUICK 0x00 +#define ALI_SMBHSTCNT_BYTE 0x01 +#define ALI_SMBHSTCNT_BYTE_DATA 0x02 +#define ALI_SMBHSTCNT_WORD_DATA 0x03 +#define ALI_SMBHSTCNT_KILL 0x04 +#define ALI_SMBHSTCNT_BLOCK 0x05 + +/* ALi-Specific constants (M1543 & older) */ +#define ALI_OLD_SMBHSTSTS_BAD 0xE0 +#define ALI_OLD_SMBHSTSTS_BUSY 0x08 +#define ALI_OLD_SMBHSTCNT_BYTE_DATA 0x20 + +#define ALI_OLD_SMBHSTCNT smbusbase + 1 +#define ALI_OLD_SMBHSTSTART smbusbase + 2 +#define ALI_OLD_SMBHSTADD smbusbase + 3 +#define ALI_OLD_SMBHSTDAT0 smbusbase + 4 +#define ALI_OLD_SMBHSTCMD smbusbase + 7 + /** Rounding factors for timing computation * * These factors are used as a configurable CEIL() function @@ -87,6 +109,8 @@ #define PIIX4_SMB_BASE_ADR_DEFAULT 0x90 #define PIIX4_SMB_BASE_ADR_VIAPRO 0xD0 +#define PIIX4_SMB_BASE_ADR_ALI1563 0x80 +#define PIIX4_SMB_BASE_ADR_ALI1543 0x14 struct pci_smbus_controller { unsigned vendor; diff --git a/system/temperature.c b/system/temperature.c index 5d29cb5..89382ec 100644 --- a/system/temperature.c +++ b/system/temperature.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2023 Sam Demeulemeester. // // Derived from an extract of memtest86+ init.c: // @@ -16,57 +17,120 @@ #include "cpuid.h" #include "cpuinfo.h" +#include "hwquirks.h" #include "msr.h" #include "pci.h" #include "temperature.h" +//------------------------------------------------------------------------------ +// Public Variables +//------------------------------------------------------------------------------ + +float cpu_temp_offset = 0; + //------------------------------------------------------------------------------ // Public Functions //------------------------------------------------------------------------------ +static int TjMax = 0; + +void get_specific_TjMax(void) +{ + // The TjMax value for some Mobile/Embedded CPUs must be read from a fixed + // table according to their CPUID, PCI Root DID/VID or PNS. + // Trying to read the MSR 0x1A2 on some of them trigger a reboot. + + // Yonah C0 Step (Pentium/Core Duo T2000 & Celeron M 200/400) + if (cpuid_info.version.raw[0] == 0x6E8) { + TjMax = 100; + } +} + +void temperature_init(void) +{ + uint32_t regl, regh; + + // Process temperature-related quirks + if (quirk.type & QUIRK_TYPE_TEMP) { + quirk.process(); + } + + // Get TjMax for Intel CPU + if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6 && (cpuid_info.dts_pmp & 1)) { + + get_specific_TjMax(); + + if (TjMax == 0) { + // Generic Method using MSR 0x1A2 + rdmsr(MSR_IA32_TEMPERATURE_TARGET, regl, regh); + TjMax = (regl >> 16) & 0x7F; + + if (TjMax < 50 || TjMax > 125) { + TjMax = 100; + } + } + } +} + int get_cpu_temperature(void) { + uint32_t regl, regh; // Intel CPU - if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) { - if (cpuid_info.dts_pmp & 1) { - uint32_t msrl, msrh; + if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6 && (cpuid_info.dts_pmp & 1)) { - rdmsr(MSR_IA32_THERM_STATUS, msrl, msrh); - int Tabs = (msrl >> 16) & 0x7F; + rdmsr(MSR_IA32_THERM_STATUS, regl, regh); + int Tabs = (regl >> 16) & 0x7F; - rdmsr(MSR_IA32_TEMPERATURE_TARGET, msrl, msrh); - int Tjunc = (msrl >> 16) & 0x7F; - - if (Tjunc < 50 || Tjunc > 125) { - Tjunc = 90; - } - return Tjunc - Tabs; - } + return TjMax - Tabs; } // AMD CPU - if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily > 0 && cpuid_info.version.extendedFamily < 8) { + else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF) { // Target only K8 & newer - // Untested yet - uint32_t rtcr = pci_config_read32(0, 24, 3, 0xA4); - int raw_temp = (rtcr >> 21) & 0x7FF; + if (cpuid_info.version.extendedFamily >= 8) { // Target Zen µarch and newer. Use SMN to get temperature. - return raw_temp / 8; + regl = amd_smn_read(SMN_THM_TCON_CUR_TMP); - } else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily >= 8) { + if ((regl >> 19) & 0x01) { + cpu_temp_offset = -49.0f; + } - // Grab CPU Temp. for ZEN CPUs using SNM - uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP); + return cpu_temp_offset + 0.125f * (float)((regl >> 21) & 0x7FF); - float offset = 0; + } else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer) - if((tval >> 19) & 0x01) { - offset = -49.0f; + regl = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10); + int raw_temp = ((regl >> 21) & 0x7FF) / 8; + + return (raw_temp > 0) ? raw_temp : 0; + + } else { // Target K8 (CPUID ExtFamily = 0) + + regl = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8); + int raw_temp = ((regl >> 16) & 0xFF) - 49 + cpu_temp_offset; + + return (raw_temp > 0) ? raw_temp : 0; + } + } + + // VIA/Centaur/Zhaoxin CPU + else if (cpuid_info.vendor_id.str[0] == 'C' && cpuid_info.vendor_id.str[1] == 'e' + && (cpuid_info.version.family == 6 || cpuid_info.version.family == 7)) { + + uint32_t msr_temp; + + if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) { + msr_temp = MSR_VIA_TEMP_NANO; // Zhaoxin, Nano + } else if (cpuid_info.version.model == 0xA || cpuid_info.version.model == 0xD) { + msr_temp = MSR_VIA_TEMP_C7; // C7 A/D + } else { + return 0; } - return offset + 0.125f * (float)((tval >> 21) & 0x7FF); + rdmsr(msr_temp, regl, regh); + return (int)(regl & 0xffffff); } return 0; diff --git a/system/temperature.h b/system/temperature.h index 73fdcef..f39c418 100644 --- a/system/temperature.h +++ b/system/temperature.h @@ -8,8 +8,22 @@ * *//* * Copyright (C) 2020-2022 Martin Whitaker. + * Copyright (C) 2003-2023 Sam Demeulemeester. */ +#define AMD_TEMP_REG_K8 0xE4 +#define AMD_TEMP_REG_K10 0xA4 + +/** + * Global CPU Temperature offset + */ +extern float cpu_temp_offset; + +/** + * Init temperature sensor and compute offsets if needed + */ +void temperature_init(void); + /** * Returns the current temperature of the CPU. Returns 0 if * the temperature cannot be read. diff --git a/system/timers.c b/system/timers.c index 54794fa..f78d39a 100644 --- a/system/timers.c +++ b/system/timers.c @@ -18,7 +18,6 @@ #define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz #define APIC_TICKS_50mS 178977 // APIC clock is 3.579545MHz -#define BENCH_MIN_START_ADR 0x1000000 // 16MB //------------------------------------------------------------------------------ // Private Functions @@ -39,6 +38,9 @@ static void correct_tsc(void) counter = inl(acpi_config.pm_addr); + // Generate a dirty delay + for(volatile uint8_t i=0; i<100u; i++); + // Make sure counter is incrementing if (inl(acpi_config.pm_addr) > counter) {