From fa563a8cb24fcbd9ea639aefdd7adc20cf8e1b7e Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 5 Jun 2022 14:36:56 +0200 Subject: [PATCH 001/113] Change the way hwquirks are processed. Add a pointer to the needed function on quirk struct, so it can be executed at any point of the code --- system/hwquirks.c | 3 ++- system/hwquirks.h | 2 ++ system/smbus.c | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/system/hwquirks.c b/system/hwquirks.c index 0aef869..a15c09a 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -54,6 +54,7 @@ void quirks_init(void) quirk.type = QUIRK_TYPE_NONE; quirk.root_vid = pci_config_read16(0, 0, 0, 0); quirk.root_did = pci_config_read16(0, 0, 0, 2); + quirk.process = NULL; // ------------------------ // -- ASUS TUSL2-C Quirk -- @@ -66,7 +67,7 @@ void quirks_init(void) if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C quirk.id = QUIRK_TUSL2; quirk.type |= QUIRK_TYPE_SMBUS; - asus_tusl2_configure_mux(); + quirk.process = asus_tusl2_configure_mux; } } } diff --git a/system/hwquirks.h b/system/hwquirks.h index 0982e83..ba1d78b 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -10,6 +10,7 @@ #include #include +#include #define QUIRK_TYPE_NONE 0b00000000 #define QUIRK_TYPE_USB 0b00000001 @@ -28,6 +29,7 @@ typedef struct { uint8_t type; uint16_t root_vid; uint16_t root_did; + void (*process)(void); } quirk_t; extern quirk_t quirk; diff --git a/system/smbus.c b/system/smbus.c index b3c3eb6..d0a04d6 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -12,6 +12,7 @@ #include "smbus.h" #include "smbios.h" #include "jedec_id.h" +#include "hwquirks.h" #define LINE_SPD 13 #define MAX_SPD_SLOT 8 @@ -153,6 +154,10 @@ void print_smbus_startup_info(void) { ram.freq = 0; curspd.isValid = false; + if (quirk.type == QUIRK_TYPE_SMBUS) { + quirk.process(); + } + index = find_smb_controller(); if (index == -1) { From c9f36fd4f5c6df7480ec2d316e5c86b3ccc463c6 Mon Sep 17 00:00:00 2001 From: Bensuperpc Date: Sun, 5 Jun 2022 14:40:15 +0200 Subject: [PATCH 002/113] Add github action (#90) - Add build with ubuntu 18.04 and 20.04 - Add build with GCC and Clang - Add dependabot - Add stalebot Signed-off-by: Bensuperpc --- .github/dependabot.yml | 9 +++++ .github/workflows/Linux.yml | 63 +++++++++++++++++++++++++++++++++++ .github/workflows/expired.yml | 22 ++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/Linux.yml create mode 100644 .github/workflows/expired.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a9953cb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +# Set update schedule for GitHub Actions + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "daily" diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml new file mode 100644 index 0000000..c8c960d --- /dev/null +++ b/.github/workflows/Linux.yml @@ -0,0 +1,63 @@ +name: Build and tests + +on: + push: + branches: + - "*" + paths-ignore: + - "**/README.md" + pull_request: + branches: + - "*" + workflow_dispatch: + +jobs: + build: + name: ${{ matrix.os }} ${{ matrix.compiler }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04] + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Linux Dependencies + run: sudo apt-get install build-essential gcc-multilib clang libc6-dev-i386-cross dosfstools mtools xorriso -y + + - name: Make all build32 + env: + C: ${{matrix.compiler}} + working-directory: ./build32 + run: make -j 2 all + + - name: Make clean build32 + working-directory: ./build32 + run: make clean + + - name: Make all build64 + env: + C: ${{matrix.compiler}} + working-directory: ./build64 + run: make -j 2 all + + - name: Make clean build64 + working-directory: ./build64 + run: make clean + + - name: Make iso build32 + env: + C: ${{matrix.compiler}} + working-directory: ./build32 + run: make -j 2 iso + + - name: Make iso build64 + env: + C: ${{matrix.compiler}} + working-directory: ./build64 + run: make -j 2 iso diff --git a/.github/workflows/expired.yml b/.github/workflows/expired.yml new file mode 100644 index 0000000..3836da1 --- /dev/null +++ b/.github/workflows/expired.yml @@ -0,0 +1,22 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '0 0 */2 * *' +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v4 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + exempt-issue-milestones: 'future,alpha,beta,release' + exempt-pr-milestones: 'bugfix,improvement' + exempt-all-pr-assignees: true + stale-issue-message: 'This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 30 days.' + stale-pr-message: 'This PR is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 30 days.' + close-issue-message: 'This issue was closed because it has been stalled for 30 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 30 days with no activity.' + days-before-issue-stale: 120 + days-before-pr-stale: 120 + days-before-issue-close: 30 + days-before-pr-close: 30 From 9ed7e220910da960ca1a108f11e85e4e4cc9bff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jun 2022 14:44:47 +0200 Subject: [PATCH 003/113] Bump actions/stale from 4 to 5 (#99) Bumps [actions/stale](https://github.com/actions/stale) from 4 to 5. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/expired.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/expired.yml b/.github/workflows/expired.yml index 3836da1..482bbcc 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@v4 + - uses: actions/stale@v5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-milestones: 'future,alpha,beta,release' From 6cd356f8310714316d6c6979aef5544ebddd89fa Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 6 Jun 2022 19:56:04 +0200 Subject: [PATCH 004/113] Add External L2 detection for ALi Aladdin V Chipset (#87) --- app/main.c | 4 ++-- system/cpuinfo.c | 5 +++++ system/hwquirks.c | 31 +++++++++++++++++++++++++++++++ system/hwquirks.h | 16 +++++++++------- system/smbus.c | 2 +- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/app/main.c b/app/main.c index f906407..1709bac 100644 --- a/app/main.c +++ b/app/main.c @@ -216,12 +216,12 @@ static void global_init(void) pci_init(); + quirks_init(); + membw_init(); smbios_init(); - quirks_init(); - badram_init(); config_init(); diff --git a/system/cpuinfo.c b/system/cpuinfo.c index 93d42e8..0123d4e 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -25,6 +25,7 @@ #include "pmem.h" #include "vmem.h" #include "memsize.h" +#include "hwquirks.h" #include "cpuinfo.h" @@ -1089,6 +1090,10 @@ void cpuinfo_init(void) void membw_init(void) { + if (quirk.type & QUIRK_TYPE_MEM_SIZE) { + quirk.process(); + } + if(enable_bench) { measure_memory_bandwidth(); } diff --git a/system/hwquirks.c b/system/hwquirks.c index a15c09a..b78ecbd 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -12,6 +12,7 @@ #include "io.h" #include "pci.h" #include "unistd.h" +#include "cpuinfo.h" quirk_t quirk; @@ -44,6 +45,25 @@ static void asus_tusl2_configure_mux(void) outb(0xAA, 0x2E); } +static void get_m1541_l2_cache_size(void) +{ + if (l2_cache != 0) { + return; + } + + // Check if L2 cache is enabled with L2CC-2 Register[0] + if ((pci_config_read8(0, 0, 0, 0x42) & 1) == 0) { + return; + } + + // Get L2 Cache Size with L2CC-1 Register[3:2] + uint8_t reg = (pci_config_read8(0, 0, 0, 0x41) >> 2) & 3; + + if (reg == 0b00) { l2_cache = 256; } + if (reg == 0b01) { l2_cache = 512; } + if (reg == 0b10) { l2_cache = 1024; } +} + // --------------------- // -- Public function -- // --------------------- @@ -56,6 +76,17 @@ void quirks_init(void) quirk.root_did = pci_config_read16(0, 0, 0, 2); quirk.process = NULL; + // ------------------------- + // -- ALi Aladdin V Quirk -- + // ------------------------- + // As on many Socket 7 Motherboard, the L2 cache is external and must + // be detected by a proprietary way based on chipset registers + if (quirk.root_vid == 0x10B9 && quirk.root_did == 0x1541) { // ALi Aladdin V (M1541) + quirk.id = QUIRK_ALI_ALADDIN_V; + quirk.type |= QUIRK_TYPE_MEM_SIZE; + quirk.process = get_m1541_l2_cache_size; + } + // ------------------------ // -- ASUS TUSL2-C Quirk -- // ------------------------ diff --git a/system/hwquirks.h b/system/hwquirks.h index ba1d78b..cca30c1 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -12,16 +12,18 @@ #include #include -#define QUIRK_TYPE_NONE 0b00000000 -#define QUIRK_TYPE_USB 0b00000001 -#define QUIRK_TYPE_SMP 0b00000010 -#define QUIRK_TYPE_SMBIOS 0b00000100 -#define QUIRK_TYPE_SMBUS 0b00001000 -#define QUIRK_TYPE_TIMER 0b00010000 +#define QUIRK_TYPE_NONE (1 << 0) +#define QUIRK_TYPE_USB (1 << 1) +#define QUIRK_TYPE_SMP (1 << 2) +#define QUIRK_TYPE_SMBIOS (1 << 3) +#define QUIRK_TYPE_SMBUS (1 << 4) +#define QUIRK_TYPE_TIMER (1 << 5) +#define QUIRK_TYPE_MEM_SIZE (1 << 6) typedef enum { QUIRK_NONE, - QUIRK_TUSL2 + QUIRK_TUSL2, + QUIRK_ALI_ALADDIN_V } quirk_id_t; typedef struct { diff --git a/system/smbus.c b/system/smbus.c index d0a04d6..50b1463 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -154,7 +154,7 @@ void print_smbus_startup_info(void) { ram.freq = 0; curspd.isValid = false; - if (quirk.type == QUIRK_TYPE_SMBUS) { + if (quirk.type & QUIRK_TYPE_SMBUS) { quirk.process(); } From e86b04a14a884910f3271d83ffe9d8c1f256c6da Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Mon, 6 Jun 2022 10:24:45 +0200 Subject: [PATCH 005/113] Perform major simplification in smbus.c to reduce code size while keeping the functions readable, removing several unused strings and unnecessary arguments passed to several functions. Add a bunch of PCI device IDs and driver indications for other SMBus controllers, so as to avoid other persons having to do that work again. Add support for two PIIX4 devices: the standard PIIX4 PCI device ID, and the ServerWorks CSB5, which has a slight twist. Co-authored-by: Lionel Debroux Co-authored-by: Sam Demeulemeester --- system/smbus.c | 431 +++++++++++++++++++++++++++++++++---------------- system/smbus.h | 12 +- 2 files changed, 305 insertions(+), 138 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 50b1463..6ca4f7d 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -22,6 +22,7 @@ ram_info ram = { 0, 0, 0, 0, 0, "N/A"}; int smbdev, smbfun; unsigned short smbusbase = 0; uint32_t smbus_id; +static uint16_t extra_initial_sleep_for_smb_transaction = 0; static int8_t spd_page = -1; static int8_t last_adr = -1; @@ -37,117 +38,22 @@ static spd_info parse_spd_ddr4 (uint8_t slot_idx); static spd_info parse_spd_ddr5 (uint8_t slot_idx); static void print_spdi(spd_info spdi, uint8_t lidx); -static int find_smb_controller(void); +static bool setup_smb_controller(void); +static bool find_smb_controller(uint16_t vid, uint16_t did); + static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr); -static void nv_mcp_get_smb(void); -static void amd_sb_get_smb(void); -static void fch_zen_get_smb(void); -static void piix4_get_smb(void); -static void ich5_get_smb(void); +static bool nv_mcp_get_smb(void); +static bool amd_sb_get_smb(void); +static bool fch_zen_get_smb(void); +static bool piix4_get_smb(void); +static bool ich5_get_smb(void); 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); -// ---------------------------------------------------------- -// WARNING: Be careful when adding a controller ID! -// Incorrect SMB accesses (ie: on bank switch) can brick your -// motherboard or your memory module. -// ---- -// No Pull Request including a new SMBUS Controller will be -// accepted without a proof (screenshot) that it has been -// tested successfully on a real motherboard. -// ---------------------------------------------------------- - -static const struct pci_smbus_controller smbcontrollers[] = { - {0x8086, 0x2413, ich5_get_smb}, // 82801AA (ICH) - {0x8086, 0x2423, ich5_get_smb}, // 82801AB (ICH) - {0x8086, 0x2443, ich5_get_smb}, // 82801BA (ICH2) - {0x8086, 0x2483, ich5_get_smb}, // 82801CA (ICH3) - {0x8086, 0x24C3, ich5_get_smb}, // 82801DB (ICH4) - {0x8086, 0x24D3, ich5_get_smb}, // 82801E (ICH5) - {0x8086, 0x25A4, ich5_get_smb}, // 6300ESB - {0x8086, 0x266A, ich5_get_smb}, // 82801F (ICH6) - {0x8086, 0x269B, ich5_get_smb}, // 6310ESB/6320ESB - {0x8086, 0x27DA, ich5_get_smb}, // 82801G (ICH7) - {0x8086, 0x283E, ich5_get_smb}, // 82801H (ICH8) - {0x8086, 0x2930, ich5_get_smb}, // 82801I (ICH9) - {0x8086, 0x5032, ich5_get_smb}, // EP80579 (Tolapai) - {0x8086, 0x3A30, ich5_get_smb}, // ICH10 - {0x8086, 0x3A60, ich5_get_smb}, // ICH10 - {0x8086, 0x3B30, ich5_get_smb}, // 5/3400 Series (PCH) - {0x8086, 0x1C22, ich5_get_smb}, // 6 Series (PCH) - {0x8086, 0x1D22, ich5_get_smb}, // Patsburg (PCH) - {0x8086, 0x1D70, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x1D71, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x1D72, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x2330, ich5_get_smb}, // DH89xxCC (PCH) - {0x8086, 0x1E22, ich5_get_smb}, // Panther Point (PCH) - {0x8086, 0x8C22, ich5_get_smb}, // Lynx Point (PCH) - {0x8086, 0x9C22, ich5_get_smb}, // Lynx Point-LP (PCH) - {0x8086, 0x1F3C, ich5_get_smb}, // Avoton (SOC) - {0x8086, 0x8D22, ich5_get_smb}, // Wellsburg (PCH) - {0x8086, 0x8D7D, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x8D7E, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x8D7F, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x23B0, ich5_get_smb}, // Coleto Creek (PCH) - {0x8086, 0x8CA2, ich5_get_smb}, // Wildcat Point (PCH) - {0x8086, 0x9CA2, ich5_get_smb}, // Wildcat Point-LP (PCH) - {0x8086, 0x0F12, ich5_get_smb}, // BayTrail (SOC) - {0x8086, 0x2292, ich5_get_smb}, // Braswell (SOC) - {0x8086, 0xA123, ich5_get_smb}, // Sunrise Point-H (PCH) - {0x8086, 0x9D23, ich5_get_smb}, // Sunrise Point-LP (PCH) - {0x8086, 0x19DF, ich5_get_smb}, // Denverton (SOC) - {0x8086, 0x1BC9, ich5_get_smb}, // Emmitsburg (PCH) - {0x8086, 0xA1A3, ich5_get_smb}, // Lewisburg (PCH) - {0x8086, 0xA223, ich5_get_smb}, // Lewisburg Super (PCH) - {0x8086, 0xA2A3, ich5_get_smb}, // Kaby Lake (PCH-H) - {0x8086, 0x31D4, ich5_get_smb}, // Gemini Lake (SOC) - {0x8086, 0xA323, ich5_get_smb}, // Cannon Lake-H (PCH) - {0x8086, 0x9DA3, ich5_get_smb}, // Cannon Lake-LP (PCH) - {0x8086, 0x18DF, ich5_get_smb}, // Cedar Fork (PCH) - {0x8086, 0x34A3, ich5_get_smb}, // Ice Lake-LP (PCH) - {0x8086, 0x38A3, ich5_get_smb}, // Ice Lake-N (PCH) - {0x8086, 0x02A3, ich5_get_smb}, // Comet Lake (PCH) - {0x8086, 0x06A3, ich5_get_smb}, // Comet Lake-H (PCH) - {0x8086, 0x4B23, ich5_get_smb}, // Elkhart Lake (PCH) - {0x8086, 0xA0A3, ich5_get_smb}, // Tiger Lake-LP (PCH) - {0x8086, 0x43A3, ich5_get_smb}, // Tiger Lake-H (PCH) - {0x8086, 0x4DA3, ich5_get_smb}, // Jasper Lake (SOC) - {0x8086, 0xA3A3, ich5_get_smb}, // Comet Lake-V (PCH) - {0x8086, 0x7AA3, ich5_get_smb}, // Alder Lake-S (PCH) - {0x8086, 0x51A3, ich5_get_smb}, // Alder Lake-P (PCH) - {0x8086, 0x54A3, ich5_get_smb}, // Alder Lake-M (PCH) - {0x8086, 0x7A23, ich5_get_smb}, // Raptor Lake-S (PCH) - - // ATI SMBUS - {0x1002, 0x4385, amd_sb_get_smb}, // ATI SB600+ (Now AMD) - - // AMD SMBUS - {0x1022, 0x780B, amd_sb_get_smb}, // AMD FCH (Pre-Zen) - {0x1022, 0x790B, fch_zen_get_smb}, // AMD FCH (Zen) - - // nVidia SMBUS - // {0x10DE, 0x01B4, nv_mcp_get_smb}, // nForce - {0x10DE, 0x0064, nv_mcp_get_smb}, // nForce 2 - // {0x10DE, 0x0084, nv_mcp_get_smb}, // nForce 2 Mobile - // {0x10DE, 0x00E4, nv_mcp_get_smb}, // nForce 3 - // {0x10DE, 0x0052, nv_mcp_get_smb}, // nForce 4 - // {0x10DE, 0x0264, nv_mcp_get_smb}, // nForce 410/430 MCP - // {0x10DE, 0x0446, nv_mcp_get_smb}, // nForce 520 - // {0x10DE, 0x0542, nv_mcp_get_smb}, // nForce 560 - // {0x10DE, 0x07D8, nv_mcp_get_smb}, // nForce 630i - {0x10DE, 0x03EB, nv_mcp_get_smb}, // nForce 630a - {0x10DE, 0x0752, nv_mcp_get_smb}, // nForce 720a - // {0x10DE, 0x0AA2, nv_mcp_get_smb}, // nForce 730i - // {0x10DE, 0x0368, nv_mcp_get_smb}, // nForce 790i Ultra - - {0, 0, NULL} -}; - -void print_smbus_startup_info(void) { - - int8_t index; +void print_smbus_startup_info(void) +{ uint8_t spdidx = 0, spd_line_idx = 0; spd_info curspd; @@ -158,15 +64,7 @@ void print_smbus_startup_info(void) { quirk.process(); } - index = find_smb_controller(); - - if (index == -1) { - return; - } - - smbcontrollers[index].get_adr(); - - if (smbusbase == 0) { + if (!setup_smb_controller() || smbusbase == 0) { return; } @@ -1236,52 +1134,295 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) return spdi; } + // -------------------------- // SMBUS Controller Functions // -------------------------- -static int find_smb_controller(void) +static bool setup_smb_controller(void) { - int i = 0; - unsigned long valuev, valued; + uint16_t vid, did; for (smbdev = 0; smbdev < 32; smbdev++) { for (smbfun = 0; smbfun < 8; smbfun++) { - valuev = pci_config_read16(0, smbdev, smbfun, 0); - if (valuev != 0xFFFF) { - for (i = 0; smbcontrollers[i].vendor > 0; i++) { - if (valuev == smbcontrollers[i].vendor) { - valued = pci_config_read16(0, smbdev, smbfun, 2); - if (valued == smbcontrollers[i].device) { - smbus_id = (valuev << 16) | valued; - return i; - } + vid = pci_config_read16(0, smbdev, smbfun, 0); + if (vid != 0xFFFF) { + did = pci_config_read16(0, smbdev, smbfun, 2); + if (did != 0xFFFF) { + if (find_smb_controller(vid, did)) { + return true; } } } } } - return -1; + return false; +} + +// ---------------------------------------------------------- +// WARNING: Be careful when adding a controller ID! +// Incorrect SMB accesses (ie: on bank switch) can brick your +// motherboard or your memory module. +// ---- +// No Pull Request including a new SMBUS Controller will be +// accepted without a proof (screenshot) that it has been +// tested successfully on a real motherboard. +// ---------------------------------------------------------- + +// PCI device IDs for Intel i801 SMBus controller. +static const uint16_t intel_ich5_dids[] = +{ + 0x2413, // 82801AA (ICH) + 0x2423, // 82801AB (ICH) + 0x2443, // 82801BA (ICH2) + 0x2483, // 82801CA (ICH3) + 0x24C3, // 82801DB (ICH4) + 0x24D3, // 82801E (ICH5) + 0x25A4, // 6300ESB + 0x266A, // 82801F (ICH6) + 0x269B, // 6310ESB/6320ESB + 0x27DA, // 82801G (ICH7) + 0x283E, // 82801H (ICH8) + 0x2930, // 82801I (ICH9) + 0x5032, // EP80579 (Tolapai) + 0x3A30, // ICH10 + 0x3A60, // ICH10 + 0x3B30, // 5/3400 Series (PCH) + 0x1C22, // 6 Series (PCH) + 0x1D22, // Patsburg (PCH) + 0x1D70, // Patsburg (PCH) IDF + 0x1D71, // Patsburg (PCH) IDF + 0x1D72, // Patsburg (PCH) IDF + 0x2330, // DH89xxCC (PCH) + 0x1E22, // Panther Point (PCH) + 0x8C22, // Lynx Point (PCH) + 0x9C22, // Lynx Point-LP (PCH) + 0x1F3C, // Avoton (SOC) + 0x8D22, // Wellsburg (PCH) + 0x8D7D, // Wellsburg (PCH) MS + 0x8D7E, // Wellsburg (PCH) MS + 0x8D7F, // Wellsburg (PCH) MS + 0x23B0, // Coleto Creek (PCH) + 0x8CA2, // Wildcat Point (PCH) + 0x9CA2, // Wildcat Point-LP (PCH) + 0x0F12, // BayTrail (SOC) + 0x2292, // Braswell (SOC) + 0xA123, // Sunrise Point-H (PCH) + 0x9D23, // Sunrise Point-LP (PCH) + 0x19DF, // Denverton (SOC) + 0x1BC9, // Emmitsburg (PCH) + 0xA1A3, // Lewisburg (PCH) + 0xA223, // Lewisburg Super (PCH) + 0xA2A3, // Kaby Lake (PCH-H) + 0x31D4, // Gemini Lake (SOC) + 0xA323, // Cannon Lake-H (PCH) + 0x9DA3, // Cannon Lake-LP (PCH) + 0x18DF, // Cedar Fork (PCH) + 0x34A3, // Ice Lake-LP (PCH) + 0x38A3, // Ice Lake-N (PCH) + 0x02A3, // Comet Lake (PCH) + 0x06A3, // Comet Lake-H (PCH) + 0x4B23, // Elkhart Lake (PCH) + 0xA0A3, // Tiger Lake-LP (PCH) + 0x43A3, // Tiger Lake-H (PCH) + 0x4DA3, // Jasper Lake (SOC) + 0xA3A3, // Comet Lake-V (PCH) + 0x7AA3, // Alder Lake-S (PCH) + 0x51A3, // Alder Lake-P (PCH) + 0x54A3, // Alder Lake-M (PCH) + 0x7A23, // Raptor Lake-S (PCH) +}; + +static bool find_in_did_array(uint16_t did, const uint16_t * ids, unsigned int size) +{ + for (unsigned int i = 0; i < size; i++) { + if (*ids++ == did) { + return true; + } + } + return false; +} + +static bool find_smb_controller(uint16_t vid, uint16_t did) +{ + switch(vid) + { + case VID_INTEL: + { + if (find_in_did_array(did, intel_ich5_dids, sizeof(intel_ich5_dids) / sizeof(intel_ich5_dids[0]))) { + return ich5_get_smb(); + } + if ( did == 0x7113 // 82371AB/EB/MB PIIX4 +// || did == 0x719B // 82440/82443MX PMC + ) { + return piix4_get_smb(); + } + // 0x0C59-0x0C5E, 0x18AC, 0x19AC, 0x1BFF, 0x1F15, 0x1F3D Atom S1200 / C2000 / C3000 SMBus controllers may not be SPD-related. + // 0x0F13 ValleyView SMBus Controller ? + // 0x7603 82372FB PIIX5 ? + // 0x8119 US15W ? + return false; + } + + case VID_AMD: + switch(did) + { +#if 0 + case 0x740B: // AMD756 + case 0x7413: // AMD766 + case 0x7443: // AMD768 + case 0x746B: // AMD8111_SMBUS + // amd756 / nforce SMB controller + case 0x746A: // AMD8111_SMBUS2 + // amd8111 SMB controller +#endif + case 0x780B: // AMD FCH (Pre-Zen) + return amd_sb_get_smb(); + case 0x790B: // AMD FCH (Zen 2/3) + return fch_zen_get_smb(); + default: + return false; + } + break; + + case VID_HYGON: + switch(did) + { + case 0x780B: // AMD FCH (Pre-Zen) + return amd_sb_get_smb(); + case 0x790B: // AMD FCH (Zen 2/3) + return fch_zen_get_smb(); + default: + return false; + } + break; + + case VID_ATI: + switch(did) + { + // case 0x4353: // SB200 + // case 0x4363: // SB300 + // case 0x4372: // IXP SB4x0 + case 0x4385: // SB600+ + return amd_sb_get_smb(); + default: + return false; + } + break; + + case VID_NVIDIA: + switch(did) + { +#if 0 + case 0x01B4: // nForce + // amd756 / nforce SMB controller +#endif + // case 0x0034: // MCP04 + // case 0x0052: // CK804 + case 0x0064: // nForce2 (MCP) + // case 0x0084: // MCP2A + // case 0x00D4: // nForce3 + // case 0x0264: // MCP51 + // case 0x0368: // MCP55 + case 0x03EB: // MCP61 + // case 0x0446: // MCP65 + // case 0x0542: // MCP67 + case 0x0752: // MCP78S + // case 0x07D8: // MCP73 + // case 0x0AA2: // MCP79 + // case 0x0D79: // MCP89 + return nv_mcp_get_smb(); + default: + return false; + } + break; +#if 0 + case VID_SIS: + switch(did) + { + case 0x0016: // SiS961/2/3 + // sis96x SMBus controller. + // There are also sis630 and sis5595 SMBus controllers. + default: + return false; + } + break; +#endif +#if 0 + case VID_VIA: + switch(did) + { + case 0x3040: // 82C586_3 + // via SMBus controller. + case 0x3050: // 82C596_3 + // Try SMB base address = 0x90, then SMB base address = 0x80 + // viapro SMBus controller. + case 0x3051: // 82C596B_3 + case 0x3057: // 82C686_4 + case 0x8235: // 8231_4 + // SMB base address = 0x90 + // viapro SMBus controller. + case 0x3074: // 8233_0 + case 0x3147: // 8233A + case 0x3177: // 8235 + case 0x3227: // 8237 + case 0x3337: // 8237A + case 0x3372: // 8237S + case 0x3287: // 8251 + case 0x8324: // CX700 + case 0x8353: // VX800 + case 0x8409: // VX855 + case 0x8410: // VX900 + // SMB base address = 0xD0 + // viapro I2C controller. + default: + return false; + } + break; +#endif + case VID_SERVERWORKS: + switch(did) + { + case 0x0201: // CSB5 + // From Linux i2c-piix4 driver: unlike its siblings, this model needs a quirk. + extra_initial_sleep_for_smb_transaction = 2100 - 500; + // Fall through. + // case 0x0200: // OSB4 + // case 0x0203: // CSB6 + // case 0x0205: // HT1000SB + // case 0x0408: // HT1100LD + return piix4_get_smb(); + default: + return false; + } + break; + default: + return false; + } + return false; } // ---------------------- // PIIX4 SMBUS Controller // ---------------------- -static void piix4_get_smb(void) +static bool piix4_get_smb(void) { uint16_t x = pci_config_read16(0, smbdev, smbfun, 0x90) & 0xFFF0; if (x != 0) { smbusbase = x; + return true; } + + return false; } // ---------------------------- // i801 / ICH5 SMBUS Controller // ---------------------------- -static void ich5_get_smb(void) +static bool ich5_get_smb(void) { uint16_t x; @@ -1297,13 +1438,15 @@ static void ich5_get_smb(void) // Reset SMBUS Controller __outb(__inb(SMBHSTSTS) & 0x1F, SMBHSTSTS); usleep(1000); + + return (smbusbase != 0); } // -------------------- // AMD SMBUS Controller // -------------------- -static void amd_sb_get_smb(void) +static bool amd_sb_get_smb(void) { uint8_t rev_id; uint16_t pm_reg; @@ -1312,10 +1455,10 @@ static void amd_sb_get_smb(void) if ((smbus_id & 0xFFFF) == 0x4385 && rev_id <= 0x3D) { // Older AMD SouthBridge (SB700 & older) use PIIX4 registers - piix4_get_smb(); + return piix4_get_smb(); } else if ((smbus_id & 0xFFFF) == 0x780B && rev_id == 0x42) { // Latest Pre-Zen APUs use the newer Zen PM registers - fch_zen_get_smb(); + return fch_zen_get_smb(); } else { // AMD SB (SB800 up to pre-FT3/FP4/AM4) uses specific registers __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT); @@ -1325,11 +1468,14 @@ static void amd_sb_get_smb(void) if (pm_reg != 0xFFE0 && pm_reg != 0) { smbusbase = pm_reg; + return true; } } + + return false; } -static void fch_zen_get_smb(void) +static bool fch_zen_get_smb(void) { uint16_t pm_reg; @@ -1341,24 +1487,27 @@ static void fch_zen_get_smb(void) // Special case for AMD Cezanne (get smb address in memory) if (imc_type == IMC_K19_CZN && pm_reg == 0xFFFF) { smbusbase = ((*(const uint32_t *)(0xFED80000 + 0x300) >> 8) & 0xFF) << 8; - return; + return true; } // Check if IO Smbus is enabled. if ((pm_reg & 0x10) == 0) { - return; + return false; } if ((pm_reg & 0xFF00) != 0) { smbusbase = pm_reg & 0xFF00; + return true; } + + return false; } // ----------------------- // nVidia SMBUS Controller // ----------------------- -static void nv_mcp_get_smb(void) +static bool nv_mcp_get_smb(void) { int smbus_base_adr; @@ -1373,7 +1522,10 @@ static void nv_mcp_get_smb(void) if (x != 0) { smbusbase = x; + return true; } + + return false; } // ------------------ @@ -1383,7 +1535,7 @@ static void nv_mcp_get_smb(void) static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) { switch ((smbus_id >> 16) & 0xFFFF) { - case 0x10DE: + case VID_NVIDIA: return nf_read_spd_byte(slot_idx, (uint8_t)spd_adr); default: return ich5_read_spd_byte(slot_idx, spd_adr); @@ -1470,6 +1622,11 @@ static uint8_t ich5_process(void) __outb(__inb(SMBHSTCNT) | SMBHSTCNT_START, SMBHSTCNT); + // Some SMB controllers need this quirk. + if (extra_initial_sleep_for_smb_transaction) { + usleep(extra_initial_sleep_for_smb_transaction); + } + do { usleep(500); status = __inb(SMBHSTSTS); diff --git a/system/smbus.h b/system/smbus.h index f950cbc..669e8a5 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -10,6 +10,16 @@ * Copyright (C) 2004-2022 Samuel Demeulemeester. */ +/* Vendor IDs */ +#define VID_ATI 0x1002 +#define VID_AMD 0x1022 +#define VID_SIS 0x1039 +#define VID_NVIDIA 0x10DE +#define VID_VIA 0x1106 +#define VID_SERVERWORKS 0x1166 +#define VID_HYGON 0x1D94 +#define VID_INTEL 0x8086 + #define I2C_WRITE 0 #define I2C_READ 1 @@ -74,7 +84,7 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f -struct pci_smbus_controller{ +struct pci_smbus_controller { unsigned vendor; unsigned device; void (*get_adr)(void); From 106eabef9868fd29a39407daa43c19246956e72d Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 6 Jun 2022 17:21:16 +0200 Subject: [PATCH 006/113] Fuse HYGON and AMD because the SMB controllor is strictly identical on both --- system/smbus.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 6ca4f7d..a67a919 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1264,6 +1264,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) return false; } + case VID_HYGON: case VID_AMD: switch(did) { @@ -1285,18 +1286,6 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) } break; - case VID_HYGON: - switch(did) - { - case 0x780B: // AMD FCH (Pre-Zen) - return amd_sb_get_smb(); - case 0x790B: // AMD FCH (Zen 2/3) - return fch_zen_get_smb(); - default: - return false; - } - break; - case VID_ATI: switch(did) { From 7758adfb9dc3ba83e2ee4527268668672de120a5 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 6 Jun 2022 17:42:08 +0200 Subject: [PATCH 007/113] Improve readability on disabled code --- system/smbus.c | 96 ++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index a67a919..5ca22a8 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1252,14 +1252,11 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) if (find_in_did_array(did, intel_ich5_dids, sizeof(intel_ich5_dids) / sizeof(intel_ich5_dids[0]))) { return ich5_get_smb(); } - if ( did == 0x7113 // 82371AB/EB/MB PIIX4 -// || did == 0x719B // 82440/82443MX PMC - ) { + if (did == 0x7113) { // 82371AB/EB/MB PIIX4 return piix4_get_smb(); } - // 0x0C59-0x0C5E, 0x18AC, 0x19AC, 0x1BFF, 0x1F15, 0x1F3D Atom S1200 / C2000 / C3000 SMBus controllers may not be SPD-related. + // 0x719B 82440/82443MX PMC ? // 0x0F13 ValleyView SMBus Controller ? - // 0x7603 82372FB PIIX5 ? // 0x8119 US15W ? return false; } @@ -1268,15 +1265,11 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) case VID_AMD: switch(did) { -#if 0 - case 0x740B: // AMD756 - case 0x7413: // AMD766 - case 0x7443: // AMD768 - case 0x746B: // AMD8111_SMBUS - // amd756 / nforce SMB controller - case 0x746A: // AMD8111_SMBUS2 - // amd8111 SMB controller -#endif + // case 0x740B: // AMD756 + // case 0x7413: // AMD766 + // case 0x7443: // AMD768 + // case 0x746B: // AMD8111_SMBUS + // case 0x746A: // AMD8111_SMBUS2 case 0x780B: // AMD FCH (Pre-Zen) return amd_sb_get_smb(); case 0x790B: // AMD FCH (Zen 2/3) @@ -1291,8 +1284,8 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) { // case 0x4353: // SB200 // case 0x4363: // SB300 - // case 0x4372: // IXP SB4x0 - case 0x4385: // SB600+ + // case 0x4372: // SB400 + case 0x4385: // SB600+ return amd_sb_get_smb(); default: return false; @@ -1302,73 +1295,68 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) case VID_NVIDIA: switch(did) { -#if 0 - case 0x01B4: // nForce - // amd756 / nforce SMB controller -#endif + // case 0x01B4: // nForce + case 0x0064: // nForce 2 + // case 0x0084: // nForce 2 Mobile + // case 0x00E4: // nForce 3 // case 0x0034: // MCP04 - // case 0x0052: // CK804 - case 0x0064: // nForce2 (MCP) - // case 0x0084: // MCP2A - // case 0x00D4: // nForce3 - // case 0x0264: // MCP51 - // case 0x0368: // MCP55 - case 0x03EB: // MCP61 - // case 0x0446: // MCP65 - // case 0x0542: // MCP67 - case 0x0752: // MCP78S - // case 0x07D8: // MCP73 - // case 0x0AA2: // MCP79 + // case 0x0052: // nForce 4 + // case 0x0264: // nForce 410/430 MCP + case 0x03EB: // nForce 630a + // case 0x0446: // nForce 520 + // case 0x0542: // nForce 560 + case 0x0752: // nForce 720a + // case 0x07D8: // nForce 630i + // case 0x0AA2: // nForce 730i // case 0x0D79: // MCP89 + // case 0x0368: // nForce 790i Ultra return nv_mcp_get_smb(); default: return false; } break; -#if 0 + case VID_SIS: switch(did) { case 0x0016: // SiS961/2/3 - // sis96x SMBus controller. - // There are also sis630 and sis5595 SMBus controllers. + // There are also SiS630 and SiS5595 SMBus controllers. default: return false; } break; -#endif -#if 0 + case VID_VIA: switch(did) { - case 0x3040: // 82C586_3 + // case 0x3040: // 82C586_3 // via SMBus controller. - case 0x3050: // 82C596_3 + // case 0x3050: // 82C596_3 // Try SMB base address = 0x90, then SMB base address = 0x80 // viapro SMBus controller. - case 0x3051: // 82C596B_3 - case 0x3057: // 82C686_4 - case 0x8235: // 8231_4 + // case 0x3051: // 82C596B_3 + // case 0x3057: // 82C686_4 + // case 0x8235: // 8231_4 // SMB base address = 0x90 // viapro SMBus controller. - case 0x3074: // 8233_0 - case 0x3147: // 8233A - case 0x3177: // 8235 - case 0x3227: // 8237 - case 0x3337: // 8237A - case 0x3372: // 8237S - case 0x3287: // 8251 - case 0x8324: // CX700 - case 0x8353: // VX800 - case 0x8409: // VX855 - case 0x8410: // VX900 + // case 0x3074: // 8233_0 + // case 0x3147: // 8233A + // case 0x3177: // 8235 + // case 0x3227: // 8237 + // case 0x3337: // 8237A + // case 0x3372: // 8237S + // case 0x3287: // 8251 + // case 0x8324: // CX700 + // case 0x8353: // VX800 + // case 0x8409: // VX855 + // case 0x8410: // VX900 // SMB base address = 0xD0 // viapro I2C controller. default: return false; } break; -#endif + case VID_SERVERWORKS: switch(did) { From 63a07258fd7488c1cdc48bf84d52361a65246e0f Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Wed, 8 Jun 2022 18:00:50 +0200 Subject: [PATCH 008/113] Fix the operation of the SMBus functions which require the SMBus controller ID. --- system/smbus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index 5ca22a8..4efebe8 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -21,7 +21,7 @@ ram_info ram = { 0, 0, 0, 0, 0, "N/A"}; int smbdev, smbfun; unsigned short smbusbase = 0; -uint32_t smbus_id; +uint32_t smbus_id = 0; static uint16_t extra_initial_sleep_for_smb_transaction = 0; static int8_t spd_page = -1; @@ -1156,6 +1156,7 @@ static bool setup_smb_controller(void) } } } + smbus_id = 0; return false; } @@ -1245,6 +1246,7 @@ static bool find_in_did_array(uint16_t did, const uint16_t * ids, unsigned int s static bool find_smb_controller(uint16_t vid, uint16_t did) { + smbus_id = (((uint32_t)vid) << 16) | did; switch(vid) { case VID_INTEL: From 221a66da1adb0eb8d07d538d2074e2d76de529b0 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Thu, 9 Jun 2022 01:14:01 +0200 Subject: [PATCH 009/113] Split ACPI Functions from SMP functions. Add ACPI Table detection for FADT & HPET (as we need better timers) --- app/main.c | 5 + build32/Makefile | 3 +- build64/Makefile | 3 +- system/acpi.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++ system/acpi.h | 52 +++++++++ system/smp.c | 234 ++------------------------------------- system/smp.h | 9 -- 7 files changed, 355 insertions(+), 233 deletions(-) create mode 100644 system/acpi.c create mode 100644 system/acpi.h diff --git a/app/main.c b/app/main.c index 1709bac..d589761 100644 --- a/app/main.c +++ b/app/main.c @@ -18,6 +18,7 @@ #include "boot.h" #include "bootparams.h" +#include "acpi.h" #include "cache.h" #include "cpuid.h" #include "cpuinfo.h" @@ -218,6 +219,8 @@ static void global_init(void) quirks_init(); + acpi_init(); + membw_init(); smbios_init(); @@ -280,6 +283,8 @@ static void global_init(void) } if (rsdp_addr != 0) { trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr); + trace(0, "ACPI FADT found at %0*x", 2*sizeof(uintptr_t), fadt_addr); + trace(0, "ACPI HPET found at %0*x", 2*sizeof(uintptr_t), hpet_addr); } if (!load_addr_ok) { trace(0, "Cannot relocate program. Press any key to reboot..."); diff --git a/build32/Makefile b/build32/Makefile index 97f02b4..7fcc728 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -14,7 +14,8 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m32 -march=i586 -fpic -fno-builtin \ INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp -SYS_OBJS = system/cpuid.o \ +SYS_OBJS = system/acpi.o \ + system/cpuid.o \ system/cpuinfo.o \ system/cpulocal.o \ system/ehci.o \ diff --git a/build64/Makefile b/build64/Makefile index 5e806fd..4dcb791 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -14,7 +14,8 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m64 -march=x86-64 -mno-mmx -mno-sse -m INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp -SYS_OBJS = system/cpuid.o \ +SYS_OBJS = system/acpi.o \ + system/cpuid.o \ system/cpuinfo.o \ system/cpulocal.o \ system/ehci.o \ diff --git a/system/acpi.c b/system/acpi.c new file mode 100644 index 0000000..e1efe21 --- /dev/null +++ b/system/acpi.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. + +#include "boot.h" +#include "bootparams.h" +#include "efi.h" + +#include "pmem.h" +#include "string.h" +#include "unistd.h" +#include "vmem.h" + +#include "acpi.h" + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +// Table signatures + +#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24)) +#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24)) + +#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) + +#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) + +#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) + +#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24)) + +#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24)) + +#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +typedef struct { + char signature[8]; // "RSD PTR " + uint8_t checksum; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_addr; + uint32_t length; + uint64_t xsdt_addr; + uint8_t xchecksum; + uint8_t reserved[3]; +} rsdp_t; + +typedef struct { + char signature[4]; // "RSDT" or "XSDT" + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table_id[8]; + char oem_revision[4]; + char creator_id[4]; + char creator_revision[4]; +} rsdt_header_t; + +//------------------------------------------------------------------------------ +// Private Variables +//------------------------------------------------------------------------------ + +static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }; +static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} }; + +//------------------------------------------------------------------------------ +// Variables +//------------------------------------------------------------------------------ + +const char *rsdp_source = ""; + +uintptr_t rsdp_addr = 0; +uintptr_t madt_addr = 0; +uintptr_t fadt_addr = 0; +uintptr_t hpet_addr = 0; + +//------------------------------------------------------------------------------ +// Private Functions +//------------------------------------------------------------------------------ + +static rsdp_t *scan_for_rsdp(uintptr_t addr, int length) +{ + uint32_t *ptr = (uint32_t *)addr; + uint32_t *end = ptr + length / sizeof(uint32_t); + + while (ptr < end) { + rsdp_t *rp = (rsdp_t *)ptr; + if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && acpi_checksum(ptr, 20) == 0) { + if (rp->revision < 2 || (rp->length < 1024 && acpi_checksum(ptr, rp->length) == 0)) { + return rp; + } + } + ptr += 4; + } + return NULL; +} + +#ifdef __x86_64__ +static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table) +{ + efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables, + system_table->num_config_tables * sizeof(efi64_config_table_t), + true); + if (config_tables == NULL) return NULL; + + uintptr_t table_addr = 0; + for (uint32_t i = 0; i < system_table->num_config_tables; i++) { + if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) { + table_addr = config_tables[i].table; + break; + } + if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) { + table_addr = config_tables[i].table; + } + } + return (rsdp_t *)table_addr; +} +#else +static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table) +{ + efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables, + system_table->num_config_tables * sizeof(efi32_config_table_t), + true); + if (config_tables == NULL) return NULL; + + uintptr_t table_addr = 0; + for (uint32_t i = 0; i < system_table->num_config_tables; i++) { + if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) { + table_addr = config_tables[i].table; + break; + } + if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) { + table_addr = config_tables[i].table; + } + } + return (rsdp_t *)table_addr; +} +#endif + +static uintptr_t find_rsdp(void) +{ + const boot_params_t *boot_params = (boot_params_t *)boot_params_addr; + + const efi_info_t *efi_info = &boot_params->efi_info; + + // Search for the RSDP + rsdp_t *rp = NULL; +#ifdef __x86_64__ + if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) { + uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab; + system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true); + if (system_table_addr != 0) { + rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr); + if (rp) rsdp_source = "EFI64 system table"; + } + } +#else + if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) { + uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true); + if (system_table_addr != 0) { + rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr); + if (rp) rsdp_source = "EFI32 system table"; + } + } +#endif + if (rp == NULL) { + // Search the BIOS EBDA area. + uintptr_t address = *(uint16_t *)0x40E << 4; + if (address) { + rp = scan_for_rsdp(address, 0x400); + if (rp) rsdp_source = "BIOS EBDA"; + } + } + if (rp == NULL) { + // Search the BIOS reserved area. + rp = scan_for_rsdp(0xE0000, 0x20000); + if (rp) rsdp_source = "BIOS reserved area"; + } + if (rp == NULL) { + // RSDP not found, give up. + return 0; + } + return (uintptr_t)rp; +} + +static uintptr_t find_acpi_table(uint32_t table_signature) +{ + rsdp_t *rp = (rsdp_t *)rsdp_addr;; + + // Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT. + rsdt_header_t *rt; + + if (rp->revision >= 2) { + rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true); + if (rt == NULL) { + return 0; + } + // Validate the XSDT. + if (*(uint32_t *)rt != XSDTSignature) { + return 0; + } + rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true); + if (rt == NULL || acpi_checksum(rt, rt->length) != 0) { + return 0; + } + // Scan the XSDT for a pointer to the MADT. + uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); + uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length); + + while (tab_ptr < tab_end) { + uintptr_t addr = *tab_ptr++; // read the next table entry + uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true); + + if (ptr && *ptr == table_signature) { + return addr; + } + } + } else { + rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true); + if (rt == NULL) { + return 0; + } + // Validate the RSDT. + if (*(uint32_t *)rt != RSDTSignature) { + return 0; + } + rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true); + if (rt == NULL || acpi_checksum(rt, rt->length) != 0) { + return 0; + } + // Scan the RSDT for a pointer to the MADT. + uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); + uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length); + + while (tab_ptr < tab_end) { + uintptr_t addr = *tab_ptr++; // read the next table entry + uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true); + + if (ptr && *ptr == table_signature) { + return addr; + } + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Public Functions +//------------------------------------------------------------------------------ + +int acpi_checksum(const void *data, int length) +{ + uint8_t sum = 0; + + uint8_t *ptr = (uint8_t *)data; + while (length--) { + sum += *ptr++; + } + return sum; +} + +void acpi_init(void) +{ + // Find ACPI RDST Table Address + rsdp_addr = find_rsdp(); + + // Find ACPI MADT Table Address + madt_addr = find_acpi_table(MADTSignature); + + // Find ACPI FADT Table Address + fadt_addr = find_acpi_table(FADTSignature); + + // Find ACPI HPET Table Address + hpet_addr = find_acpi_table(HPETSignature); +} diff --git a/system/acpi.h b/system/acpi.h new file mode 100644 index 0000000..c6273d3 --- /dev/null +++ b/system/acpi.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _ACPI_H_ +#define _ACPI_H_ +/** + * \file + * + * Provides support for multi-threaded operation. + * + *//* + * Copyright (C) 2020-2022 Martin Whitaker. + * Copyright (C) 2020-2022 Sam Whitaker. + */ + +#include +#include + +/** + * The search step that located the ACPI RSDP (for debug). + */ +extern const char *rsdp_source; + +/** + * The address of the ACPI RSDP + */ +extern uintptr_t rsdp_addr; + +/** + * The address of the ACPI MADT + */ +extern uintptr_t madt_addr; + +/** + * The address of the ACPI FADT + */ +extern uintptr_t fadt_addr; + +/** + * The address of the ACPI HPET + */ +extern uintptr_t hpet_addr; + +/** + * ACPI Table Checksum Function + */ +int acpi_checksum(const void *data, int length); + +/** + * Initialises the SMP state and detects the number of available CPU cores. + */ +void acpi_init(void); + +#endif /* _ACPI_H_ */ diff --git a/system/smp.c b/system/smp.c index 8c34d67..e7ab546 100644 --- a/system/smp.c +++ b/system/smp.c @@ -1,11 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. // // Derived from an extract of memtest86+ smp.c: // // MemTest86+ V5 Specific code (GPL V2.0) -// By Samuel DEMEULEMEESTER, sdemeule@memtest.org -// http://www.canardpc.com - http://www.memtest.org // ------------------------------------------------ // smp.c - MemTest-86 Version 3.5 // @@ -15,6 +14,7 @@ #include #include +#include "acpi.h" #include "boot.h" #include "bootparams.h" #include "efi.h" @@ -75,18 +75,8 @@ // Table signatures #define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24)) - #define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24)) -#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24)) -#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24)) - -#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) - -#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) - -#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) - // MP config table entry types #define MP_PROCESSOR 0 @@ -189,30 +179,6 @@ typedef struct { uint8_t dst_apic_lint; } mp_local_interrupt_entry_t; -typedef struct { - char signature[8]; // "RSD PTR " - uint8_t checksum; - char oem_id[6]; - uint8_t revision; - uint32_t rsdt_addr; - uint32_t length; - uint64_t xsdt_addr; - uint8_t xchecksum; - uint8_t reserved[3]; -} rsdp_t; - -typedef struct { - char signature[4]; // "RSDT" or "XSDT" - uint32_t length; - uint8_t revision; - uint8_t checksum; - char oem_id[6]; - char oem_table_id[8]; - char oem_revision[4]; - char creator_id[4]; - char creator_revision[4]; -} rsdt_header_t; - typedef struct { char signature[4]; // "APIC" uint32_t length; @@ -251,9 +217,6 @@ typedef struct { // Private Variables //------------------------------------------------------------------------------ -static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }; -static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} }; - static apic_register_t *apic = NULL; static uint8_t apic_id_to_cpu_num[MAX_APIC_IDS]; @@ -270,10 +233,6 @@ static uintptr_t alloc_addr = 0; int num_available_cpus = 1; // There is always at least one CPU, the BSP -const char *rsdp_source = ""; - -uintptr_t rsdp_addr = 0; - //------------------------------------------------------------------------------ // Private Functions //------------------------------------------------------------------------------ @@ -293,24 +252,13 @@ static uint32_t apic_read(int reg) return read32(&apic[reg][0]); } -static int checksum(const void *data, int length) -{ - uint8_t sum = 0; - - uint8_t *ptr = (uint8_t *)data; - while (length--) { - sum += *ptr++; - } - return sum; -} - static floating_pointer_struct_t *scan_for_floating_ptr_struct(uintptr_t addr, int length) { uint32_t *ptr = (uint32_t *)addr; uint32_t *end = ptr + length / sizeof(uint32_t); while (ptr < end) { - if (*ptr == FPSignature && checksum(ptr, 16) == 0) { + if (*ptr == FPSignature && acpi_checksum(ptr, 16) == 0) { floating_pointer_struct_t *fp = (floating_pointer_struct_t *)ptr; if (fp->length == 1 && (fp->spec_rev == 1 || fp->spec_rev == 4)) { return fp; @@ -329,7 +277,7 @@ static bool read_mp_config_table(uintptr_t addr) mpc = (mp_config_table_header_t *)map_region(addr, mpc->length, true); if (mpc == NULL) return false; - if (mpc->signature != MPCSignature || checksum(mpc, mpc->length) != 0) { + if (mpc->signature != MPCSignature || acpi_checksum(mpc, mpc->length) != 0) { return false; } @@ -426,32 +374,17 @@ static bool find_cpus_in_floating_mp_struct(void) return false; } -static rsdp_t *scan_for_rsdp(uintptr_t addr, int length) +static bool find_cpus_in_madt(void) { - uint32_t *ptr = (uint32_t *)addr; - uint32_t *end = ptr + length / sizeof(uint32_t); + if(madt_addr == 0) return false; - while (ptr < end) { - rsdp_t *rp = (rsdp_t *)ptr; - if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && checksum(ptr, 20) == 0) { - if (rp->revision < 2 || (rp->length < 1024 && checksum(ptr, rp->length) == 0)) { - return rp; - } - } - ptr += 4; - } - return NULL; -} - -static bool parse_madt(uintptr_t addr) -{ - madt_table_header_t *mpc = (madt_table_header_t *)map_region(addr, sizeof(madt_table_header_t), true); + madt_table_header_t *mpc = (madt_table_header_t *)map_region(madt_addr, sizeof(madt_table_header_t), true); if (mpc == NULL) return false; - mpc = (madt_table_header_t *)map_region(addr, mpc->length, true); + mpc = (madt_table_header_t *)map_region(madt_addr, mpc->length, true); if (mpc == NULL) return false; - if (checksum(mpc, mpc->length) != 0) { + if (acpi_checksum(mpc, mpc->length) != 0) { return false; } @@ -491,150 +424,6 @@ static bool parse_madt(uintptr_t addr) return true; } -#ifdef __x86_64__ -static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table) -{ - efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi64_config_table_t), true); - if (config_tables == NULL) return NULL; - - uintptr_t table_addr = 0; - for (uint32_t i = 0; i < system_table->num_config_tables; i++) { - if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) { - table_addr = config_tables[i].table; - break; - } - if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) { - table_addr = config_tables[i].table; - } - } - return (rsdp_t *)table_addr; -} -#else -static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table) -{ - efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi32_config_table_t), true); - if (config_tables == NULL) return NULL; - - uintptr_t table_addr = 0; - for (uint32_t i = 0; i < system_table->num_config_tables; i++) { - if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) { - table_addr = config_tables[i].table; - break; - } - if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) { - table_addr = config_tables[i].table; - } - } - return (rsdp_t *)table_addr; -} -#endif - -static bool find_cpus_in_rsdp(void) -{ - const boot_params_t *boot_params = (boot_params_t *)boot_params_addr; - - const efi_info_t *efi_info = &boot_params->efi_info; - - // Search for the RSDP - rsdp_t *rp = NULL; -#ifdef __x86_64__ - if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) { - uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab; - system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true); - if (system_table_addr != 0) { - rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr); - if (rp) rsdp_source = "EFI64 system table"; - } - } -#else - if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) { - uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true); - if (system_table_addr != 0) { - rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr); - if (rp) rsdp_source = "EFI32 system table"; - } - } -#endif - if (rp == NULL) { - // Search the BIOS EBDA area. - uintptr_t address = *(uint16_t *)0x40E << 4; - if (address) { - rp = scan_for_rsdp(address, 0x400); - if (rp) rsdp_source = "BIOS EBDA"; - } - } - if (rp == NULL) { - // Search the BIOS reserved area. - rp = scan_for_rsdp(0xE0000, 0x20000); - if (rp) rsdp_source = "BIOS reserved area"; - } - if (rp == NULL) { - // RSDP not found, give up. - return false; - } - rsdp_addr = (uintptr_t)rp; - - // Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT. - rsdt_header_t *rt; - if (rp->revision >= 2) { - rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true); - if (rt == NULL) { - return false; - } - // Validate the XSDT. - if (*(uint32_t *)rt != XSDTSignature) { - return false; - } - rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true); - if (rt == NULL || checksum(rt, rt->length) != 0) { - return false; - } - // Scan the XSDT for a pointer to the MADT. - uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); - uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length); - - while (tab_ptr < tab_end) { - uintptr_t addr = *tab_ptr++; // read the next table entry - uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true); - - if (ptr && *ptr == MADTSignature) { - if (parse_madt(addr)) { - return true; - } - } - } - } else { - rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true); - if (rt == NULL) { - return false; - } - // Validate the RSDT. - if (*(uint32_t *)rt != RSDTSignature) { - return false; - } - rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true); - if (rt == NULL || checksum(rt, rt->length) != 0) { - return false; - } - // Scan the RSDT for a pointer to the MADT. - uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); - uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length); - - while (tab_ptr < tab_end) { - uintptr_t addr = *tab_ptr++; // read the next table entry - uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true); - - if (ptr && *ptr == MADTSignature) { - if (parse_madt(addr)) { - return true; - } - } - } - } - - return false; -} - static inline void send_ipi(int apic_id, int trigger, int level, int mode, uint8_t vector) { apic_write(APIC_REG_ICRHI, apic_id << 24); @@ -671,7 +460,8 @@ static uint32_t read_apic_esr(bool is_p5) static bool start_cpu(int cpu_num) { - // This is based on the method used in Linux 5.14. We don't support non-integrated APICs, so can simplify it a bit. + // This is based on the method used in Linux 5.14. + // We don't support non-integrated APICs, so can simplify it a bit. int apic_id = cpu_num_to_apic_id[cpu_num]; @@ -748,7 +538,7 @@ void smp_init(bool smp_enable) } if (smp_enable) { - (void)(find_cpus_in_rsdp() || find_cpus_in_floating_mp_struct()); + (void)(find_cpus_in_madt() || find_cpus_in_floating_mp_struct()); } diff --git a/system/smp.h b/system/smp.h index 9cf608c..6f601a9 100644 --- a/system/smp.h +++ b/system/smp.h @@ -38,15 +38,6 @@ typedef enum __attribute__ ((packed)) { */ extern int num_available_cpus; -/** - * The search step that located the ACPI RSDP (for debug). - */ -extern const char *rsdp_source; -/** - * The address of the ACPI RSDP (for debug). - */ -extern uintptr_t rsdp_addr; - /** * Initialises the SMP state and detects the number of available CPU cores. */ From cee2d32766855855d8ce5ac173145a30c793c3b0 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Thu, 9 Jun 2022 01:27:42 +0200 Subject: [PATCH 010/113] Add a few ACPI Tables Signature that could be useful later --- system/acpi.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/system/acpi.c b/system/acpi.c index e1efe21..c770d0f 100644 --- a/system/acpi.c +++ b/system/acpi.c @@ -22,17 +22,23 @@ #define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24)) #define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24)) -#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) +#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) // Root System Description Table -#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) +#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) // Extended System Description Table -#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) +#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) // Multiple APIC Description Table -#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24)) +#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24)) // Fixed ACPI Description Table -#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24)) +#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24)) // High Precision Event Timer -#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) +#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) // Error Injection Table +#define ERSTSignature ('E' | ('R' << 8) | ('S' << 16) | ('T' << 24)) // Error Record Serialization Table +#define CPEPSignature ('C' | ('P' << 8) | ('E' << 16) | ('P' << 24)) // Corrected Platform Error Polling Table +#define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table + +#define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality System Information Table (NUMA) +#define SRATSignature ('S' | ('R' << 8) | ('A' << 16) | ('T' << 24)) // System Resource Affinity Table (NUMA) //------------------------------------------------------------------------------ // Types From eac4d03462a13188d9aeb55c2b70e0c4cbd11657 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 12 Jun 2022 18:42:35 +0200 Subject: [PATCH 011/113] Parse FADT to find ACPI Timer Base Address and specs --- system/acpi.c | 83 +++++++++++++++++++++++++++++++++++++++++++-------- system/acpi.h | 39 +++++++++++++----------- system/smp.c | 6 ++-- 3 files changed, 95 insertions(+), 33 deletions(-) diff --git a/system/acpi.c b/system/acpi.c index c770d0f..35c7f7c 100644 --- a/system/acpi.c +++ b/system/acpi.c @@ -35,7 +35,7 @@ #define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) // Error Injection Table #define ERSTSignature ('E' | ('R' << 8) | ('S' << 16) | ('T' << 24)) // Error Record Serialization Table #define CPEPSignature ('C' | ('P' << 8) | ('E' << 16) | ('P' << 24)) // Corrected Platform Error Polling Table -#define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table +#define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table #define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality System Information Table (NUMA) #define SRATSignature ('S' | ('R' << 8) | ('A' << 16) | ('T' << 24)) // System Resource Affinity Table (NUMA) @@ -44,6 +44,14 @@ // Types //------------------------------------------------------------------------------ +typedef struct __attribute__ ((packed)) { + uint8_t address_space; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t access_size; + uint64_t address; +} acpi_gen_addr_struct; + typedef struct { char signature[8]; // "RSD PTR " uint8_t checksum; @@ -81,10 +89,7 @@ static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0x const char *rsdp_source = ""; -uintptr_t rsdp_addr = 0; -uintptr_t madt_addr = 0; -uintptr_t fadt_addr = 0; -uintptr_t hpet_addr = 0; +acpi_t acpi_config = {0, 0, 0, 0, 0, 0, 0, 0, false}; //------------------------------------------------------------------------------ // Private Functions @@ -197,11 +202,16 @@ static uintptr_t find_rsdp(void) static uintptr_t find_acpi_table(uint32_t table_signature) { - rsdp_t *rp = (rsdp_t *)rsdp_addr;; + rsdp_t *rp = (rsdp_t *)acpi_config.rsdp_addr; - // Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT. + // Found the RSDP, now get either the RSDT or XSDT + // and scan it for a pointer to the table we're looking for rsdt_header_t *rt; + if (acpi_config.ver_maj < rp->revision) { + acpi_config.ver_maj = rp->revision; + } + if (rp->revision >= 2) { rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true); if (rt == NULL) { @@ -215,7 +225,7 @@ static uintptr_t find_acpi_table(uint32_t table_signature) if (rt == NULL || acpi_checksum(rt, rt->length) != 0) { return 0; } - // Scan the XSDT for a pointer to the MADT. + // Scan the XSDT for a pointer to the table we're looking for. uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length); @@ -240,7 +250,7 @@ static uintptr_t find_acpi_table(uint32_t table_signature) if (rt == NULL || acpi_checksum(rt, rt->length) != 0) { return 0; } - // Scan the RSDT for a pointer to the MADT. + // Scan the RSDT for a pointer to the table we're looking for. uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t)); uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length); @@ -257,6 +267,48 @@ static uintptr_t find_acpi_table(uint32_t table_signature) return 0; } +static bool parse_fadt(uintptr_t fadt_addr) +{ + // FADT is a very big & complex table and we only need a few data. + // We use byte offset instead of a complete struct. + + // FADT Header is identical to RSDP Header + rsdt_header_t *fadt = (rsdt_header_t *)fadt_addr; + + // Validate FADT + if (fadt == NULL || acpi_checksum(fadt, fadt->length) != 0) { + return false; + } + + // Get ACPI Version + acpi_config.ver_maj = fadt->revision; + + if (fadt->length > FADT_MINOR_REV_OFFSET) { + acpi_config.ver_min = *(uint8_t *)(fadt_addr+FADT_MINOR_REV_OFFSET) & 0xF; + } + + // Get Old PM Base Address (32bit IO) + acpi_config.pm_addr = *(uint32_t *)(fadt_addr+FADT_PM_TMR_BLK_OFFSET); + acpi_config.pm_is_io = true; + +#ifdef __x86_64__ + acpi_gen_addr_struct *rt; + + // Get APIC Timer Address + if (fadt->length > FADT_X_PM_TMR_BLK_OFFSET) { + rt = (acpi_gen_addr_struct *)map_region(fadt_addr+FADT_X_PM_TMR_BLK_OFFSET, sizeof(acpi_gen_addr_struct), true); + + acpi_config.pm_is_io = (rt->address_space == 1) ? true : false; + + if (rt->address != 0) { + acpi_config.pm_addr = rt->address; + } + } +#endif + + return true; +} + //------------------------------------------------------------------------------ // Public Functions //------------------------------------------------------------------------------ @@ -275,14 +327,19 @@ int acpi_checksum(const void *data, int length) void acpi_init(void) { // Find ACPI RDST Table Address - rsdp_addr = find_rsdp(); + acpi_config.rsdp_addr = find_rsdp(); // Find ACPI MADT Table Address - madt_addr = find_acpi_table(MADTSignature); + acpi_config.madt_addr = find_acpi_table(MADTSignature); // Find ACPI FADT Table Address - fadt_addr = find_acpi_table(FADTSignature); + acpi_config.fadt_addr = find_acpi_table(FADTSignature); + + // Parse FADT + if (acpi_config.fadt_addr) { + parse_fadt(acpi_config.fadt_addr); + } // Find ACPI HPET Table Address - hpet_addr = find_acpi_table(HPETSignature); + acpi_config.hpet_addr = find_acpi_table(HPETSignature); } diff --git a/system/acpi.h b/system/acpi.h index c6273d3..72c818e 100644 --- a/system/acpi.h +++ b/system/acpi.h @@ -14,30 +14,35 @@ #include #include +#define FADT_PM_TMR_BLK_OFFSET 76 +#define FADT_MINOR_REV_OFFSET 131 +#define FADT_X_PM_TMR_BLK_OFFSET 208 + +/** + * A struct containing various ACPI-related infos for later uses. + */ + +typedef struct { + uint8_t ver_maj; + uint8_t ver_min; + uint64_t test; + uintptr_t rsdp_addr; + uintptr_t madt_addr; + uintptr_t fadt_addr; + uintptr_t hpet_addr; + uintptr_t pm_addr; + bool pm_is_io; +} acpi_t; + /** * The search step that located the ACPI RSDP (for debug). */ extern const char *rsdp_source; /** - * The address of the ACPI RSDP + * Global ACPI config struct */ -extern uintptr_t rsdp_addr; - -/** - * The address of the ACPI MADT - */ -extern uintptr_t madt_addr; - -/** - * The address of the ACPI FADT - */ -extern uintptr_t fadt_addr; - -/** - * The address of the ACPI HPET - */ -extern uintptr_t hpet_addr; +extern acpi_t acpi_config; /** * ACPI Table Checksum Function diff --git a/system/smp.c b/system/smp.c index e7ab546..4c9bcdc 100644 --- a/system/smp.c +++ b/system/smp.c @@ -376,12 +376,12 @@ static bool find_cpus_in_floating_mp_struct(void) static bool find_cpus_in_madt(void) { - if(madt_addr == 0) return false; + if(acpi_config.madt_addr == 0) return false; - madt_table_header_t *mpc = (madt_table_header_t *)map_region(madt_addr, sizeof(madt_table_header_t), true); + madt_table_header_t *mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, sizeof(madt_table_header_t), true); if (mpc == NULL) return false; - mpc = (madt_table_header_t *)map_region(madt_addr, mpc->length, true); + mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, mpc->length, true); if (mpc == NULL) return false; if (acpi_checksum(mpc, mpc->length) != 0) { From a5576974cf8661b3f3a1f0074b16fa59033130c5 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 12 Jun 2022 22:32:30 +0200 Subject: [PATCH 012/113] Add ACPI Timer as the primary TSC correction source and PIT Timer as fallback --- app/main.c | 10 +++--- build32/Makefile | 1 + build64/Makefile | 1 + system/acpi.c | 2 +- system/acpi.h | 3 +- system/cpuinfo.c | 34 ------------------ system/timers.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ system/timers.h | 20 +++++++++++ 8 files changed, 124 insertions(+), 41 deletions(-) create mode 100644 system/timers.c create mode 100644 system/timers.h diff --git a/app/main.c b/app/main.c index d589761..16f7a3c 100644 --- a/app/main.c +++ b/app/main.c @@ -34,6 +34,7 @@ #include "smbios.h" #include "smp.h" #include "temperature.h" +#include "timers.h" #include "vmem.h" #include "unistd.h" @@ -221,6 +222,8 @@ static void global_init(void) acpi_init(); + timers_init(); + membw_init(); smbios_init(); @@ -281,10 +284,9 @@ static void global_init(void) for (int i = 0; i < pm_map_size; i++) { trace(0, "pm %0*x - %0*x", 2*sizeof(uintptr_t), pm_map[i].start, 2*sizeof(uintptr_t), pm_map[i].end); } - if (rsdp_addr != 0) { - trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr); - trace(0, "ACPI FADT found at %0*x", 2*sizeof(uintptr_t), fadt_addr); - trace(0, "ACPI HPET found at %0*x", 2*sizeof(uintptr_t), hpet_addr); + if (acpi_config.rsdp_addr != 0) { + trace(0, "ACPI RSDP (v%u.%u) found in %s at %0*x", acpi_config.ver_maj, acpi_config.ver_min, rsdp_source, 2*sizeof(uintptr_t), acpi_config.rsdp_addr); + trace(0, "ACPI FADT found at %0*x", 2*sizeof(uintptr_t), acpi_config.fadt_addr); } if (!load_addr_ok) { trace(0, "Cannot relocate program. Press any key to reboot..."); diff --git a/build32/Makefile b/build32/Makefile index 7fcc728..1e03597 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -33,6 +33,7 @@ SYS_OBJS = system/acpi.o \ system/smbus.o \ system/smp.o \ system/temperature.o \ + system/timers.o \ system/uhci.o \ system/usbhcd.o \ system/vmem.o \ diff --git a/build64/Makefile b/build64/Makefile index 4dcb791..99c5213 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -33,6 +33,7 @@ SYS_OBJS = system/acpi.o \ system/smbus.o \ system/smp.o \ system/temperature.o \ + system/timers.o \ system/uhci.o \ system/usbhcd.o \ system/vmem.o \ diff --git a/system/acpi.c b/system/acpi.c index 35c7f7c..b9d74f7 100644 --- a/system/acpi.c +++ b/system/acpi.c @@ -89,7 +89,7 @@ static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0x const char *rsdp_source = ""; -acpi_t acpi_config = {0, 0, 0, 0, 0, 0, 0, 0, false}; +acpi_t acpi_config = {0, 0, 0, 0, 0, 0, 0, false}; //------------------------------------------------------------------------------ // Private Functions diff --git a/system/acpi.h b/system/acpi.h index 72c818e..ee0a54d 100644 --- a/system/acpi.h +++ b/system/acpi.h @@ -22,10 +22,9 @@ * A struct containing various ACPI-related infos for later uses. */ -typedef struct { +typedef struct __attribute__ ((packed)) { uint8_t ver_maj; uint8_t ver_min; - uint64_t test; uintptr_t rsdp_addr; uintptr_t madt_addr; uintptr_t fadt_addr; diff --git a/system/cpuinfo.c b/system/cpuinfo.c index 0123d4e..f8522ef 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -33,7 +33,6 @@ // Constants //------------------------------------------------------------------------------ -#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz #define BENCH_MIN_START_ADR 0x1000000 // 16MB //------------------------------------------------------------------------------ @@ -861,37 +860,6 @@ static void determine_cpu_model(void) } } -static void measure_cpu_speed(void) -{ - if (cpuid_info.flags.rdtsc == 0) { - return; - } - - // Set up timer - outb((inb(0x61) & ~0x02) | 0x01, 0x61); - outb(0xb0, 0x43); - outb(PIT_TICKS_50mS & 0xff, 0x42); - outb(PIT_TICKS_50mS >> 8, 0x42); - - uint32_t start_time; - rdtscl(start_time); - - int loops = 0; - do { - loops++; - } while ((inb(0x61) & 0x20) == 0); - - uint32_t end_time; - rdtscl(end_time); - - uint32_t run_time = end_time - start_time; - - // Make sure we have a credible result - if (loops >= 4 && run_time >= 50000) { - clks_per_msec = run_time / 50; - } -} - static uint32_t memspeed(uintptr_t src, uint32_t len, int iter) { uintptr_t dst; @@ -1084,8 +1052,6 @@ void cpuinfo_init(void) determine_cache_size(); determine_cpu_model(); - - measure_cpu_speed(); } void membw_init(void) diff --git a/system/timers.c b/system/timers.c new file mode 100644 index 0000000..54794fa --- /dev/null +++ b/system/timers.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. + +#include +#include +#include + +#include "acpi.h" +#include "cpuid.h" +#include "cpuinfo.h" +#include "io.h" +#include "tsc.h" + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +#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 +//------------------------------------------------------------------------------ + +static void correct_tsc(void) +{ + uint32_t start_time, end_time, run_time, counter; + int loops = 0; + + if (cpuid_info.flags.rdtsc == 0) { + return; + } + + // If available, use APIC Timer to find TSC correction factor + if (acpi_config.pm_is_io && acpi_config.pm_addr != 0) { + rdtscl(start_time); + + counter = inl(acpi_config.pm_addr); + + // Make sure counter is incrementing + if (inl(acpi_config.pm_addr) > counter) { + + while (1) { + if (inl(acpi_config.pm_addr) > (counter + APIC_TICKS_50mS) || loops > 1000000) { + break; + } + loops++; + } + + rdtscl(end_time); + + run_time = end_time - start_time; + + // Make sure we have a credible result + if (loops >= 10 && run_time >= 50000) { + clks_per_msec = run_time / 50; + return; + } + } + } + + // Use PIT Timer to find TSC correction factor if APIC not available + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + outb(0xb0, 0x43); + outb(PIT_TICKS_50mS & 0xff, 0x42); + outb(PIT_TICKS_50mS >> 8, 0x42); + + rdtscl(start_time); + + loops = 0; + do { + loops++; + } while ((inb(0x61) & 0x20) == 0); + + rdtscl(end_time); + + run_time = end_time - start_time; + + // Make sure we have a credible result + if (loops >= 4 && run_time >= 50000) { + clks_per_msec = run_time / 50; + } +} + +//------------------------------------------------------------------------------ +// Public Functions +//------------------------------------------------------------------------------ + +void timers_init(void) +{ + correct_tsc(); +} diff --git a/system/timers.h b/system/timers.h new file mode 100644 index 0000000..9c8d165 --- /dev/null +++ b/system/timers.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _TIMERS_H_ +#define _TIMERS_H_ +/** + * \file + * + * Provides support for various timers sources + * + *//* + * Copyright (C) 2020-2022 Martin Whitaker. + * Copyright (C) 2004-2022 Sam Demeulemeester + */ + + +/** + * Initialize timers (to correct TSC frequency) + */ +void timers_init(void); + +#endif /* _TIMERS_H_ */ From 231b389b3c072bb3a57044b9ed678ec84323c43c Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 19 Jun 2022 16:26:00 +0200 Subject: [PATCH 013/113] Various minor cosmetic changes on acpi.c/h (mainly comments and code format) --- system/acpi.c | 11 +++++------ system/acpi.h | 7 ++++--- system/smp.c | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/system/acpi.c b/system/acpi.c index b9d74f7..b441ddb 100644 --- a/system/acpi.c +++ b/system/acpi.c @@ -37,7 +37,7 @@ #define CPEPSignature ('C' | ('P' << 8) | ('E' << 16) | ('P' << 24)) // Corrected Platform Error Polling Table #define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table -#define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality System Information Table (NUMA) +#define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality Information Table (NUMA) #define SRATSignature ('S' | ('R' << 8) | ('A' << 16) | ('T' << 24)) // System Resource Affinity Table (NUMA) //------------------------------------------------------------------------------ @@ -326,20 +326,19 @@ int acpi_checksum(const void *data, int length) void acpi_init(void) { - // Find ACPI RDST Table Address acpi_config.rsdp_addr = find_rsdp(); - // Find ACPI MADT Table Address + if (acpi_config.rsdp_addr == 0) { + return; + } + acpi_config.madt_addr = find_acpi_table(MADTSignature); - // Find ACPI FADT Table Address acpi_config.fadt_addr = find_acpi_table(FADTSignature); - // Parse FADT if (acpi_config.fadt_addr) { parse_fadt(acpi_config.fadt_addr); } - // Find ACPI HPET Table Address acpi_config.hpet_addr = find_acpi_table(HPETSignature); } diff --git a/system/acpi.h b/system/acpi.h index ee0a54d..6194260 100644 --- a/system/acpi.h +++ b/system/acpi.h @@ -4,11 +4,11 @@ /** * \file * - * Provides support for multi-threaded operation. + * Provides support for ACPI (Find & parse tables) * *//* * Copyright (C) 2020-2022 Martin Whitaker. - * Copyright (C) 2020-2022 Sam Whitaker. + * Copyright (C) 2004-2022 Sam Demeulemeester. */ #include @@ -49,7 +49,8 @@ extern acpi_t acpi_config; int acpi_checksum(const void *data, int length); /** - * Initialises the SMP state and detects the number of available CPU cores. + * Look for specific ACPI Tables Addresses (RSDP, MADT, ...) + * and parse some of the tables */ void acpi_init(void); diff --git a/system/smp.c b/system/smp.c index 4c9bcdc..9e5d8cb 100644 --- a/system/smp.c +++ b/system/smp.c @@ -376,7 +376,9 @@ static bool find_cpus_in_floating_mp_struct(void) static bool find_cpus_in_madt(void) { - if(acpi_config.madt_addr == 0) return false; + if (acpi_config.madt_addr == 0) { + return false + } madt_table_header_t *mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, sizeof(madt_table_header_t), true); if (mpc == NULL) return false; From 680e6ad79b1bd7098b7b4a0a5446a1c485394244 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 19 Jun 2022 16:27:53 +0200 Subject: [PATCH 014/113] Typo on smp.c (missing ;) --- system/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smp.c b/system/smp.c index 9e5d8cb..ff08df4 100644 --- a/system/smp.c +++ b/system/smp.c @@ -377,7 +377,7 @@ static bool find_cpus_in_floating_mp_struct(void) static bool find_cpus_in_madt(void) { if (acpi_config.madt_addr == 0) { - return false + return false; } madt_table_header_t *mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, sizeof(madt_table_header_t), true); From 1c88824a7d760353368946859ce5221ea637a45a Mon Sep 17 00:00:00 2001 From: 01e3 <105136494+01e3@users.noreply.github.com> Date: Sun, 19 Jun 2022 07:40:30 -0700 Subject: [PATCH 015/113] Optimize screen & serial output handling. (#85) - Enable VGA/FB to output box drawing characters while maintaining VT100 character set for serial. Shorten and simplify the screen setup code. - Track the background color to decide if the serial output needs to be inverted. Remove no longer needed logic for known areas of the screen that need to be inverted. As a bonus - popup menu can now be also inverted on serial. - Reduce the amount of data sent to serial by using CR+LF when possible instead of always relying on absolute positioning. Add tty_print() for positioning the cursor, remove no longer needed tty_print(). - Remove no longer needed "LF -> LF+CR" logic from serial_echo_print(). Before (gcc-11.3.0-x86_64): text data bss total filename 929 357 64 1350 system/serial.o 3517 1356 54 4927 app/display.o After (gcc-11.3.0-x86_64): text data bss total filename 907 336 64 1307 system/serial.o 3442 1242 54 4738 app/display.o Co-authored-by: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> --- app/display.c | 53 +++++++++++----------- system/serial.c | 118 ++++++++++++++++++++++++++++-------------------- 2 files changed, 96 insertions(+), 75 deletions(-) diff --git a/app/display.c b/app/display.c index fd2348a..88d8d0a 100644 --- a/app/display.c +++ b/app/display.c @@ -80,6 +80,11 @@ void display_init(void) clear_screen(); + /* The commented horizontal lines provide visual cue for where and how + * they will appear on the screen. They are drawn down below using + * Extended ASCII characters. + */ + set_foreground_colour(BLACK); set_background_colour(WHITE); clear_screen_region(0, 0, 0, 27); @@ -88,34 +93,30 @@ void display_init(void) printc(0, 14, '+'); set_foreground_colour(WHITE); set_background_colour(BLUE); - prints(0,28, "| "); - prints(1, 0, "CLK/Temp: N/A | Pass % "); - prints(2, 0, "L1 Cache: N/A | Test % "); - prints(3, 0, "L2 Cache: N/A | Test # "); - prints(4, 0, "L3 Cache: N/A | Testing: "); - prints(5, 0, "Memory : N/A | Pattern: "); - prints(6, 0, "--------------------------------------------------------------------------------"); - prints(7, 0, "CPU: SMP: N/A | Time: Status: Init. "); - prints(8, 0, "Using: | Pass: Errors: "); - prints(9, 0, "--------------------------------------------------------------------------------"); + prints(1, 0, "CLK/Temp: N/A | Pass %"); + prints(2, 0, "L1 Cache: N/A | Test %"); + prints(3, 0, "L2 Cache: N/A | Test #"); + prints(4, 0, "L3 Cache: N/A | Testing:"); + prints(5, 0, "Memory : N/A | Pattern:"); +// prints(6, 0, "--------------------------------------------------------------------------------"); + 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. - // Disable if TTY is enabled to avoid VT100 char replacements - if (!enable_tty) { - for (int i = 0;i < 80; i++) { - print_char(6, i, 0xc4); - print_char(9, i, 0xc4); - } - for (int i = 0; i < 6; i++) { - print_char(i, 28, 0xb3); - } - for (int i = 7; i < 10; i++) { - print_char(i, 42, 0xb3); - } - print_char(6, 28, 0xc1); - print_char(6, 42, 0xc2); - print_char(9, 42, 0xc1); + for (int i = 0;i < 80; i++) { + print_char(6, i, 0xc4); + print_char(9, i, 0xc4); } + for (int i = 0; i < 6; i++) { + print_char(i, 28, 0xb3); + } + for (int i = 7; i < 10; i++) { + print_char(i, 42, 0xb3); + } + + print_char(6, 28, 0xc1); + print_char(6, 42, 0xc2); + print_char(9, 42, 0xc1); set_foreground_colour(BLUE); set_background_colour(WHITE); diff --git a/system/serial.c b/system/serial.c index 21ba971..cdb3684 100644 --- a/system/serial.c +++ b/system/serial.c @@ -67,33 +67,24 @@ void serial_echo_print(const char *p) if (!port->enable) { return; } + /* Now, do each character */ while (*p) { - serial_wait_for_xmit(port); - /* Send the character out. */ - serial_write_reg(port, UART_TX, *p); - if (*p==10) { - serial_wait_for_xmit(port); - serial_write_reg(port, UART_TX, 13); - } - p++; + serial_wait_for_xmit(port); + serial_write_reg(port, UART_TX, *p++); } } -void tty_print(int y, int x, const char *p) +void tty_goto(int y, int x) { - static char sx[3], sy[3]; - - itoa(++x,sx); - itoa(++y,sy); + static char s[3]; serial_echo_print("\x1b["); - serial_echo_print(sy); + serial_echo_print(itoa(y + 1, s)); serial_echo_print(";"); - serial_echo_print(sx); + serial_echo_print(itoa(x + 1, s)); serial_echo_print("H"); - serial_echo_print(p); } //------------------------------------------------------------------------------ @@ -135,8 +126,8 @@ void tty_init(void) serial_write_reg(&console_serial, UART_LCR, lcr); /* Done with divisor */ /* Prior to disabling interrupts, read the LSR and RBR registers */ - uart_status = serial_read_reg(&console_serial, UART_LSR); /* COM? LSR */ - uart_status = serial_read_reg(&console_serial, UART_RX); /* COM? RBR */ + uart_status = serial_read_reg(&console_serial, UART_LSR); /* COM? LSR */ + uart_status = serial_read_reg(&console_serial, UART_RX); /* COM? RBR */ serial_write_reg(&console_serial, UART_IER, 0x00); /* Disable all interrupts */ tty_clear_screen(); @@ -146,7 +137,9 @@ void tty_init(void) void tty_send_region(int start_row, int start_col, int end_row, int end_col) { char p[SCREEN_WIDTH+1]; - int col_len = end_col - start_col; + uint8_t ch; + int pos = 0; + int cur_inverse = -1, inverse = false; if (start_col > (SCREEN_WIDTH - 1) || end_col > (SCREEN_WIDTH - 1)) { return; @@ -158,42 +151,69 @@ void tty_send_region(int start_row, int start_col, int end_row, int end_col) for (int row = start_row; row <= end_row; row++) { - // Last line is inverted (Black on white) - if (row == SCREEN_HEIGHT-1) { - tty_inverse(); + /* Move the cursor to the new position. If the starting col is not 0 or + * this is the first row we have to use absolute positioning, otherwise + * CR + LF can take us to col=0, row++ */ + if (start_col || row == start_row) { + tty_goto(row, start_col); + } else { + serial_echo_print("\r\n"); } // Copy Shadow buffer to TTY buffer + pos = 0; for (int col = start_col; col <= end_col; col++) { - p[col] = shadow_buffer[row][col].value & 0x7F; + + inverse = ((shadow_buffer[row][col].attr & 0x70) >> 4 != BLUE); + + if (cur_inverse != inverse) { + + if (pos) { + p[pos] = '\0'; + serial_echo_print(p); + pos = 0; + } + + if (inverse) { + tty_inverse(); + } else { + tty_normal(); + } + + cur_inverse = inverse; + } + + /* Make sure only VT100 characters are sent. */ + ch = shadow_buffer[row][col].ch; + + switch (ch) { + case 32 ... 127: + break; + + case 0xB3: + ch = '|'; + break; + + case 0xC1: + case 0xC2: + case 0xC4: + ch = '-'; + break; + + case 0xF8: + ch = '*'; + break; + + default: + ch = '?'; + } + + p[pos++] = ch; } - // Add string terminator - p[end_col+1] = '\0'; - - // For first line, title on top-left must be inverted - // Do the switch, send to TTY then continue to next line. - if (row == 0 && start_col == 0 && col_len > 28) { - tty_inverse(); - p[28] = '\0'; - tty_print(row,0,p); - tty_normal(); - p[28] = '|'; - tty_print(row, 28, p + 28); - continue; - } - - // Replace degree symbol with '*' for tty to avoid a C437/VT100 translation table. - if (row == 1 && (shadow_buffer[1][25].value & 0xFF) == 0xF8) { - p[25] = 0x2A; - } - - // Send row to TTY - tty_print(row, start_col, p + start_col); - - // Revert to normal if last line. - if (row == SCREEN_HEIGHT-1) { - tty_normal(); + if (pos) { + p[pos] = '\0'; + serial_echo_print(p); } } } From 6b998e82e77fe1334a3236afd45be25174806c72 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 19 Jun 2022 16:47:10 +0200 Subject: [PATCH 016/113] [TTY/Serial] Always use absolute positioning instead of relying on CR-LF --- system/serial.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/system/serial.c b/system/serial.c index cdb3684..a825318 100644 --- a/system/serial.c +++ b/system/serial.c @@ -151,14 +151,9 @@ void tty_send_region(int start_row, int start_col, int end_row, int end_col) for (int row = start_row; row <= end_row; row++) { - /* Move the cursor to the new position. If the starting col is not 0 or - * this is the first row we have to use absolute positioning, otherwise - * CR + LF can take us to col=0, row++ */ - if (start_col || row == start_row) { - tty_goto(row, start_col); - } else { - serial_echo_print("\r\n"); - } + // Always use absolute positioning instead of relying on CR-LF to avoid issues + // when a CR-LF is lost (especially with Industrial RS232/Ethernet converters). + tty_goto(row, start_col); // Copy Shadow buffer to TTY buffer pos = 0; From c2e94527e172caf45325093e5aa74e858e36dd57 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Wed, 13 Jul 2022 20:57:02 +0100 Subject: [PATCH 017/113] Fix handling of EFI memory map when located above 4GB (issue #115) The code which saves and restores the upper 32 bits of the address was not being included, due to a typo in the #ifdef expression. --- boot/efisetup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/efisetup.c b/boot/efisetup.c index 36bb283..5fc92df 100644 --- a/boot/efisetup.c +++ b/boot/efisetup.c @@ -559,7 +559,7 @@ static efi_status_t set_efi_info_and_exit_boot_services(efi_handle_t handle, boo boot_params->efi_info.mem_desc_version = mem_desc_version; boot_params->efi_info.mem_map = (uintptr_t)mem_map; boot_params->efi_info.mem_map_size = mem_map_size; -#ifdef __X86_64__ +#ifdef __x86_64__ boot_params->efi_info.sys_tab_hi = (uintptr_t)sys_table >> 32; boot_params->efi_info.mem_map_hi = (uintptr_t)mem_map >> 32; #endif @@ -571,7 +571,7 @@ fail: static void set_e820_map(boot_params_t *params) { uintptr_t mem_map_addr = params->efi_info.mem_map; -#ifdef __X86_64__ +#ifdef __x86_64__ mem_map_addr |= (uintptr_t)params->efi_info.mem_map_hi << 32; #endif size_t mem_map_size = params->efi_info.mem_map_size; From 89e2643de4114702848fedecbbe96c79dc8c7c83 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Sat, 16 Jul 2022 13:28:53 +0200 Subject: [PATCH 018/113] Add AP Enumeration to distinguish P-Core from E-Core on Hybrid CPUs (#62) Add AP Enumeration to distinguish E-Core from P-Core on Intel Hybrid CPUs, and exclude them from the selected cores by default. Including E-Cores slows down some tests and takes longer to catch memory errors. A new exclude_ecores flag has been added in config.c to include E-Cores if needed. --- app/config.c | 21 +++++++++++++++++---- app/config.h | 4 ++++ app/display.c | 28 +++++++++++++++++++++------- app/display.h | 8 +++++++- app/main.c | 25 +++++++++++++++++++++++++ system/cpuid.c | 18 ++++++++++++++++++ system/cpuid.h | 14 ++++++++++++++ 7 files changed, 106 insertions(+), 12 deletions(-) diff --git a/app/config.c b/app/config.c index edfe3ab..4e19822 100644 --- a/app/config.c +++ b/app/config.c @@ -1,11 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. // // Derived from memtest86+ config.c: // -// MemTest86+ V5.00 Specific code (GPL V2.0) -// By Samuel DEMEULEMEESTER, sdemeule@memtest.org -// http://www.x86-secret.com - http://www.memtest.org // ---------------------------------------------------- // config.c - MemTest-86 Version 3.4 // @@ -19,6 +17,7 @@ #include "bootparams.h" #include "cpuinfo.h" +#include "cpuid.h" #include "hwctrl.h" #include "keyboard.h" #include "memsize.h" @@ -87,6 +86,9 @@ error_mode_t error_mode = ERROR_MODE_NONE; cpu_state_t cpu_state[MAX_CPUS]; +core_type_t hybrid_core_type[MAX_CPUS]; +bool exclude_ecores = true; + bool smp_enabled = true; bool enable_temperature = true; @@ -699,7 +701,14 @@ static void cpu_selection_menu(void) prints(POP_R+5, POP_LI, " Add one CPU"); prints(POP_R+6, POP_LI, " Add CPU range"); prints(POP_R+7, POP_LI, " Add all CPUs"); - prints(POP_R+8, POP_LI, " Exit menu"); + if (cpuid_info.topology.is_hybrid) { + if (exclude_ecores) { + prints(POP_R+8, POP_LI, " Include E-Cores"); + } else { + prints(POP_R+8, POP_LI, " Exclude E-Cores"); + } + } + prints(POP_R+9, POP_LI, " Exit menu"); display_cpu_selection(display_offset); @@ -722,6 +731,10 @@ static void cpu_selection_menu(void) case '5': changed = set_all_cpus(true, display_offset); break; + case '6': + exclude_ecores = !exclude_ecores; + prints(POP_R+8, POP_LI+6, exclude_ecores ? "Exclude" : "Include"); + break; case 'u': if (display_offset >= SEL_W) { display_offset -= SEL_W; diff --git a/app/config.h b/app/config.h index 82c37af..0a9f429 100644 --- a/app/config.h +++ b/app/config.h @@ -14,6 +14,7 @@ #include #include "smp.h" +#include "cpuid.h" typedef enum { PAR, @@ -45,6 +46,9 @@ extern error_mode_t error_mode; extern cpu_state_t cpu_state[MAX_CPUS]; +extern core_type_t hybrid_core_type[MAX_CPUS]; +extern bool exclude_ecores; + extern bool smp_enabled; extern bool enable_temperature; diff --git a/app/display.c b/app/display.c index 88d8d0a..71ac182 100644 --- a/app/display.c +++ b/app/display.c @@ -179,8 +179,13 @@ void display_cpu_topology(void) extern int num_enabled_cpus; int num_cpu_sockets = 1; + // Display Thread Count and Thread Dispatch Mode if (smp_enabled) { - display_threading(num_enabled_cpus, cpu_mode_str[cpu_mode]); + if (cpuid_info.topology.is_hybrid && cpuid_info.topology.ecore_count > 0 && exclude_ecores) { + display_threading(num_enabled_cpus - cpuid_info.topology.ecore_count, cpu_mode_str[cpu_mode]); + } else { + display_threading(num_enabled_cpus, cpu_mode_str[cpu_mode]); + } } else { display_threading_disabled(); } @@ -198,16 +203,25 @@ void display_cpu_topology(void) // 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_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 + // Display P/E-Core count for Hybrid CPUs. if (cpuid_info.topology.is_hybrid) { - display_cpu_topo_hybrid(cpuid_info.topology.thread_count); + if (cpuid_info.topology.pcore_count > 1) { + + if (cpuid_info.flags.htt && + (cpuid_info.topology.thread_count - cpuid_info.topology.ecore_count) == cpuid_info.topology.pcore_count) { + cpuid_info.topology.pcore_count /= 2; + } + + display_cpu_topo_hybrid(cpuid_info.topology.pcore_count, + cpuid_info.topology.ecore_count, + cpuid_info.topology.thread_count); + } else { + display_cpu_topo_hybrid_short(cpuid_info.topology.thread_count); + } return; } diff --git a/app/display.h b/app/display.h index 2414f2d..16c5b7b 100644 --- a/app/display.h +++ b/app/display.h @@ -81,7 +81,13 @@ typedef enum { #define display_threading_disabled() \ prints(7,31, "Disabled") -#define display_cpu_topo_hybrid(num_threads) \ +#define display_cpu_topo_hybrid(num_pcores, num_ecores, num_threads) \ + { \ + clear_screen_region(7, 5, 7, 25); \ + printf(7, 5, "%uP+%uE-Cores (%uT)", num_pcores, num_ecores, num_threads); \ + } + +#define display_cpu_topo_hybrid_short(num_threads) \ printf(7, 5, "%u Threads (Hybrid)", num_threads) #define display_cpu_topo_multi_socket(num_sockets, num_cores, num_threads) \ diff --git a/app/main.c b/app/main.c index 16f7a3c..bcf2bcf 100644 --- a/app/main.c +++ b/app/main.c @@ -304,6 +304,30 @@ static void global_init(void) restart = false; } +static void ap_enumerate(int my_cpu) +{ + if (!cpuid_info.topology.is_hybrid) { + return; + } + + hybrid_core_type[my_cpu] = get_ap_hybrid_type(); + + if (hybrid_core_type[my_cpu] == CORE_PCORE) { + cpuid_info.topology.pcore_count++; + } else if (hybrid_core_type[my_cpu] == CORE_ECORE) { + cpuid_info.topology.ecore_count++; + } + + if (hybrid_core_type[my_cpu] == CORE_ECORE && exclude_ecores) { + cpu_state[my_cpu] = CPU_STATE_DISABLED; + //TODO : hlt AP? + } + + if (my_cpu == num_enabled_cpus - 1) { + display_cpu_topology(); + } +} + static void setup_vm_map(uintptr_t win_start, uintptr_t win_end) { vm_map_size = 0; @@ -503,6 +527,7 @@ void main(void) } else { trace(my_cpu, "AP started"); cpu_state[my_cpu] = CPU_STATE_RUNNING; + ap_enumerate(my_cpu); while (init_state < 2) { usleep(100); } diff --git a/system/cpuid.c b/system/cpuid.c index 1792307..0466993 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -187,6 +187,8 @@ void cpuid_init(void) cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]); if (reg[3] & (1 << 15)) { cpuid_info.topology.is_hybrid = 1; + cpuid_info.topology.pcore_count = 1; // We have at least 1 P-Core as BSP + cpuid_info.topology.ecore_count = 0; } for (int i=0; i < 4; i++) { @@ -226,3 +228,19 @@ void cpuid_init(void) break; } } + +core_type_t get_ap_hybrid_type(void) +{ + uint32_t eax, ebx, ecx, edx; + + cpuid(0x1A, 0, &eax, &ebx, &ecx, &edx); + + switch ((eax >> 24) & 0xFF) { + case CPU_PCORE_ID: + return CORE_PCORE; + case CPU_ECORE_ID: + return CORE_ECORE; + default: + return CORE_UNKNOWN; + } +} diff --git a/system/cpuid.h b/system/cpuid.h index 57e9733..a16c1ae 100644 --- a/system/cpuid.h +++ b/system/cpuid.h @@ -15,6 +15,15 @@ #include +#define CPU_ECORE_ID 0x20 +#define CPU_PCORE_ID 0x40 + +typedef enum { + CORE_UNKNOWN, + CORE_PCORE, + CORE_ECORE +} core_type_t; + /** * Structures that hold the collected CPUID information. */ @@ -194,6 +203,11 @@ extern cpuid_info_t cpuid_info; */ void cpuid_init(void); +/** + * Return the Core Type (for Hybrid CPUs) + */ +core_type_t get_ap_hybrid_type(void); + /** * Executes the cpuid instruction. */ From e6e0f0c8e756e87c452a36f51c1f68c0af63deed Mon Sep 17 00:00:00 2001 From: martinwhitaker Date: Sat, 16 Jul 2022 12:34:08 +0100 Subject: [PATCH 019/113] USB improvements (#116) * Add new heap manager. * Convert OHCI driver to use new heap manager. * Convert UHCI driver to use new heap manager. * Convert EHCI driver to use new heap manager. * Convert XHCI driver to use new heap manager. * Convert SMP to use new heap manager. * Add a "usbinit" boot option to handle various buggy USB devices. This replaces the "keyboard=buggy-usb" option, and adds a second workaround to handle the problem seen in issue #107. --- README.md | 16 ++++-- app/config.c | 11 +++- app/main.c | 3 + build32/Makefile | 1 + build64/Makefile | 1 + system/ehci.c | 45 +++++++-------- system/heap.c | 128 +++++++++++++++++++++++++++++++++++++++++++ system/heap.h | 86 +++++++++++++++++++++++++++++ system/ohci.c | 29 +++++----- system/smp.c | 6 +- system/uhci.c | 46 +++++++--------- system/usbhcd.c | 4 +- system/usbhcd.h | 3 +- system/xhci.c | 140 +++++++++++++++++++---------------------------- 14 files changed, 355 insertions(+), 164 deletions(-) create mode 100644 system/heap.c create mode 100644 system/heap.h diff --git a/README.md b/README.md index 369438d..9d05dcf 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,13 @@ recognised: * where *type* is one of * legacy * usb - * buggy-usb + * usbdebug + * pauses after probing for USB keyboards + * usbinit=*mode* + * where *mode* is one of + * 1 = use the two-step init sequence for high speed devices + * 2 = add a second USB reset in the init sequence + * 3 = the combination of modes 1 and 2 * console=ttyS*x*,*y* * activate serial/tty console output, where *x* is one of the following IO port * 0 = 0x3F8 @@ -152,9 +158,7 @@ recognised: Memtest86+ supports both the legacy keyboard interface (using I/O ports 0x60 and 0x64) and USB keyboards (using its own USB device drivers). One or the other can be selected via the boot command line, If neither is selected, the -default is to use both. An additional option on the boot command line is -`buggy-usb` which enables the longer initialisation sequence required by some -older USB devices. +default is to use both. Older BIOSs usually support USB legacy keyboard emulation, which makes USB keyboards act like legacy keyboards connected to ports 0x60 and 0x64. This @@ -170,6 +174,10 @@ emulation and add `keyboard=legacy` on the boot command line. you enable the Compatibility System Module (CSM) in the BIOS setup. Others only support it when actually booting in legacy mode. +Many USB devices don't fully conform to the USB specification. If the USB +keyboard probe hangs or fails to detect your keyboard, try the various +workarounds provided by the "usbinit" boot option. + **NOTE**: Memtest86+'s USB device drivers are work in progress. Not all USB devices are supported yet, and there may be problems on some hardware. diff --git a/app/config.c b/app/config.c index 4e19822..be2a12e 100644 --- a/app/config.c +++ b/app/config.c @@ -177,9 +177,6 @@ static void parse_option(const char *option, const char *params) keyboard_types = KT_LEGACY; } else if (strncmp(params, "usb", 4) == 0) { keyboard_types = KT_USB; - } else if (strncmp(params, "buggy-usb", 10) == 0) { - keyboard_types = KT_USB; - usb_init_options |= USB_EXTRA_RESET; } } else if (strncmp(option, "powersave", 10) == 0) { if (strncmp(params, "off", 4) == 0) { @@ -203,6 +200,14 @@ static void parse_option(const char *option, const char *params) enable_trace = true; } else if (strncmp(option, "usbdebug", 9) == 0) { usb_init_options |= USB_DEBUG; + } else if (strncmp(option, "usbinit", 8) == 0) { + if (strncmp(params, "1", 2) == 0) { + usb_init_options |= USB_2_STEP_INIT; + } else if (strncmp(params, "2", 2) == 0) { + usb_init_options |= USB_EXTRA_RESET; + } else if (strncmp(params, "3", 2) == 0) { + usb_init_options |= USB_2_STEP_INIT|USB_EXTRA_RESET; + } } else if (strncmp(option, "nosm", 5) == 0) { enable_sm = false; } diff --git a/app/main.c b/app/main.c index bcf2bcf..ab4e8db 100644 --- a/app/main.c +++ b/app/main.c @@ -22,6 +22,7 @@ #include "cache.h" #include "cpuid.h" #include "cpuinfo.h" +#include "heap.h" #include "hwctrl.h" #include "hwquirks.h" #include "io.h" @@ -216,6 +217,8 @@ static void global_init(void) pmem_init(); + heap_init(); + pci_init(); quirks_init(); diff --git a/build32/Makefile b/build32/Makefile index 1e03597..51cd440 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -20,6 +20,7 @@ SYS_OBJS = system/acpi.o \ system/cpulocal.o \ system/ehci.o \ system/font.o \ + system/heap.o \ system/hwctrl.o \ system/hwquirks.o \ system/keyboard.o \ diff --git a/build64/Makefile b/build64/Makefile index 99c5213..67d3a3f 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -21,6 +21,7 @@ SYS_OBJS = system/acpi.o \ system/ehci.o \ system/font.o \ system/hwctrl.o \ + system/heap.o \ system/hwquirks.o \ system/keyboard.o \ system/ohci.o \ diff --git a/system/ehci.c b/system/ehci.c index 9b62452..1653d65 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -5,10 +5,10 @@ #include #include +#include "heap.h" #include "memrw32.h" #include "memsize.h" #include "pci.h" -#include "pmem.h" #include "usb.h" #include "string.h" @@ -226,11 +226,6 @@ typedef struct { // Private Functions //------------------------------------------------------------------------------ -static size_t num_pages(size_t size) -{ - return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; -} - static int usb_to_ehci_speed(usb_speed_t usb_speed) { switch (usb_speed) { @@ -519,20 +514,26 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) if (!halt_host_controller(op_regs)) return false; if (!reset_host_controller(op_regs)) return false; + // Record the heap state to allow us to free memory. + uintptr_t initial_heap_mark = lm_heap_mark(); + // Allocate and initialise a periodic frame list. This needs to be aligned on a 4K page boundary. Some controllers // don't support a programmable list length, so we just use the default length. - pm_map[0].end -= num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t)); - uintptr_t pfl_addr = pm_map[0].end << PAGE_SHIFT; + uintptr_t pfl_addr = lm_heap_alloc(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE); + if (pfl_addr == 0) { + goto no_keyboards_found; + } uint32_t *pfl = (uint32_t *)pfl_addr; + for (int i = 0; i < EHCI_MAX_PFL_LENGTH; i++) { pfl[i] = EHCI_LP_TERMINATE; } - // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory, - // so allocate it in the first segment. - // TODO: check for segment overflow. - pm_map[0].end -= num_pages(sizeof(workspace_t)); - uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT; + // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. + uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + if (workspace_addr == 0) { + goto no_keyboards_found; + } workspace_t *ws = (workspace_t *)workspace_addr; memset(ws, 0, sizeof(workspace_t)); @@ -549,9 +550,7 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) write32(&op_regs->periodic_list_base, pfl_addr); write32(&op_regs->async_list_addr, (uintptr_t)(ws->qhd)); if (!start_host_controller(op_regs)) { - pm_map[0].end += num_pages(sizeof(workspace_t)); - pm_map[0].end += num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t)); - return false; + goto no_keyboards_found; } flush32(&op_regs->config_flag, 1); @@ -647,17 +646,9 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) } if (num_keyboards == 0) { - // Halt the host controller. (void)halt_host_controller(op_regs); (void)reset_host_controller(op_regs); - - // Deallocate the workspace for this controller. - pm_map[0].end += num_pages(sizeof(workspace_t)); - - // Deallocate the periodic frame list. - pm_map[0].end += num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t)); - - return false; + goto no_keyboards_found; } ws->num_keyboards = num_keyboards; @@ -691,4 +682,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) enable_periodic_schedule(op_regs); return true; + +no_keyboards_found: + lm_heap_rewind(initial_heap_mark); + return false; } diff --git a/system/heap.c b/system/heap.c new file mode 100644 index 0000000..fff3a44 --- /dev/null +++ b/system/heap.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2022 Martin Whitaker. + +#include + +#include "boot.h" + +#include "memsize.h" +#include "pmem.h" + +#include "heap.h" + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +typedef struct { + int segment; + uintptr_t start; + uintptr_t end; +} heap_t; + +//------------------------------------------------------------------------------ +// Private Variables +//------------------------------------------------------------------------------ + +static heap_t lm_heap = { .segment = -1, .start = 0, .end = 0 }; +static heap_t hm_heap = { .segment = -1, .start = 0, .end = 0 }; + +//------------------------------------------------------------------------------ +// Private Functions +//------------------------------------------------------------------------------ + +static size_t num_pages(size_t size) +{ + return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + +static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment) +{ + if (heap->segment < 0) { + return 0; + } + uintptr_t addr = pm_map[heap->segment].end - num_pages(size); + addr &= ~((alignment - 1) >> PAGE_SHIFT); + if (addr < heap->start) { + return 0; + } + pm_map[heap->segment].end = addr; + return addr << PAGE_SHIFT; +} + +static uintptr_t heap_mark(const heap_t *heap) +{ + if (heap->segment < 0) { + return 0; + } + return pm_map[heap->segment].end; +} + +static void heap_rewind(const heap_t *heap, uintptr_t mark) +{ + if (heap->segment >= 0 && mark > pm_map[heap->segment].end && mark <= heap->end) { + pm_map[heap->segment].end = mark; + } +} +//------------------------------------------------------------------------------ +// Public Functions +//------------------------------------------------------------------------------ + +void heap_init(void) +{ + // Use the largest 20-bit addressable physical memory segment for the low-memory heap. + // Use the largest 32-bit addressable physical memory segment for the high-memory heap. + // Exclude memory occupied by the program or below it in that segment. + uintptr_t program_start = (uintptr_t)_start >> PAGE_SHIFT; + uintptr_t program_end = program_start + num_pages(_end - _start); + uintptr_t max_segment_size = 0; + for (int i = 0; i < pm_map_size && pm_map[i].end <= PAGE_C(4,GB); i++) { + uintptr_t try_heap_start = pm_map[i].start; + uintptr_t try_heap_end = pm_map[i].end; + if (program_start >= try_heap_start && program_end <= try_heap_end) { + try_heap_start = program_end; + } + uintptr_t segment_size = try_heap_end - try_heap_start; + if (segment_size >= max_segment_size) { + max_segment_size = segment_size; + if (try_heap_end <= PAGE_C(1,MB)) { + lm_heap.segment = i; + lm_heap.start = try_heap_start; + lm_heap.end = try_heap_end; + } + hm_heap.segment = i; + hm_heap.start = try_heap_start; + hm_heap.end = try_heap_end; + } + } +} + +uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment) +{ + return heap_alloc(&lm_heap, size, alignment); +} + +uintptr_t lm_heap_mark(void) +{ + return heap_mark(&lm_heap); +} + +void lm_heap_rewind(uintptr_t mark) +{ + heap_rewind(&lm_heap, mark); +} + +uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment) +{ + return heap_alloc(&hm_heap, size, alignment); +} + +uintptr_t hm_heap_mark(void) +{ + return heap_mark(&hm_heap); +} + +void hm_heap_rewind(uintptr_t mark) +{ + heap_rewind(&hm_heap, mark); +} diff --git a/system/heap.h b/system/heap.h new file mode 100644 index 0000000..142e268 --- /dev/null +++ b/system/heap.h @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef HEAP_H +#define HEAP_H +/** + * \file + * + * Provides functions to allocate and free chunks of physical memory that will + * be excluded from the memory tests. Two separate heaps are supported, one in + * low (20-bit addressable) memory, the other in high (32-bit addressable) + * memory. + * + *//* + * Copyright (C) 2022 Martin Whitaker. + */ + +#include +#include + +/** + * Initialises the heaps. + */ +void heap_init(void); + +/** + * Allocates a chunk of physical memory below 1MB. The allocated region will + * be at least the requested size with the requested alignment. This memory + * is always mapped to the identical address in virtual memory. + * + * \param size - the requested size in bytes. + * \param alignment - the requested byte alignment (must be a power of 2). + * + * \returns + * On success, the allocated address in physical memory. On failure, 0. + */ +uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment); + +/** + * Returns a value indicating the current allocation state of the low-memory + * heap. This value may be passed to lm_heap_rewind() to free any low memory + * allocated after this call. + * + * \returns + * An opaque value indicating the current allocation state. + */ +uintptr_t lm_heap_mark(void); + +/** + * Frees any low memory allocated since the specified mark was obtained from + * a call to lm_heap_mark(). + * + * \param mark - the mark that indicates how much memory to free. + */ +void lm_heap_rewind(uintptr_t mark); + +/** + * Allocates a chunk of physical memory below 4GB. The allocated region will + * be at least the requested size with the requested alignment. The caller is + * responsible for mapping it into virtual memory if required. + * + * \param size - the requested size in bytes. + * \param alignment - the requested byte alignment (must be a power of 2). + * + * \returns + * On success, the allocated address in physical memory. On failure, 0. + */ +uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment); + +/** + * Returns a value indicating the current allocation state of the high-memory + * heap. This value may be passed to hm_heap_rewind() to free any high memory + * allocated after this call. + * + * \returns + * An opaque value indicating the current allocation state. + */ +uintptr_t hm_heap_mark(void); + +/** + * Frees any high memory allocated since the specified mark was obtained from + * a call to hm_heap_mark(). + * + * \param mark - the mark that indicates how much memory to free. + */ +void hm_heap_rewind(uintptr_t mark); + +#endif // HEAP_H diff --git a/system/ohci.c b/system/ohci.c index 88104cd..17d221f 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -5,9 +5,9 @@ #include #include +#include "heap.h" #include "memrw32.h" #include "memsize.h" -#include "pmem.h" #include "usb.h" #include "string.h" @@ -243,11 +243,6 @@ typedef struct { // Private Functions //------------------------------------------------------------------------------ -static size_t num_pages(size_t size) -{ - return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; -} - static bool reset_ohci_port(ohci_op_regs_t *op_regs, int port_idx) { // The OHCI reset lasts for 10ms, but the USB specification calls for 50ms (but not necessarily continuously). @@ -461,11 +456,14 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) return false; } - // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory, - // so allocate it in the first segment. - // TODO: check for segment overflow. - pm_map[0].end -= num_pages(sizeof(workspace_t)); - uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT; + // Record the heap state to allow us to free memory. + uintptr_t initial_heap_mark = lm_heap_mark(); + + // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. + uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + if (workspace_addr == 0) { + goto no_keyboards_found; + } workspace_t *ws = (workspace_t *)workspace_addr; memset(ws, 0, sizeof(workspace_t)); @@ -574,10 +572,7 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) // Delay to allow the controller to reset. usleep(10); - // Deallocate the workspace for this controller. - pm_map[0].end += num_pages(sizeof(workspace_t)); - - return false; + goto no_keyboards_found; } @@ -611,4 +606,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) flush32(&op_regs->interrupt_status, ~0); return true; + +no_keyboards_found: + lm_heap_rewind(initial_heap_mark); + return false; } diff --git a/system/smp.c b/system/smp.c index ff08df4..bc6215e 100644 --- a/system/smp.c +++ b/system/smp.c @@ -20,10 +20,10 @@ #include "efi.h" #include "cpuid.h" +#include "heap.h" #include "memrw32.h" #include "memsize.h" #include "msr.h" -#include "pmem.h" #include "string.h" #include "unistd.h" #include "vmem.h" @@ -548,9 +548,9 @@ void smp_init(bool smp_enable) apic_id_to_cpu_num[cpu_num_to_apic_id[i]] = i; } - // Reserve last page of first segment for AP trampoline and sync objects. + // Allocate a page of low memory for AP trampoline and sync objects. // These need to remain pinned in place during relocation. - smp_heap_page = --pm_map[0].end; + smp_heap_page = lm_heap_alloc(PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT; ap_startup_addr = (uintptr_t)startup; diff --git a/system/uhci.c b/system/uhci.c index 924b0d0..1cb0615 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -5,11 +5,11 @@ #include #include +#include "heap.h" #include "io.h" #include "memrw32.h" #include "memsize.h" #include "pci.h" -#include "pmem.h" #include "usb.h" #include "string.h" @@ -195,11 +195,6 @@ typedef struct { // Private Functions //------------------------------------------------------------------------------ -static size_t num_pages(size_t size) -{ - return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; -} - static bool io_wait_until_clr(uint16_t io_reg, uint16_t bit_mask, int max_time) { int timer = max_time >> 3; @@ -434,16 +429,21 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) if (!halt_host_controller(io_base)) return false; if (!reset_host_controller(io_base)) return false; - // Allocate and initialise the frame list. This needs to be aligned on a 4K page boundary. - pm_map[0].end -= num_pages(UHCI_FL_LENGTH * sizeof(uint32_t)); - uintptr_t fl_addr = pm_map[0].end << PAGE_SHIFT; + // Record the heap state to allow us to free memory. + uintptr_t initial_heap_mark = lm_heap_mark(); + + // Allocate the frame list. This needs to be aligned on a 4K page boundary. + uintptr_t fl_addr = lm_heap_alloc(UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE); + if (fl_addr == 0) { + goto no_keyboards_found; + } uint32_t *fl = (uint32_t *)fl_addr; - // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory, - // so allocate it in the first segment. - // TODO: check for segment overflow. - pm_map[0].end -= num_pages(sizeof(workspace_t)); - uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT; + // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. + uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + if (workspace_addr == 0) { + goto no_keyboards_found; + } workspace_t *ws = (workspace_t *)workspace_addr; memset(ws, 0, sizeof(workspace_t)); @@ -469,9 +469,7 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) outl(fl_addr, UHCI_FLBASE); outb(UHCI_SOF_DEFAULT, UHCI_SOF); if (!start_host_controller(io_base)) { - pm_map[0].end += num_pages(sizeof(workspace_t)); - pm_map[0].end += num_pages(UHCI_FL_LENGTH * sizeof(uint32_t)); - return false; + goto no_keyboards_found; } // Construct a hub descriptor for the root hub. @@ -535,16 +533,8 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) num_keyboards, num_keyboards != 1 ? "s" : ""); if (num_keyboards == 0) { - // Halt the host controller. (void)halt_host_controller(io_base); - - // Deallocate the workspace for this controller. - pm_map[0].end += num_pages(sizeof(workspace_t)); - - // Deallocate the periodic frame list. - pm_map[0].end += num_pages(UHCI_FL_LENGTH * sizeof(uint32_t)); - - return false; + goto no_keyboards_found; } ws->num_keyboards = num_keyboards; @@ -582,4 +572,8 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) } return true; + +no_keyboards_found: + lm_heap_rewind(initial_heap_mark); + return false; } diff --git a/system/usbhcd.c b/system/usbhcd.c index cb50b1b..456ab43 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -543,12 +543,12 @@ bool assign_usb_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num ep0->max_packet_size = default_max_packet_size(device_speed); ep0->interval = 0; - // The device should currently be in Default state. For loww and full speed devices, We first fetch the first + // The device should currently be in Default state. For low and full speed devices, we first fetch the first // 8 bytes of the device descriptor to discover the maximum packet size for the control endpoint. We then set // the device address, which moves the device into Address state, and fetch the full device descriptor. size_t fetch_length = sizeof(usb_device_desc_t); - if (device_speed < USB_SPEED_HIGH) { + if (device_speed < USB_SPEED_HIGH || usb_init_options & USB_2_STEP_INIT) { fetch_length = 8; goto fetch_descriptor; } diff --git a/system/usbhcd.h b/system/usbhcd.h index 3d1fc29..df81288 100644 --- a/system/usbhcd.h +++ b/system/usbhcd.h @@ -121,7 +121,8 @@ typedef enum { USB_DEFAULT_INIT = 0, USB_EXTRA_RESET = 1 << 0, USB_IGNORE_EHCI = 1 << 1, - USB_DEBUG = 1 << 2 + USB_2_STEP_INIT = 1 << 2, + USB_DEBUG = 1 << 3 } usb_init_options_t; /** diff --git a/system/xhci.c b/system/xhci.c index 3acf9d5..aebc20f 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -4,9 +4,9 @@ #include #include +#include "heap.h" #include "memrw32.h" #include "memsize.h" -#include "pmem.h" #include "usb.h" #include "vmem.h" @@ -329,9 +329,11 @@ typedef struct { uint32_t cr_enqueue_state; uint32_t er_dequeue_state; - // Transient values used during device enumeration and configuration. + // Input context for controller commands. uintptr_t input_context_addr; - uintptr_t output_context_addr; + + // Transient values used during device enumeration and configuration. + uintptr_t initial_heap_mark; uintptr_t control_ep_tr_addr; uintptr_t interrupt_ep_tr_addr; @@ -342,26 +344,10 @@ typedef struct { uint8_t kbd_ep_id [MAX_KEYBOARDS]; } workspace_t __attribute__ ((aligned (64))); -//------------------------------------------------------------------------------ -// Private Variables -//------------------------------------------------------------------------------ - -// The heap segment of the physical memory map is used when allocating memory -// to the controller that we don't need to access during normal operation. -// Any memory we do need to access during normal operation is allocated from -// segment 0, which is permanently mapped into the virtual memory address space. - -static int heap_segment = -1; - //------------------------------------------------------------------------------ // Private Functions //------------------------------------------------------------------------------ -static size_t num_pages(size_t size) -{ - return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; -} - static size_t round_up(size_t size, size_t alignment) { return (size + alignment - 1) & ~(alignment - 1); @@ -658,37 +644,36 @@ static int allocate_slot(const usb_hcd_t *hcd) xhci_trb_t event; - // Allocate and initialise a private workspace for this device. - // TODO: check for heap overflow. + // Record the heap state to allow us to free memory. + ws->initial_heap_mark = lm_heap_mark(); - pm_map[0].end -= num_pages(DEVICE_WS_SIZE); - uintptr_t device_workspace_addr = pm_map[0].end << PAGE_SHIFT; - ws->output_context_addr = device_workspace_addr; - ws->control_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE; - ws->interrupt_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE + sizeof(ep_tr_t); + // Allocate and initialise a private workspace for this device. + uintptr_t device_workspace_addr = lm_heap_alloc(DEVICE_WS_SIZE, PAGE_SIZE); + if (device_workspace_addr == 0) { + goto free_memory; + } memset((void *)device_workspace_addr, 0, DEVICE_WS_SIZE); - // Temporarily allocate and initialise the input context data structure on the heap. - // As we only use this temporarily, there's no need to adjust pm_map. - - ws->input_context_addr = device_workspace_addr - XHCI_MAX_IP_CONTEXT_SIZE; - - memset((void *)ws->input_context_addr, 0, XHCI_MAX_IP_CONTEXT_SIZE); + ws->control_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE; + ws->interrupt_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE + sizeof(ep_tr_t); // Allocate a device slot and set up its output context. enqueue_xhci_command(ws, XHCI_TRB_ENABLE_SLOT | XHCI_TRB_USB2_SLOT, 0, 0); ring_host_controller_doorbell(ws->db_regs); if (wait_for_xhci_event(ws, XHCI_TRB_COMMAND_COMPLETE, 100*MILLISEC, &event) != XHCI_EVENT_CC_SUCCESS) { - pm_map[0].end += num_pages(DEVICE_WS_SIZE); - return 0; + goto free_memory; } int slot_id = event_slot_id(&event); - write64(&ws->device_context_index[slot_id], ws->output_context_addr); + write64(&ws->device_context_index[slot_id], device_workspace_addr); return slot_id; + +free_memory: + lm_heap_rewind(ws->initial_heap_mark); + return 0; } static bool release_slot(const usb_hcd_t *hcd, int slot_id) @@ -705,7 +690,7 @@ static bool release_slot(const usb_hcd_t *hcd, int slot_id) write64(&ws->device_context_index[slot_id], 0); - pm_map[0].end += num_pages(DEVICE_WS_SIZE); + lm_heap_rewind(ws->initial_heap_mark); return true; } @@ -903,20 +888,6 @@ static void poll_keyboards(const usb_hcd_t *hcd) } } -static bool set_heap_segment(void) -{ - // Use the largest 32-bit addressable physical memory segment for the heap. - uintptr_t max_segment_size = 0; - for (int i = 0; i < pm_map_size && pm_map[i].end <= PAGE_C(4,GB); i++) { - uintptr_t segment_size = pm_map[i].end - pm_map[i].start; - if (segment_size >= max_segment_size) { - max_segment_size = segment_size; - heap_segment = i; - } - } - return max_segment_size > 0; -} - //------------------------------------------------------------------------------ // Driver Method Table //------------------------------------------------------------------------------ @@ -939,11 +910,6 @@ static const hcd_methods_t methods = { bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) { - if (heap_segment < 0) { - if (!set_heap_segment()) return false; - } - uintptr_t heap_segment_end = pm_map[heap_segment].end; - uint8_t port_type[XHCI_MAX_PORTS]; memset(port_type, 0, sizeof(port_type)); @@ -1018,12 +984,14 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) // Ensure the controller is halted and then reset it. if (!halt_host_controller(op_regs)) return false; - if (!reset_host_controller(op_regs)) return false; + // Record the heap states to allow us to free memory. + uintptr_t initial_lm_heap_mark = lm_heap_mark(); + uintptr_t initial_hm_heap_mark = hm_heap_mark(); + // Record the controller page size. uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12; - uintptr_t xhci_page_mask = xhci_page_size - 1; // Find the maximum number of device slots the controller supports. int max_slots = cap_regs->hcs_params1 & 0xff; @@ -1033,31 +1001,30 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) | ((cap_regs->hcs_params2 >> 27) & 0x1f); // Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size. - // TODO: check for heap overflow. uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size; - pm_map[heap_segment].end -= num_pages(scratchpad_size); - pm_map[heap_segment].end &= ~(xhci_page_mask >> PAGE_SHIFT); - uintptr_t scratchpad_paddr = pm_map[heap_segment].end << PAGE_SHIFT; + uintptr_t scratchpad_paddr = hm_heap_alloc(scratchpad_size, xhci_page_size); + if (scratchpad_paddr == 0) { + goto no_keyboards_found; + } uintptr_t scratchpad_vaddr = map_region(scratchpad_paddr, scratchpad_size, true); if (scratchpad_vaddr == 0) { - pm_map[heap_segment].end = heap_segment_end; - return false; + goto no_keyboards_found; } memset((void *)scratchpad_vaddr, 0, scratchpad_size); // Allocate and initialise the device context base address and scratchpad buffer arrays on the heap. // Both need to be aligned on a 64 byte boundary. - // TODO: check for heap overflow. uintptr_t device_context_index_size = (1 + max_slots) * sizeof(uint64_t); uintptr_t scratchpad_buffer_index_offs = round_up(device_context_index_size, 64); uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t); - pm_map[heap_segment].end -= num_pages(scratchpad_buffer_index_offs + scratchpad_buffer_index_size); - uintptr_t device_context_index_paddr = pm_map[heap_segment].end << PAGE_SHIFT; + uintptr_t device_context_index_paddr = hm_heap_alloc(scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64); + if (device_context_index_paddr == 0) { + goto no_keyboards_found; + } uintptr_t device_context_index_vaddr = map_region(device_context_index_paddr, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, true); if (device_context_index_vaddr == 0) { - pm_map[heap_segment].end = heap_segment_end; - return false; + goto no_keyboards_found; } memset((void *)device_context_index_vaddr, 0, device_context_index_size); @@ -1073,11 +1040,11 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) } } - // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory, - // so allocate it in the first segment. - // TODO: check for segment overflow. - pm_map[0].end -= num_pages(sizeof(workspace_t)); - uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT; + // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. + uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + if (workspace_addr == 0) { + goto no_keyboards_found; + } workspace_t *ws = (workspace_t *)workspace_addr; memset(ws, 0, sizeof(workspace_t)); @@ -1093,6 +1060,14 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) ws->cr_enqueue_state = WS_CR_SIZE; // cycle = 1, index = 0 ws->er_dequeue_state = WS_ER_SIZE; // cycle = 1, index = 0 + // Allocate and initialise the input context data structure. This needs to be contained within a single page. + ws->input_context_addr = lm_heap_alloc(XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE); + if (ws->input_context_addr == 0) { + goto no_keyboards_found; + } + + memset((void *)ws->input_context_addr, 0, XHCI_MAX_IP_CONTEXT_SIZE); + // Initialise the driver object for this controller. hcd->methods = &methods; hcd->ws = &ws->base_ws; @@ -1110,9 +1085,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) write64(&op_regs->dcbaap, device_context_index_paddr); write32(&op_regs->config, (read32(&op_regs->config) & 0xfffffc00) | max_slots); if (!start_host_controller(op_regs)) { - pm_map[0].end += num_pages(sizeof(workspace_t)); - pm_map[heap_segment].end = heap_segment_end; - return false; + goto no_keyboards_found; } // Construct a hub descriptor for the root hub. @@ -1177,16 +1150,8 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) num_keyboards, num_keyboards != 1 ? "s" : ""); if (num_keyboards == 0) { - // Halt the host controller. (void)halt_host_controller(op_regs); - - // Free the pages we allocated in segment 0. - pm_map[0].end += num_pages(sizeof(workspace_t)); - - // Free the pages we allocated in the heap segment. - pm_map[heap_segment].end = heap_segment_end; - - return false; + goto no_keyboards_found; } // Initialise the interrupt TRB ring for each keyboard interface. @@ -1200,4 +1165,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) } return true; + +no_keyboards_found: + lm_heap_rewind(initial_lm_heap_mark); + hm_heap_rewind(initial_hm_heap_mark); + return false; } From 034372f4bfd01d37f0749108564ca09ca58a51fe Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Sun, 17 Jul 2022 20:20:52 +0200 Subject: [PATCH 020/113] Add much bigger PASS/FAIL banner (#113) The goal is to see the actual test result (PASS or FAIL) far away. --- app/display.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- app/display.h | 8 +++++-- app/error.c | 4 ++++ app/main.c | 7 +++--- 4 files changed, 78 insertions(+), 6 deletions(-) diff --git a/app/display.c b/app/display.c index 71ac182..5b27186 100644 --- a/app/display.c +++ b/app/display.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. +// Copyright (C) 2004-2022 Sam Demeulemeester. #include #include @@ -31,6 +32,17 @@ // Constants //------------------------------------------------------------------------------ +#define POP_STAT_R 12 +#define POP_STAT_C 18 + +#define POP_STAT_W 44 +#define POP_STAT_H 9 + +#define POP_STAT_LAST_R (POP_STAT_R + POP_STAT_H - 1) +#define POP_STAT_LAST_C (POP_STAT_C + POP_STAT_W - 1) + +#define POP_STATUS_REGION POP_STAT_R, POP_STAT_C, POP_STAT_LAST_R, POP_STAT_LAST_C + #define SPINNER_PERIOD 100 // milliseconds #define NUM_SPIN_STATES 4 @@ -60,6 +72,9 @@ static uint64_t next_spin_time = 0; // TSC time stamp static int prev_sec = -1; // previous second static bool timed_update_done = false; // update cycle status +bool big_status_displayed = false; +static uint16_t popup_status_save_buffer[POP_STAT_W * POP_STAT_H]; + //------------------------------------------------------------------------------ // Variables //------------------------------------------------------------------------------ @@ -339,9 +354,57 @@ void display_temperature(void) printf(1, 20-offset, "%2i/%2i%cC", actual_cpu_temp, max_cpu_temp, 0xF8); } +void display_big_status(bool pass) +{ + if (big_status_displayed) { + return; + } + + save_screen_region(POP_STATUS_REGION, popup_status_save_buffer); + + set_background_colour(BLACK); + set_foreground_colour(pass ? GREEN : RED); + clear_screen_region(POP_STATUS_REGION); + + if (pass) { + prints(POP_STAT_R+1, POP_STAT_C+5, "###### ## ##### ##### "); + prints(POP_STAT_R+2, POP_STAT_C+5, "## ## #### ## ## ## ## "); + prints(POP_STAT_R+3, POP_STAT_C+5, "## ## ## ## ## ## "); + prints(POP_STAT_R+4, POP_STAT_C+5, "###### ## ## ##### ##### "); + prints(POP_STAT_R+5, POP_STAT_C+5, "## ######## ## ## "); + prints(POP_STAT_R+6, POP_STAT_C+5, "## ## ## ## ## ## ## "); + prints(POP_STAT_R+7, POP_STAT_C+5, "## ## ## ##### ##### "); + } else { + prints(POP_STAT_R+1, POP_STAT_C+5, "####### ## ###### ## "); + prints(POP_STAT_R+2, POP_STAT_C+5, "## #### ## ## "); + prints(POP_STAT_R+3, POP_STAT_C+5, "## ## ## ## ## "); + prints(POP_STAT_R+4, POP_STAT_C+5, "##### ## ## ## ## "); + prints(POP_STAT_R+5, POP_STAT_C+5, "## ######## ## ## "); + prints(POP_STAT_R+6, POP_STAT_C+5, "## ## ## ## ## "); + prints(POP_STAT_R+7, POP_STAT_C+5, "## ## ## ###### ###### "); + } + set_background_colour(BLUE); + set_foreground_colour(WHITE); + big_status_displayed = true; +} + +void restore_big_status(void) +{ + restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer); + big_status_displayed = false; +} + void check_input(void) { - switch (get_key()) { + char input_key = get_key(); + + if (input_key == '\0') { + return; + } else if (big_status_displayed) { + restore_big_status(); + } + + switch (input_key) { case ESC: clear_message_area(); display_notice("Rebooting..."); diff --git a/app/display.h b/app/display.h index 16c5b7b..fc63401 100644 --- a/app/display.h +++ b/app/display.h @@ -200,10 +200,10 @@ typedef enum { printf(scroll_message_row, col, __VA_ARGS__) #define display_notice(str) \ - prints(ROW_MESSAGE_T + 6, (SCREEN_WIDTH - strlen(str)) / 2, str) + prints(ROW_MESSAGE_T + 8, (SCREEN_WIDTH - strlen(str)) / 2, str) #define display_notice_with_args(length, ...) \ - printf(ROW_MESSAGE_T + 6, (SCREEN_WIDTH - length) / 2, __VA_ARGS__) + printf(ROW_MESSAGE_T + 8, (SCREEN_WIDTH - length) / 2, __VA_ARGS__) #define clear_footer_message() \ { \ @@ -240,6 +240,10 @@ void display_start_test(void); void display_temperature(void); +void display_big_status(bool pass); + +void restore_big_status(void); + void check_input(void); void set_scroll_lock(bool enabled); diff --git a/app/error.c b/app/error.c index 8224147..af6fe83 100644 --- a/app/error.c +++ b/app/error.c @@ -369,6 +369,10 @@ void error_update(void) display_error_count(error_count); display_status("Failed!"); + if (error_count == 1) { + display_big_status(false); + } + if (enable_tty) { tty_error_redraw(); } diff --git a/app/main.c b/app/main.c index ab4e8db..e7fcbbd 100644 --- a/app/main.c +++ b/app/main.c @@ -4,8 +4,8 @@ // Derived from memtest86+ main.c: // // MemTest86+ V5 Specific code (GPL V2.0) -// By Samuel DEMEULEMEESTER, sdemeule@memtest.org -// http://www.canardpc.com - http://www.memtest.org +// By Samuel DEMEULEMEESTER, memtest@memtest.org +// https://www.memtest.org // ------------------------------------------------ // main.c - MemTest-86 Version 3.5 // @@ -664,7 +664,8 @@ void main(void) display_pass_count(pass_num); if (error_count == 0) { display_status("Pass "); - display_notice("** Pass completed, no errors **"); + display_big_status(true); + //display_notice("** Pass completed, no errors **"); } } } From 187bc8609e5f9f7c04f3dd27014714a7c110ca5a Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 17 Jul 2022 20:28:58 +0200 Subject: [PATCH 021/113] Add support for nForce 410/430 & 680a/680i/780i/790i chipsets (tested) --- system/smbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 4efebe8..1a97c0c 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1303,7 +1303,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x00E4: // nForce 3 // case 0x0034: // MCP04 // case 0x0052: // nForce 4 - // case 0x0264: // nForce 410/430 MCP + case 0x0264: // nForce 410/430 MCP case 0x03EB: // nForce 630a // case 0x0446: // nForce 520 // case 0x0542: // nForce 560 @@ -1311,7 +1311,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x07D8: // nForce 630i // case 0x0AA2: // nForce 730i // case 0x0D79: // MCP89 - // case 0x0368: // nForce 790i Ultra + case 0x0368: // nForce 680a/680i/780i/790i return nv_mcp_get_smb(); default: return false; From 37cb966f3983ab353d68f920c6e1646636627bb5 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 17 Jul 2022 22:31:47 +0200 Subject: [PATCH 022/113] Version change to 6.00 Beta 3 (v6.00-beta3) --- app/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/display.c b/app/display.c index 5b27186..4d21eb6 100644 --- a/app/display.c +++ b/app/display.c @@ -103,7 +103,7 @@ void display_init(void) set_foreground_colour(BLACK); set_background_colour(WHITE); clear_screen_region(0, 0, 0, 27); - prints(0, 0, " Memtest86+ v6.00b2"); + prints(0, 0, " Memtest86+ v6.00b3"); set_foreground_colour(RED); printc(0, 14, '+'); set_foreground_colour(WHITE); From 53f61e6b87606244da67d1a05961aed16a18ed44 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 23 Jul 2022 23:01:53 +0200 Subject: [PATCH 023/113] Add 'Heoriady' and 'Golden Empire' to the list of known JEDEC Manufacturers for SPD decoding (#22) --- system/jedec_id.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/jedec_id.h b/system/jedec_id.h index 78be6ee..f0a04e6 100644 --- a/system/jedec_id.h +++ b/system/jedec_id.h @@ -411,7 +411,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0310, "Agere Systems" }, // { 0x0311, "NeoMagic" }, // { 0x0312, "AuroraNetics" }, -// { 0x0313, "Golden Empire" }, + { 0x0313, "Golden Empire" }, { 0x0314, "Mushkin" }, // { 0x0315, "Tioga Technologies" }, // { 0x0316, "Netlist" }, @@ -1098,7 +1098,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x084C, "Shenzhen Pango Microsystems Co Ltd" }, // { 0x084D, "Vasekey" }, // { 0x084F, "Eyenix Co Ltd" }, -// { 0x0850, "Heoriady" }, + { 0x0850, "Heoriady" }, // { 0x0851, "Accelerated Memory Production Inc" }, // { 0x0852, "INVECAS Inc" }, // { 0x0853, "AP Memory" }, From cf156adc4a0066751536c9d1a5eeef463c314eac Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 23 Jul 2022 23:47:06 +0200 Subject: [PATCH 024/113] Solve an issue with Core 2 Duo/Quad and same gen CPUs, where HTT flag is enabled in CPUID while the CPU does not support SMT. (#125 #129) Now compare the number of physical core with the number of reserved APIC to check if SMT is really available or not --- system/cpuid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/cpuid.c b/system/cpuid.c index 0466993..58aa72b 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -215,7 +215,11 @@ void cpuid_init(void) cpuid_info.topology.thread_count = cpuid_info.topology.core_count; if (cpuid_info.flags.htt){ - cpuid_info.topology.thread_count *= 2; + if (((cpuid_info.proc_info.raw >> 16) & 0xFF) > (uint32_t)cpuid_info.topology.core_count) { + cpuid_info.topology.thread_count *= 2; + } else { + cpuid_info.flags.htt = !cpuid_info.flags.htt; + } } } else if (cpuid_info.max_cpuid >= 0x2) { if(cpuid_info.flags.htt){ From 740df34656b122613f3e1f506daff6d16174a6c2 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 23 Jul 2022 23:59:49 +0200 Subject: [PATCH 025/113] Remove now useless IMC check to allow temperature reporting on more older CPUs --- system/temperature.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/system/temperature.c b/system/temperature.c index d36f979..5d29cb5 100644 --- a/system/temperature.c +++ b/system/temperature.c @@ -27,9 +27,6 @@ int get_cpu_temperature(void) { - if (imc_type == 0) { - return 0; - } // Intel CPU if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) { From 13d95690415db84f8cb5b99de4f475a41ed3e146 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 24 Jul 2022 13:56:41 +0100 Subject: [PATCH 026/113] By default, only enable USB keyboard detection when booted in UEFI mode. Most legacy BIOSs will support USB legacy keyboard emulation. Using that will avoid having to reserve memory for the USB drivers, and should improve the chance of having a working keyboard without having to work around various USB device quirks. --- README.md | 12 ++++++------ app/config.c | 2 ++ boot/bootparams.h | 2 ++ system/keyboard.c | 14 +++++++++++++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9d05dcf..c54c210 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ recognised: * where *type* is one of * legacy * usb + * both * usbdebug * pauses after probing for USB keyboards * usbinit=*mode* @@ -157,8 +158,9 @@ recognised: Memtest86+ supports both the legacy keyboard interface (using I/O ports 0x60 and 0x64) and USB keyboards (using its own USB device drivers). One or the -other can be selected via the boot command line, If neither is selected, the -default is to use both. +other or both can be selected via the boot command line, If not specified on +the command line, the default is to use both if the system was booted in UEFI +mode, otherwise to only use the legacy interface. Older BIOSs usually support USB legacy keyboard emulation, which makes USB keyboards act like legacy keyboards connected to ports 0x60 and 0x64. This @@ -168,7 +170,8 @@ keyboards directly. The downside of that is that the USB controllers and device drivers require some memory to be reserved for their private use, which means that memory can't then be covered by the memory tests. So to maximise test coverage, if it is supported, enable USB legacy keyboard -emulation and add `keyboard=legacy` on the boot command line. +emulation and, if booting in UEFI mode, add `keyboard=legacy` on the boot +command line. **NOTE**: Some UEFI BIOSs only support USB legacy keyboard emulation when you enable the Compatibility System Module (CSM) in the BIOS setup. Others @@ -178,9 +181,6 @@ Many USB devices don't fully conform to the USB specification. If the USB keyboard probe hangs or fails to detect your keyboard, try the various workarounds provided by the "usbinit" boot option. -**NOTE**: Memtest86+'s USB device drivers are work in progress. Not all USB -devices are supported yet, and there may be problems on some hardware. - ## Operation Once booted, Memtest86+ will initialise its display, then pause for a few diff --git a/app/config.c b/app/config.c index be2a12e..7a7ed82 100644 --- a/app/config.c +++ b/app/config.c @@ -177,6 +177,8 @@ static void parse_option(const char *option, const char *params) keyboard_types = KT_LEGACY; } else if (strncmp(params, "usb", 4) == 0) { keyboard_types = KT_USB; + } else if (strncmp(params, "both", 5) == 0) { + keyboard_types = KT_USB|KT_LEGACY; } } else if (strncmp(option, "powersave", 10) == 0) { if (strncmp(params, "off", 4) == 0) { diff --git a/boot/bootparams.h b/boot/bootparams.h index 49ec96c..45d95c4 100644 --- a/boot/bootparams.h +++ b/boot/bootparams.h @@ -15,6 +15,8 @@ #include +#include + typedef struct { uint8_t orig_x; uint8_t orig_y; diff --git a/system/keyboard.c b/system/keyboard.c index 513b42d..71a37af 100644 --- a/system/keyboard.c +++ b/system/keyboard.c @@ -3,6 +3,8 @@ #include +#include "bootparams.h" + #include "io.h" #include "usbhcd.h" @@ -212,7 +214,7 @@ static const char usb_hid_keymap[] = { // Public Variables //------------------------------------------------------------------------------ -keyboard_types_t keyboard_types = KT_LEGACY | KT_USB; +keyboard_types_t keyboard_types = KT_NONE; //------------------------------------------------------------------------------ // Public Functions @@ -220,6 +222,16 @@ keyboard_types_t keyboard_types = KT_LEGACY | KT_USB; void keyboard_init(void) { + if (keyboard_types == KT_NONE) { + // No command line option was found, so set the default according to + // how we were booted. + const boot_params_t *boot_params = (boot_params_t *)boot_params_addr; + if (boot_params->efi_info.loader_signature != 0) { + keyboard_types = KT_USB|KT_LEGACY; + } else { + keyboard_types = KT_LEGACY; + } + } if (keyboard_types & KT_USB) { find_usb_keyboards(keyboard_types == KT_USB); } From 408fdb8db6389a2339c8133203f2ffc5964502b6 Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Thu, 14 Jul 2022 18:30:37 +0200 Subject: [PATCH 027/113] Switch to an array of heaps in the heap manager, and heap IDs in the allocation functions. --- system/ehci.c | 8 +++--- system/heap.c | 57 ++++++++++++------------------------------- system/heap.h | 67 +++++++++++++++++---------------------------------- system/ohci.c | 6 ++--- system/smp.c | 2 +- system/uhci.c | 8 +++--- system/xhci.c | 24 +++++++++--------- 7 files changed, 62 insertions(+), 110 deletions(-) diff --git a/system/ehci.c b/system/ehci.c index 1653d65..ad380a7 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -515,11 +515,11 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) if (!reset_host_controller(op_regs)) return false; // Record the heap state to allow us to free memory. - uintptr_t initial_heap_mark = lm_heap_mark(); + uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); // Allocate and initialise a periodic frame list. This needs to be aligned on a 4K page boundary. Some controllers // don't support a programmable list length, so we just use the default length. - uintptr_t pfl_addr = lm_heap_alloc(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE); + uintptr_t pfl_addr = heap_alloc(HEAP_TYPE_LM_1, EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE); if (pfl_addr == 0) { goto no_keyboards_found; } @@ -530,7 +530,7 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) } // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. - uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE); if (workspace_addr == 0) { goto no_keyboards_found; } @@ -684,6 +684,6 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) return true; no_keyboards_found: - lm_heap_rewind(initial_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark); return false; } diff --git a/system/heap.c b/system/heap.c index fff3a44..ff339b0 100644 --- a/system/heap.c +++ b/system/heap.c @@ -24,8 +24,10 @@ typedef struct { // Private Variables //------------------------------------------------------------------------------ -static heap_t lm_heap = { .segment = -1, .start = 0, .end = 0 }; -static heap_t hm_heap = { .segment = -1, .start = 0, .end = 0 }; +static heap_t heaps[HEAP_TYPE_LAST] = { + { .segment = -1, .start = 0, .end = 0 }, + { .segment = -1, .start = 0, .end = 0 } +}; //------------------------------------------------------------------------------ // Private Functions @@ -36,8 +38,9 @@ static size_t num_pages(size_t size) return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; } -static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment) +uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment) { + const heap_t * heap = &heaps[heap_id]; if (heap->segment < 0) { return 0; } @@ -50,16 +53,18 @@ static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment return addr << PAGE_SHIFT; } -static uintptr_t heap_mark(const heap_t *heap) +uintptr_t heap_mark(heap_type_t heap_id) { + const heap_t * heap = &heaps[heap_id]; if (heap->segment < 0) { return 0; } return pm_map[heap->segment].end; } -static void heap_rewind(const heap_t *heap, uintptr_t mark) +void heap_rewind(heap_type_t heap_id, uintptr_t mark) { + const heap_t * heap = &heaps[heap_id]; if (heap->segment >= 0 && mark > pm_map[heap->segment].end && mark <= heap->end) { pm_map[heap->segment].end = mark; } @@ -86,43 +91,13 @@ void heap_init(void) if (segment_size >= max_segment_size) { max_segment_size = segment_size; if (try_heap_end <= PAGE_C(1,MB)) { - lm_heap.segment = i; - lm_heap.start = try_heap_start; - lm_heap.end = try_heap_end; + heaps[HEAP_TYPE_LM_1].segment = i; + heaps[HEAP_TYPE_LM_1].start = try_heap_start; + heaps[HEAP_TYPE_LM_1].end = try_heap_end; } - hm_heap.segment = i; - hm_heap.start = try_heap_start; - hm_heap.end = try_heap_end; + heaps[HEAP_TYPE_HM_1].segment = i; + heaps[HEAP_TYPE_HM_1].start = try_heap_start; + heaps[HEAP_TYPE_HM_1].end = try_heap_end; } } } - -uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment) -{ - return heap_alloc(&lm_heap, size, alignment); -} - -uintptr_t lm_heap_mark(void) -{ - return heap_mark(&lm_heap); -} - -void lm_heap_rewind(uintptr_t mark) -{ - heap_rewind(&lm_heap, mark); -} - -uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment) -{ - return heap_alloc(&hm_heap, size, alignment); -} - -uintptr_t hm_heap_mark(void) -{ - return heap_mark(&hm_heap); -} - -void hm_heap_rewind(uintptr_t mark) -{ - heap_rewind(&hm_heap, mark); -} diff --git a/system/heap.h b/system/heap.h index 142e268..4c7e0ef 100644 --- a/system/heap.h +++ b/system/heap.h @@ -16,71 +16,48 @@ #include #include +typedef enum { + HEAP_TYPE_LM_1, + HEAP_TYPE_HM_1, + HEAP_TYPE_LAST +} heap_type_t; + /** * Initialises the heaps. */ void heap_init(void); /** - * Allocates a chunk of physical memory below 1MB. The allocated region will - * be at least the requested size with the requested alignment. This memory - * is always mapped to the identical address in virtual memory. + * Allocates a chunk of physical memory in the given heap. The allocated + * region will be at least the requested size with the requested alignment. + * This memory is always mapped to the identical address in virtual memory. * - * \param size - the requested size in bytes. - * \param alignment - the requested byte alignment (must be a power of 2). + * \param size - the requested size in bytes. + * \param alignment - the requested byte alignment (must be a power of 2). + * \param heap - the heap on which this allocation shall be performed. * * \returns * On success, the allocated address in physical memory. On failure, 0. */ -uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment); +uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment); /** - * Returns a value indicating the current allocation state of the low-memory - * heap. This value may be passed to lm_heap_rewind() to free any low memory - * allocated after this call. + * Returns a value indicating the current allocation state of the given + * memory heap. This value may be passed to heap_rewind() to free any + * memory from that heap allocated after this call. * * \returns * An opaque value indicating the current allocation state. */ -uintptr_t lm_heap_mark(void); +uintptr_t heap_mark(heap_type_t heap_id); /** - * Frees any low memory allocated since the specified mark was obtained from - * a call to lm_heap_mark(). + * Frees any memory allocated in the given heap since the specified mark was + * obtained from a call to heap_mark(). * - * \param mark - the mark that indicates how much memory to free. + * \param mark - the mark that indicates how much memory to free. + * \param heap - the heap on which this rewind shall be performed. */ -void lm_heap_rewind(uintptr_t mark); - -/** - * Allocates a chunk of physical memory below 4GB. The allocated region will - * be at least the requested size with the requested alignment. The caller is - * responsible for mapping it into virtual memory if required. - * - * \param size - the requested size in bytes. - * \param alignment - the requested byte alignment (must be a power of 2). - * - * \returns - * On success, the allocated address in physical memory. On failure, 0. - */ -uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment); - -/** - * Returns a value indicating the current allocation state of the high-memory - * heap. This value may be passed to hm_heap_rewind() to free any high memory - * allocated after this call. - * - * \returns - * An opaque value indicating the current allocation state. - */ -uintptr_t hm_heap_mark(void); - -/** - * Frees any high memory allocated since the specified mark was obtained from - * a call to hm_heap_mark(). - * - * \param mark - the mark that indicates how much memory to free. - */ -void hm_heap_rewind(uintptr_t mark); +void heap_rewind(heap_type_t heap_id, uintptr_t mark); #endif // HEAP_H diff --git a/system/ohci.c b/system/ohci.c index 17d221f..d8abb18 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -457,10 +457,10 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) } // Record the heap state to allow us to free memory. - uintptr_t initial_heap_mark = lm_heap_mark(); + uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. - uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE); if (workspace_addr == 0) { goto no_keyboards_found; } @@ -608,6 +608,6 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) return true; no_keyboards_found: - lm_heap_rewind(initial_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark); return false; } diff --git a/system/smp.c b/system/smp.c index bc6215e..c8f8c6e 100644 --- a/system/smp.c +++ b/system/smp.c @@ -550,7 +550,7 @@ void smp_init(bool smp_enable) // Allocate a page of low memory for AP trampoline and sync objects. // These need to remain pinned in place during relocation. - smp_heap_page = lm_heap_alloc(PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT; + smp_heap_page = heap_alloc(HEAP_TYPE_LM_1, PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT; ap_startup_addr = (uintptr_t)startup; diff --git a/system/uhci.c b/system/uhci.c index 1cb0615..6109fd8 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -430,17 +430,17 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) if (!reset_host_controller(io_base)) return false; // Record the heap state to allow us to free memory. - uintptr_t initial_heap_mark = lm_heap_mark(); + uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); // Allocate the frame list. This needs to be aligned on a 4K page boundary. - uintptr_t fl_addr = lm_heap_alloc(UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE); + uintptr_t fl_addr = heap_alloc(HEAP_TYPE_LM_1, UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE); if (fl_addr == 0) { goto no_keyboards_found; } uint32_t *fl = (uint32_t *)fl_addr; // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. - uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE); if (workspace_addr == 0) { goto no_keyboards_found; } @@ -574,6 +574,6 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) return true; no_keyboards_found: - lm_heap_rewind(initial_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark); return false; } diff --git a/system/xhci.c b/system/xhci.c index aebc20f..a739884 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -645,10 +645,10 @@ static int allocate_slot(const usb_hcd_t *hcd) xhci_trb_t event; // Record the heap state to allow us to free memory. - ws->initial_heap_mark = lm_heap_mark(); + ws->initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); // Allocate and initialise a private workspace for this device. - uintptr_t device_workspace_addr = lm_heap_alloc(DEVICE_WS_SIZE, PAGE_SIZE); + uintptr_t device_workspace_addr = heap_alloc(HEAP_TYPE_LM_1, DEVICE_WS_SIZE, PAGE_SIZE); if (device_workspace_addr == 0) { goto free_memory; } @@ -672,7 +672,7 @@ static int allocate_slot(const usb_hcd_t *hcd) return slot_id; free_memory: - lm_heap_rewind(ws->initial_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark); return 0; } @@ -690,7 +690,7 @@ static bool release_slot(const usb_hcd_t *hcd, int slot_id) write64(&ws->device_context_index[slot_id], 0); - lm_heap_rewind(ws->initial_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark); return true; } @@ -987,8 +987,8 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) if (!reset_host_controller(op_regs)) return false; // Record the heap states to allow us to free memory. - uintptr_t initial_lm_heap_mark = lm_heap_mark(); - uintptr_t initial_hm_heap_mark = hm_heap_mark(); + uintptr_t initial_lm_heap_mark = heap_mark(HEAP_TYPE_LM_1); + uintptr_t initial_hm_heap_mark = heap_mark(HEAP_TYPE_HM_1); // Record the controller page size. uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12; @@ -1002,7 +1002,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) // Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size. uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size; - uintptr_t scratchpad_paddr = hm_heap_alloc(scratchpad_size, xhci_page_size); + uintptr_t scratchpad_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_size, xhci_page_size); if (scratchpad_paddr == 0) { goto no_keyboards_found; } @@ -1018,7 +1018,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) uintptr_t device_context_index_size = (1 + max_slots) * sizeof(uint64_t); uintptr_t scratchpad_buffer_index_offs = round_up(device_context_index_size, 64); uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t); - uintptr_t device_context_index_paddr = hm_heap_alloc(scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64); + uintptr_t device_context_index_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64); if (device_context_index_paddr == 0) { goto no_keyboards_found; } @@ -1041,7 +1041,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) } // Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory. - uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE); + uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE); if (workspace_addr == 0) { goto no_keyboards_found; } @@ -1061,7 +1061,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) ws->er_dequeue_state = WS_ER_SIZE; // cycle = 1, index = 0 // Allocate and initialise the input context data structure. This needs to be contained within a single page. - ws->input_context_addr = lm_heap_alloc(XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE); + ws->input_context_addr = heap_alloc(HEAP_TYPE_LM_1, XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE); if (ws->input_context_addr == 0) { goto no_keyboards_found; } @@ -1167,7 +1167,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) return true; no_keyboards_found: - lm_heap_rewind(initial_lm_heap_mark); - hm_heap_rewind(initial_hm_heap_mark); + heap_rewind(HEAP_TYPE_LM_1, initial_lm_heap_mark); + heap_rewind(HEAP_TYPE_HM_1, initial_hm_heap_mark); return false; } From 8a3cac8133430b93129341c3c6105b7f1d3a5445 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Tue, 26 Jul 2022 20:02:58 +0200 Subject: [PATCH 028/113] Fix an issue while detection Core topology on Core 2 CPU. Some CPU like Intel Yorkfield (Core 2 Quad) reports max CPUID > 0xB but doesn't support CPUID = 0xB. Check x2apic flag to be sure CPUID 0xB is supported. If not, fallback to older detection method --- system/cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/cpuid.c b/system/cpuid.c index 58aa72b..aef3924 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -181,7 +181,7 @@ void cpuid_init(void) case 'G': if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta // Intel - if (cpuid_info.max_cpuid >= 0xB) { + if (cpuid_info.max_cpuid >= 0xB && cpuid_info.flags.x2apic) { // Populate Hybrid Status (CPUID 7.EDX[15]) for Alder Lake+ cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]); From 1316c6c099a988b2e20a2e2e48e04784281008d1 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 5 Aug 2022 20:40:18 +0100 Subject: [PATCH 029/113] Fix scanning of an external USB hub attached to an Intel XHCI (issue #135) The Intel controller requires unused fields in the input context to be zero. --- system/xhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/xhci.c b/system/xhci.c index a739884..74a05cb 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -718,6 +718,8 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_ // Prepare the input context for the ADDRESS_DEVICE command. + memset((xhci_input_context_t *)ws->input_context_addr, 0, sizeof(xhci_input_context_t)); + xhci_ctrl_context_t *ctrl_context = (xhci_ctrl_context_t *)ws->input_context_addr; ctrl_context->add_context_flags = XHCI_CONTEXT_A(0) | XHCI_CONTEXT_A(1); @@ -734,6 +736,7 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_ } else { slot_context->root_hub_port_num = port_num; } + xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + 2 * ws->context_size); ep_context->params2 = XHCI_EP_CONTROL << 3 | 3 << 1; // EP Type | CErr ep_context->max_burst_size = 0; From 148dfd4d540cef3dd216fef74439e90c69d3c752 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 5 Aug 2022 20:48:24 +0100 Subject: [PATCH 030/113] Apply the USB_2_STEP_INIT option when using an XHCI controller. This was added to the generic assign_address() method, but the XHCI driver overrides that. --- system/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/xhci.c b/system/xhci.c index 74a05cb..99cab67 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -757,7 +757,7 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_ size_t fetch_length = sizeof(usb_device_desc_t); uint32_t command_flags = 0; - if (device_speed < USB_SPEED_HIGH) { + if (device_speed < USB_SPEED_HIGH || usb_init_options & USB_2_STEP_INIT) { fetch_length = 8; command_flags = XHCI_TRB_BSR; } From 9660eead4ee3a02597a3d2556d64ff3171448e0c Mon Sep 17 00:00:00 2001 From: a1346054 <36859588+a1346054@users.noreply.github.com> Date: Mon, 15 Aug 2022 15:51:48 +0000 Subject: [PATCH 031/113] Simple maintenance improvements (#145) * Fix typos * Add missing final newline * Trim trailing whitespace --- README.md | 4 ++-- app/error.c | 2 +- app/interrupt.c | 2 +- boot/setup.S | 4 ++-- system/cache.h | 4 ++-- system/ehci.c | 6 +++--- system/ohci.c | 2 +- system/smbios.h | 2 +- system/smbus.c | 4 ++-- system/smbus.h | 2 +- system/uhci.c | 2 +- system/usbhcd.c | 2 +- tests/addr_walk1.c | 2 +- tests/block_move.c | 2 +- 14 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c54c210..0c84866 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ booted directly by a legacy BIOS (in floppy mode) or by an intermediate bootloader using the Linux 16-bit boot protocol and a `memtest.efi` binary image file which can be booted directly by a 32-bit UEFI BIOS. Either image can be booted by an intermediate bootloader using the Linux 32-bit or 32-bit -EFI handover boot protocols. +EFI handover boot protocols. To build a 64-bit image, change directory into the `build64` directory and type `make`. The result is a `memtest.bin` binary image file which can be @@ -144,7 +144,7 @@ recognised: * activate serial/tty console output, where *x* is one of the following IO port * 0 = 0x3F8 * 1 = 0x2F8 - * 2 = 0x3E8 + * 2 = 0x3E8 * 3 = 0x2E8 * and *y* is an optional baud rate to choose from the following list * 9600 diff --git a/app/error.c b/app/error.c index af6fe83..b6da413 100644 --- a/app/error.c +++ b/app/error.c @@ -334,7 +334,7 @@ void addr_error(testword_t *addr1, testword_t *addr2, testword_t good, testword_ void data_error(testword_t *addr, testword_t good, testword_t bad, bool use_for_badram) { #if USB_WORKAROUND - /* Skip any errrors that appear to be due to the BIOS using location + /* Skip any errors that appear to be due to the BIOS using location * 0x4e0 for USB keyboard support. This often happens with Intel * 810, 815 and 820 chipsets. It is possible that we will skip * a real error but the odds are very low. diff --git a/app/interrupt.c b/app/interrupt.c index 2266a85..b2da527 100644 --- a/app/interrupt.c +++ b/app/interrupt.c @@ -196,7 +196,7 @@ void interrupt(struct trap_regs *trap_regs) clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1); prints(ROW_FOOTER, 0, "Press any key to reboot..."); - + while (get_key() == 0) { } reboot(); } diff --git a/boot/setup.S b/boot/setup.S index f6640f3..2511741 100644 --- a/boot/setup.S +++ b/boot/setup.S @@ -132,7 +132,7 @@ do_setup: call empty_8042 movb $0xd1, %al # send write command outb %al, $0x64 - call empty_8042 + call empty_8042 movb $0xdf, %al # A20 on outb %al, $0x60 call empty_8042 @@ -352,7 +352,7 @@ empty_8042: call delay inb $0x60, %al # read it jmp empty_8042 - + no_output: testb $2, %al # is input buffer full? jnz empty_8042 # yes - loop diff --git a/system/cache.h b/system/cache.h index 3ec7438..3a40550 100644 --- a/system/cache.h +++ b/system/cache.h @@ -46,7 +46,7 @@ static inline void cache_on(void) #ifdef __x86_64__ __asm__ __volatile__ ("\t" "movq %%cr0, %%rax \n\t" - "andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */ + "andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */ "movq %%rax, %%cr0 \n" : /* no outputs */ : /* no inputs */ @@ -55,7 +55,7 @@ static inline void cache_on(void) #else __asm__ __volatile__ ("\t" "movl %%cr0, %%eax \n\t" - "andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */ + "andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */ "movl %%eax, %%cr0 \n" : /* no outputs */ : /* no inputs */ diff --git a/system/ehci.c b/system/ehci.c index ad380a7..c65d0fb 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -47,7 +47,7 @@ #define EHCI_USBCMD_ITC(n) ((n) << 16) // Interrupt Threshold Control = n (n = 1,2,4,8,16,32,64) -// USB Status register +// USB Status register #define EHCI_USBSTS_INT 0x00000001 // Interrupt #define EHCI_USBSTS_ERR 0x00000002 // Error interrupt @@ -60,7 +60,7 @@ #define EHCI_USBSTS_PSS 0x00004000 // Periodic Schedule Status #define EHCI_USBSTS_ASS 0x00008000 // Asynchronous Schedule Status -// Port Status and Control register +// Port Status and Control register #define EHCI_PORT_SC_CCS 0x00000001 // Current Connect Status #define EHCI_PORT_SC_CCSC 0x00000002 // Current Connect Status Change @@ -78,7 +78,7 @@ #define EHCI_PORT_SC_LS_J 0x00000800 // Line Status is J-state #define EHCI_PORT_SC_LS_U 0x00000c00 // Line Status is undefined -// Link Pointer +// Link Pointer #define EHCI_LP_TERMINATE 0x00000001 // Terminate (T) bit diff --git a/system/ohci.c b/system/ohci.c index d8abb18..f002206 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -410,7 +410,7 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) { ohci_op_regs_t *op_regs = (ohci_op_regs_t *)base_addr; - // Check the host controller revison. + // Check the host controller revision. if ((read32(&op_regs->revision) & 0xff) != 0x10) { return false; } diff --git a/system/smbios.h b/system/smbios.h index f1323bc..52f7afb 100644 --- a/system/smbios.h +++ b/system/smbios.h @@ -135,7 +135,7 @@ extern struct mem_dev *dmi_memory_device; int smbios_init(void); /** - * Print DMI + * Print DMI */ void print_smbios_startup_info(void); diff --git a/system/smbus.c b/system/smbus.c index 1a97c0c..54a34f6 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -192,7 +192,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) spdi.sku_len = 0; spdi.module_size = 0; - // Compute module size for symmetric & assymetric configuration + // Compute module size for symmetric & asymmetric configuration for (int sbyte_adr = 1; sbyte_adr <= 2; sbyte_adr++) { uint32_t cur_rank = 0; uint8_t sbyte = get_spd(slot_idx, sbyte_adr * 4); @@ -871,7 +871,7 @@ static spd_info parse_spd_ddr(uint8_t slot_idx) case 128: spdi.module_size = 512; break; - default: // we don't support asymetric banking + default: // we don't support asymmetric banking spdi.module_size = 0; break; } diff --git a/system/smbus.h b/system/smbus.h index 669e8a5..62d23ef 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -127,4 +127,4 @@ extern ram_info ram; void print_smbus_startup_info(void); -#endif // SMBUS_H \ No newline at end of file +#endif // SMBUS_H diff --git a/system/uhci.c b/system/uhci.c index 6109fd8..1ec06f3 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -59,7 +59,7 @@ #define UHCI_USBCMD_GR 0x0004 // Global Reset #define UHCI_USBCMD_MAXP 0x0080 // Max Packet -// USB Status register +// USB Status register #define UHCI_USBSTS_INT 0x0001 // Interrupt #define UHCI_USBSTS_ERR 0x0002 // Error interrupt diff --git a/system/usbhcd.c b/system/usbhcd.c index 456ab43..447dd72 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -600,7 +600,7 @@ bool assign_usb_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num return true; } -bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num, +bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num, usb_speed_t device_speed, int device_id, int *num_devices, usb_ep_t keyboards[], int max_keyboards, int *num_keyboards) { diff --git a/tests/addr_walk1.c b/tests/addr_walk1.c index 5222cd0..366ea62 100644 --- a/tests/addr_walk1.c +++ b/tests/addr_walk1.c @@ -70,7 +70,7 @@ int test_addr_walk1(int my_cpu) break; } write_word(p2, ~invert ^ (testword_t)p2); - + testword_t actual = read_word(p1); if (unlikely(actual != expect)) { addr_error(p1, p2, expect, actual); diff --git a/tests/block_move.c b/tests/block_move.c index 859f83e..979f05a 100644 --- a/tests/block_move.c +++ b/tests/block_move.c @@ -84,7 +84,7 @@ int test_block_move(int my_cpu, int iterations) } flush_caches(my_cpu); - // Now move the data around. First move the data up half of the segment size + // Now move the data around. First move the data up half of the segment size // we are testing. Then move the data to the original location + 32 bytes. for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; From 02702fa8c5c4201ce5d9e1f4f07bc7700a7c80d0 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 15 Aug 2022 22:26:22 +0200 Subject: [PATCH 032/113] Change check to be sure Extended Topology Information (CPUID.0BH:EBX[15:0]) is supported --- system/cpuid.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/system/cpuid.c b/system/cpuid.c index aef3924..260f138 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -181,7 +181,11 @@ void cpuid_init(void) case 'G': if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta // Intel - if (cpuid_info.max_cpuid >= 0xB && cpuid_info.flags.x2apic) { + if (cpuid_info.max_cpuid >= 0xB) { + cpuid(0xB, 0, ®[0], ®[1], ®[2], ®[3]); + } + + if (cpuid_info.max_cpuid >= 0xB && (reg[1] & 0xFF) != 0) { // Check if Extended Topology Information is available // Populate Hybrid Status (CPUID 7.EDX[15]) for Alder Lake+ cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]); @@ -191,7 +195,7 @@ void cpuid_init(void) cpuid_info.topology.ecore_count = 0; } - for (int i=0; i < 4; i++) { + for (int i = 0; i < 4; i++) { cpuid(0xB, i, ®[0], ®[1], ®[2], ®[3]); switch((reg[2] >> 8) & 0xFF) { From 93051adfc2b85227c8f48bc30ea53f2fda652c09 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 20 Aug 2022 10:18:25 +0100 Subject: [PATCH 033/113] Update README. - update text to indicate that benchmarking and SPD reporting has now been restored - point to GitHub issue tracker for known limitations and bugs --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0c84866..455657f 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ of the PCMemTest rewrite was to: In the process of creating PCMemTest, a number of features of Memtest86+ v5.01 that were not strictly required for testing the system memory were dropped. In -particular, no attempt is made to measure the cache and main memory speed, or -to identify and report the DRAM type. These features will be added back -in Memtest86+ v6.0 in an attempt to create an unified, fully-featured release. +particular, no attempt was made to measure the cache and main memory speed, or +to identify and report the DRAM type. These features were added back in +Memtest86+ v6.0 to create a unified, fully-featured release. ## Licensing @@ -537,7 +537,8 @@ of all zeros and all ones. ## Known Limitations and Bugs - * Keyboard may not be detected at launch in UEFI mode +Please see the list of [open issues](https://github.com/memtest86plus/memtest86plus/issues) +on GitHub. Feel free to submit bug reports! From 0f8981412c49c630c312a086687878c89275d0df Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Fri, 26 Aug 2022 21:56:12 +0200 Subject: [PATCH 034/113] Various fixes on SPD decoding algorithms (#152) * [DDR5] Fix rounding errors on SPD Timings * [DDR5] Add a rounding factor of ~0.3% according to JEDEC to solve the last rounding issue found on NETAC Modules * [DDR5] Add missing package ranks per channel parameter in total module capacity algorithm * [DDR4] Fix rounding issues in SPD timings & frequency * [DDR3] Fix rounding issues in SPD timings & frequency decoding. Check XMP Profile #2. Add a quirk for Kingston based on very early XMP 1.0 specs * [DDR2] Fix CAS detection & rounding issues in SPD timings w/ EPP * [DDR] Correct SPD timings rounding issues & add support for x.5 CAS latencies * [SDR] Correct SPD Timings decoding due to rounding errors * Add various JEP106 Manufacturers found while debugging * Update timings display function to handle x.5 CAS --- app/display.c | 4 +- app/display.h | 6 +- system/jedec_id.h | 52 +++++++------- system/smbus.c | 178 +++++++++++++++++++++++++++------------------- system/smbus.h | 11 +++ 5 files changed, 148 insertions(+), 103 deletions(-) diff --git a/app/display.c b/app/display.c index 4d21eb6..2097e7e 100644 --- a/app/display.c +++ b/app/display.c @@ -266,7 +266,7 @@ void post_display_init(void) if (false) { // Try to get RAM information from IMC (TODO) display_spec_mode("IMC: "); - display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS); + display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tCL_dec, ram.tRCD, ram.tRP, ram.tRAS); display_mode = DISPLAY_MODE_IMC; } else if (ram.freq > 0 && ram.tCL > 0) { // If not available, grab max memory specs from SPD @@ -274,7 +274,7 @@ void post_display_init(void) if (ram.freq <= 166) { display_spec_sdr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS); } else { - display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS); + display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tCL_dec, ram.tRCD, ram.tRP, ram.tRAS); } display_mode = DISPLAY_MODE_SPD; } else { diff --git a/app/display.h b/app/display.h index fc63401..7d065f7 100644 --- a/app/display.h +++ b/app/display.h @@ -102,9 +102,9 @@ typedef enum { #define display_spec_mode(mode) \ prints(8,0, mode); -#define display_spec_ddr(freq, type, cl, rcd, rp, ras) \ - printf(8,5, "%uMHz (%s-%u) CAS %u-%u-%u-%u", \ - freq / 2, type, freq, cl, rcd, rp, ras); +#define display_spec_ddr(freq, type, cl, cl_dec, rcd, rp, ras) \ + printf(8,5, "%uMHz (%s-%u) CAS %u%s-%u-%u-%u", \ + freq / 2, type, freq, cl, cl_dec?".5":"", rcd, rp, ras); #define display_spec_sdr(freq, type, cl, rcd, rp, ras) \ printf(8,5, "%uMHz (%s PC%u) CAS %u-%u-%u-%u", \ diff --git a/system/jedec_id.h b/system/jedec_id.h index f0a04e6..6b280c9 100644 --- a/system/jedec_id.h +++ b/system/jedec_id.h @@ -79,7 +79,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x003D, "Tektronix" }, // { 0x003E, "Oracle Corporation" }, // { 0x003F, "Silicon Storage Technology" }, -// { 0x0040, "ProMos/Mosel Vitelic" }, + { 0x0040, "MOSEL" }, { 0x0041, "Infineon" }, { 0x0042, "Macronix" }, // { 0x0043, "Xerox" }, @@ -161,7 +161,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0111, "DATARAM" }, // { 0x0112, "United Microelectronics Corp" }, // { 0x0113, "TCSI" }, -// { 0x0114, "Smart Modular" }, + { 0x0114, "Smart Modular" }, // { 0x0115, "Hughes Aircraft" }, // { 0x0116, "Lanstar Semiconductor" }, // { 0x0117, "Qlogic" }, @@ -392,7 +392,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x027B, "Accelerant Networks" }, // { 0x027C, "Silicon Wave" }, // { 0x027D, "SandCraft" }, -// { 0x027E, "Elpida" }, + { 0x027E, "Elpida" }, // { 0x0301, "Solectron" }, // { 0x0302, "Optosys Technologies" }, // { 0x0303, "Buffalo (Formerly Melco)" }, @@ -407,14 +407,14 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x030C, "Elite Flash Storage" }, // { 0x030D, "Mysticom" }, // { 0x030E, "LightSand Communications" }, -// { 0x030F, "ATI Technologies" }, + { 0x030F, "ATI" }, // { 0x0310, "Agere Systems" }, // { 0x0311, "NeoMagic" }, // { 0x0312, "AuroraNetics" }, - { 0x0313, "Golden Empire" }, + { 0x0313, "GEIL" }, { 0x0314, "Mushkin" }, // { 0x0315, "Tioga Technologies" }, -// { 0x0316, "Netlist" }, + { 0x0316, "Netlist" }, // { 0x0317, "TeraLogic" }, // { 0x0318, "Cicada Semiconductor" }, // { 0x0319, "Centon Electronics" }, @@ -480,7 +480,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0355, "Silverback Systems" }, // { 0x0356, "Jade Star Technologies" }, // { 0x0357, "Pijnenburg Securealink" }, -// { 0x0358, "takeMS - Ultron AG" }, + { 0x0358, "takeMS" }, // Ultron AG // { 0x0359, "Cambridge Silicon Radio" }, { 0x035A, "Swissbit" }, // { 0x035B, "Nazomi Communications" }, @@ -540,7 +540,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0413, "Digital Communications Technology Inc" }, // { 0x0414, "Silicon-Based Technology" }, // { 0x0415, "Fulcrum Microsystems" }, -// { 0x0416, "Positivo Informatica Ltd" }, + { 0x0416, "Positivo" }, // { 0x0417, "XIOtech Corporation" }, // { 0x0418, "PortalPlayer" }, // { 0x0419, "Zhiying Software" }, @@ -585,7 +585,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0440, "Bandspeed" }, // { 0x0441, "LeWiz Communications" }, // { 0x0442, "CPU Technology" }, -// { 0x0443, "Ramaxel Technology" }, + { 0x0443, "Ramaxel" }, // { 0x0444, "DSP Group" }, // { 0x0445, "Axis Communications" }, // { 0x0446, "Legacy Electronics" }, @@ -706,7 +706,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x053B, "Solid State System Co Ltd" }, // { 0x053C, "Kian Tech LLC" }, // { 0x053D, "Artimi" }, -// { 0x053E, "Power Quotient International" }, + { 0x053E, "PQI" }, // { 0x053F, "Avago Technologies" }, // { 0x0540, "ADTechnology" }, // { 0x0541, "Sigma Designs" }, @@ -730,20 +730,20 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0553, "Velogix" }, // { 0x0554, "Montalvo Systems" }, // { 0x0555, "iVivity Inc" }, -// { 0x0556, "Walton Chaintech" }, -// { 0x0557, "AENEON" }, + { 0x0556, "Walton Chaintech" }, + { 0x0557, "AENEON" }, // { 0x0558, "Lorom Industrial Co Ltd" }, // { 0x0559, "Radiospire Networks" }, // { 0x055A, "Sensio Technologies Inc" }, // { 0x055B, "Nethra Imaging" }, -// { 0x055C, "Hexon Technology Pte Ltd" }, + { 0x055C, "Hexon" }, // { 0x055D, "CompuStocx (CSX)" }, // { 0x055E, "Methode Electronics Inc" }, // { 0x055F, "Connect One Ltd" }, // { 0x0560, "Opulan Technologies" }, // { 0x0561, "Septentrio NV" }, // { 0x0562, "Goldenmars Technology Inc" }, -// { 0x0563, "Kreton Corporation" }, + { 0x0563, "Kreton Corp." }, // { 0x0564, "Cochlear Ltd" }, // { 0x0565, "Altair Semiconductor" }, // { 0x0566, "NetEffect Inc" }, @@ -835,7 +835,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x063E, "Wilocity" }, // { 0x063F, "Novafora Inc" }, // { 0x0640, "iKoa Corporation" }, -// { 0x0641, "ASint Technology" }, + { 0x0641, "ASint" }, { 0x0642, "Ramtron" }, // { 0x0643, "Plato Networks Inc" }, // { 0x0644, "IPtronics AS" }, @@ -874,7 +874,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0666, "Netronome" }, // { 0x0667, "Zenverge Inc" }, // { 0x0668, "N-trig Ltd" }, -// { 0x0669, "SanMax Technologies Inc" }, + { 0x0669, "SanMax" }, // { 0x066A, "Contour Semiconductor Inc" }, { 0x066B, "TwinMOS" }, // { 0x066C, "Silicon Systems Inc" }, @@ -987,7 +987,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x075A, "Bestdon Technology Co Ltd" }, // { 0x075B, "Baysand Inc" }, // { 0x075C, "Uroad Technology Co Ltd" }, -// { 0x075D, "Wilk Elektronik S.A." }, + { 0x075D, "Wilk Elektronik" }, // { 0x075E, "AAI" }, // { 0x075F, "Harman" }, // { 0x0760, "Berg Microelectronics Inc" }, @@ -1038,12 +1038,12 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0810, "Exelis" }, // { 0x0811, "Satixfy Ltd" }, // { 0x0812, "Galaxy Microsystems Ltd" }, -// { 0x0813, "Gloway International Co Ltd" }, + { 0x0813, "Gloway" }, // { 0x0814, "Lab" }, // { 0x0815, "Smart Energy Instruments" }, // { 0x0816, "Approved Memory Corporation" }, // { 0x0817, "Axell Corporation" }, -// { 0x0818, "Essencore Limited" }, + { 0x0818, "KLEVV" }, // { 0x0819, "Phytium" }, // { 0x081A, "Xi'an UniIC Semiconductors Co Ltd" }, // { 0x081B, "Ambiq Micro" }, @@ -1208,7 +1208,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x093F, "Pegasus Semiconductor (Shanghai) Co" }, // { 0x0940, "Mythic Inc" }, // { 0x0941, "Elmos Semiconductor AG" }, -// { 0x0942, "Kllisre" }, + { 0x0942, "Kllisre" }, // { 0x0943, "Shenzhen Winconway Technology" }, // { 0x0944, "Shenzhen Xingmem Technology Corp" }, // { 0x0945, "Gold Key Technology Co Ltd" }, @@ -1261,7 +1261,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0974, "Hyundai Inc" }, // { 0x0975, "EXCELERAM" }, // { 0x0976, "PsiKick" }, -// { 0x0977, "Netac Technology Co Ltd" }, + { 0x0977, "Netac" }, { 0x0978, "PCCOOLER" }, // { 0x0979, "Jiangsu Huacun Electronic Technology" }, // { 0x097A, "Shenzhen Micro Innovation Industry" }, @@ -1335,7 +1335,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0A42, "Thermaltake Technology Co Ltd" }, // { 0x0A43, "Shenzhen O?Yang Maile Technology Ltd" }, // { 0x0A44, "UPMEM" }, -// { 0x0A45, "Chun Well Technology Holding Limited" }, + { 0x0A45, "Chun Well" }, // { 0x0A46, "Astera Labs Inc" }, // { 0x0A47, "Winconway" }, // { 0x0A48, "Advantech Co Ltd" }, @@ -1384,7 +1384,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0A73, "MCLogic Inc" }, // { 0x0A74, "Eorex Corporation" }, // { 0x0A75, "Arm Technology (China) Co Ltd" }, -// { 0x0A76, "Lexar Co Limited" }, + { 0x0A76, "Lexar" }, // { 0x0A77, "QinetiQ Group plc" }, // { 0x0A78, "Exascend" }, // { 0x0A79, "Hong Kong Hyunion Electronics Co Ltd" }, @@ -1410,7 +1410,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0B0F, "Quadratica LLC" }, // { 0x0B10, "Anpec Electronics" }, // { 0x0B11, "Xi'an Morebeck Semiconductor Tech Co" }, -// { 0x0B12, "Kingbank Technology Co Ltd" }, + { 0x0B12, "Kingbank" }, // { 0x0B13, "ITRenew Inc" }, // { 0x0B14, "Shenzhen Eaget Innovation Tech Ltd" }, // { 0x0B15, "Jazer" }, @@ -1556,7 +1556,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0C23, "Tangem AG" }, // { 0x0C24, "FuturePath Technology (Shenzhen) Co" }, // { 0x0C25, "RC Module" }, -// { 0x0C26, "Timetec International Inc" }, + { 0x0C26, "Timetec" }, // { 0x0C27, "ICMAX Technologies Co Limited" }, // { 0x0C28, "Lynxi Technologies Ltd Co" }, // { 0x0C29, "Guangzhou Taisupanke Computer Equipment" }, @@ -1611,7 +1611,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x0C5A, "Fraunhofer IPMS" }, // { 0x0C5B, "Shenzhen Daxinlang Electronic Tech Co" }, // { 0x0C5C, "Abacus Peripherals Private Limited" }, -// { 0x0C5D, "OLOy Technology" }, + { 0x0C5D, "OLOy" }, // { 0x0C5E, "Wuhan P&S Semiconductor Co Ltd" }, // { 0x0C5F, "Sitrus Technology" }, // { 0x0C60, "AnHui Conner Storage Co Ltd" }, diff --git a/system/smbus.c b/system/smbus.c index 54a34f6..cbfd586 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -17,7 +17,7 @@ #define LINE_SPD 13 #define MAX_SPD_SLOT 8 -ram_info ram = { 0, 0, 0, 0, 0, "N/A"}; +ram_info ram = { 0, 0, 0, 0, 0, 0, "N/A"}; int smbdev, smbfun; unsigned short smbusbase = 0; @@ -175,10 +175,11 @@ static void print_spdi(spd_info spdi, uint8_t lidx) ram.freq = spdi.freq; } if (ram.tCL < spdi.tCL) { - ram.tCL = spdi.tCL; - ram.tRCD = spdi.tRCD; - ram.tRP = spdi.tRP; - ram.tRAS = spdi.tRAS; + ram.tCL = spdi.tCL; + ram.tCL_dec = spdi.tCL_dec; + ram.tRCD = spdi.tRCD; + ram.tRP = spdi.tRP; + ram.tRAS = spdi.tRAS; } } @@ -191,6 +192,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) spdi.slot_num = slot_idx; spdi.sku_len = 0; spdi.module_size = 0; + spdi.tCL_dec = 0; // Compute module size for symmetric & asymmetric configuration for (int sbyte_adr = 1; sbyte_adr <= 2; sbyte_adr++) { @@ -248,11 +250,16 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) sbyte = get_spd(slot_idx, (sbyte_adr * 4) + 2); cur_rank /= 1U << (((sbyte >> 5) & 3) + 2); + sbyte = get_spd(slot_idx, 234); + + // Package ranks per Channel + cur_rank *= 1U << ((sbyte >> 3) & 7); + // Add current rank to total package size spdi.module_size += cur_rank; // If not Asymmetrical, don't process the second rank - if ((get_spd(slot_idx, 234) >> 6) == 0) { + if ((sbyte >> 6) == 0) { break; } } @@ -297,27 +304,28 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) // CAS# Latency tns = (uint16_t)get_spd(slot_idx, 718 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 717 + xmp_offset); - spdi.tCL = (uint16_t)(tns/tCK + 0.5f); + spdi.tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi.tCL += spdi.tCL % 2; // if tCL is odd, round to upper even. // RAS# to CAS# Latency tns = (uint16_t)get_spd(slot_idx, 720 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 719 + xmp_offset); - spdi.tRCD = (uint16_t)(tns/tCK + 0.5f); + spdi.tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // RAS# Precharge tns = (uint16_t)get_spd(slot_idx, 722 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 721 + xmp_offset); - spdi.tRP = (uint16_t)(tns/tCK + 0.5f); + spdi.tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Active Time tns = (uint16_t)get_spd(slot_idx, 724 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 723 + xmp_offset); - spdi.tRAS = (uint16_t)(tns/tCK + 0.5f); + spdi.tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Cycle Time tns = (uint16_t)get_spd(slot_idx, 726 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 725 + xmp_offset); - spdi.tRC = (uint16_t)(tns/tCK + 0.5f); + spdi.tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; } else { // -------------------- // JEDEC Specifications @@ -326,27 +334,28 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) // CAS# Latency tns = (uint16_t)get_spd(slot_idx, 31) << 8 | (uint16_t)get_spd(slot_idx, 30); - spdi.tCL = (uint16_t)(tns/tCK + 0.5f); + spdi.tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi.tCL += spdi.tCL % 2; // RAS# to CAS# Latency tns = (uint16_t)get_spd(slot_idx, 33) << 8 | (uint16_t)get_spd(slot_idx, 32); - spdi.tRCD = (uint16_t)(tns/tCK + 0.5f); + spdi.tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // RAS# Precharge tns = (uint16_t)get_spd(slot_idx, 35) << 8 | (uint16_t)get_spd(slot_idx, 34); - spdi.tRP = (uint16_t)(tns/tCK + 0.5f); + spdi.tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Active Time tns = (uint16_t)get_spd(slot_idx, 37) << 8 | (uint16_t)get_spd(slot_idx, 36); - spdi.tRAS = (uint16_t)(tns/tCK + 0.5f); + spdi.tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Cycle Time tns = (uint16_t)get_spd(slot_idx, 39) << 8 | (uint16_t)get_spd(slot_idx, 38); - spdi.tRC = (uint16_t)(tns/tCK + 0.5f); + spdi.tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; } // Module manufacturer @@ -387,6 +396,7 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) spdi.type = "DDR4"; spdi.slot_num = slot_idx; spdi.sku_len = 0; + spdi.tCL_dec = 0; // Compute module size in MB with shifts spdi.module_size = 1U << ( @@ -400,31 +410,37 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) spdi.hasECC = (((get_spd(slot_idx, 13) >> 3) & 1) == 1); // Module max clock - float tns, tckns, ramfreq; + float tns, tCK, ramfreq, fround; if (get_spd(slot_idx, 384) == 0x0C && get_spd(slot_idx, 385) == 0x4A) { // Max XMP - tckns = (uint8_t)get_spd(slot_idx, 396) * 0.125f + - (int8_t)get_spd(slot_idx, 431) * 0.001f; - - ramfreq = 1.0f / tckns * 2.0f * 1000.0f; - - spdi.freq = (ramfreq+50)/100; - spdi.freq *= 100; + tCK = (uint8_t)get_spd(slot_idx, 396) * 0.125f + + (int8_t)get_spd(slot_idx, 431) * 0.001f; spdi.XMP = 2; } else { // Max JEDEC - tckns = (uint8_t)get_spd(slot_idx, 18) * 0.125f + - (int8_t)get_spd(slot_idx, 125) * 0.001f; - - ramfreq = 1.0f / tckns * 2.0f * 1000.0f; - spdi.freq = (uint16_t)ramfreq; + tCK = (uint8_t)get_spd(slot_idx, 18) * 0.125f + + (int8_t)get_spd(slot_idx, 125) * 0.001f; spdi.XMP = 0; } + ramfreq = 1.0f / tCK * 2.0f * 1000.0f; + + // Round DRAM Freq to nearest x00/x33/x66 + fround = ((int)(ramfreq * 0.01 + .5) / 0.01) - ramfreq; + ramfreq += fround; + + if (fround < -16.5) { + ramfreq += 33; + } else if (fround > 16.5) { + ramfreq -= 34; + } + + spdi.freq = ramfreq; + // Module Timings if (spdi.XMP == 2) { // ------------------ @@ -434,28 +450,28 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 401) * 0.125f + (int8_t)get_spd(slot_idx, 430) * 0.001f; - spdi.tCL = (uint16_t)(tns/tckns); + spdi.tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 402) * 0.125f + (int8_t)get_spd(slot_idx, 429) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 403) * 0.125f + (int8_t)get_spd(slot_idx, 428) * 0.001f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 405) * 0.125f + (int8_t)get_spd(slot_idx, 427) * 0.001f + (uint8_t)(get_spd(slot_idx, 404) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 406) * 0.125f + (uint8_t)(get_spd(slot_idx, 404) >> 4) * 32.0f; - spdi.tRC = (uint16_t)(tns/tckns); + spdi.tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); } else { // -------------------- // JEDEC Specifications @@ -464,27 +480,27 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 24) * 0.125f + (int8_t)get_spd(slot_idx, 123) * 0.001f; - spdi.tCL = (uint16_t)(tns/tckns); + spdi.tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 25) * 0.125f + (int8_t)get_spd(slot_idx, 122) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 26) * 0.125f + (int8_t)get_spd(slot_idx, 121) * 0.001f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 28) * 0.125f + (uint8_t)(get_spd(slot_idx, 27) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 29) * 0.125f + (uint8_t)(get_spd(slot_idx, 27) >> 4) * 32.0f; - spdi.tRC = (uint16_t)(tns/tckns); + spdi.tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); } // Module manufacturer @@ -526,6 +542,7 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) spdi.slot_num = slot_idx; spdi.sku_len = 0; spdi.XMP = 0; + spdi.tCL_dec = 0; // Compute module size in MB with shifts spdi.module_size = 1U << ( @@ -538,9 +555,16 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) spdi.hasECC = (((get_spd(slot_idx, 8) >> 3) & 1) == 1); uint8_t tck = get_spd(slot_idx, 12); + uint8_t tck2 = get_spd(slot_idx, 221); if (get_spd(slot_idx, 176) == 0x0C && get_spd(slot_idx, 177) == 0x4A) { tck = get_spd(slot_idx, 186); + + // Check if profile #2 is faster + if (tck2 > 5 && tck2 < tck) { + tck = tck2; + } + spdi.XMP = 1; } @@ -560,6 +584,10 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) break; case 10: spdi.freq = 1600; + // Quirk for early Kingston DDR3-1866 with XMP < 1.1 + if (spdi.XMP == 1 && get_spd(slot_idx, 181) == 0x0E) { + spdi.freq = 1866; + } break; case 9: spdi.freq = 1866; @@ -585,57 +613,57 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) // CAS# Latency tns = get_spd(slot_idx, 187); - spdi.tCL = (uint16_t)(tns/tckns); + spdi.tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = get_spd(slot_idx, 192); - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tns = get_spd(slot_idx, 191); - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time - tns = (uint16_t)(get_spd(slot_idx, 194) & 0xF0) << 4 | - get_spd(slot_idx, 195); + tns = (uint16_t)((get_spd(slot_idx, 194) & 0xF0) << 3 | + get_spd(slot_idx, 195)); ; - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time - tns = (uint16_t)(get_spd(slot_idx, 194) & 0x0F) << 8 | - get_spd(slot_idx, 196); - spdi.tRC = (uint16_t)(tns/tckns); + tns = (uint16_t)((get_spd(slot_idx, 194) & 0x0F) << 8 | + get_spd(slot_idx, 196)); + spdi.tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } else { // -------------------- // JEDEC Specifications // -------------------- tckns = (uint8_t)get_spd(slot_idx, 12) * 0.125f + - (int8_t)get_spd(slot_idx, 134) * 0.001f; + (int8_t)get_spd(slot_idx, 34) * 0.001f; // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 16) * 0.125f + (int8_t)get_spd(slot_idx, 35) * 0.001f; - spdi.tCL = (uint16_t)(tns/tckns); + spdi.tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 18) * 0.125f + (int8_t)get_spd(slot_idx, 36) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 20) * 0.125f + (int8_t)get_spd(slot_idx, 37) * 0.001f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 22) * 0.125f + (uint8_t)(get_spd(slot_idx, 21) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 23) * 0.125f + - (uint8_t)(get_spd(slot_idx, 21) >> 4) * 32.0f; - spdi.tRC = (uint16_t)(tns/tckns); + (uint8_t)(get_spd(slot_idx, 21) >> 4) * 32.0f + 1; + spdi.tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } // Module manufacturer @@ -676,6 +704,7 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) spdi.slot_num = slot_idx; spdi.sku_len = 0; spdi.XMP = 0; + spdi.tCL_dec = 0; // Compute module size in MB switch (get_spd(slot_idx, 31)) { @@ -750,23 +779,22 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) for (int shft = 0; shft < 7; shft++) { if ((tbyte >> shft) & 1) { spdi.tCL = shft; - break; } } // RAS# to CAS# Latency tbyte = get_spd(slot_idx, 111 + epp_offset); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tbyte = get_spd(slot_idx, 112 + epp_offset); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = get_spd(slot_idx, 113 + epp_offset); - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time spdi.tRC = 0; @@ -777,23 +805,22 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) for (int shft = 0; shft < 7; shft++) { if ((tbyte >> shft) & 1) { spdi.tCL = shft; - break; } } // RAS# to CAS# Latency tbyte = get_spd(slot_idx, 29); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tbyte = get_spd(slot_idx, 27); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = get_spd(slot_idx, 30); - spdi.tRAS = (uint16_t)(tns/tckns); + spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time spdi.tRC = 0; @@ -888,23 +915,29 @@ static spd_info parse_spd_ddr(uint8_t slot_idx) spdi.freq = (uint16_t)(1.0f / tckns * 1000.0f * 2.0f); // Module Timings + spdi.tCL_dec = 0; uint8_t spd_byte18 = get_spd(slot_idx, 18); for (int shft = 0; shft < 7; shft++) { if ((spd_byte18 >> shft) & 1) { - spdi.tCL = 1.0f + shft * 0.5f; // TODO: .5 CAS - break; + spdi.tCL = 1.0f + shft * 0.5f; + // Check tCL decimal (x.5 CAS) + if (shft == 1 || shft == 3 || shft == 5) { + spdi.tCL_dec = 5; + } else { + spdi.tCL_dec = 0; + } } } tns = (get_spd(slot_idx, 29) >> 2) + (get_spd(slot_idx, 29) & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); tns = (get_spd(slot_idx, 27) >> 2) + (get_spd(slot_idx, 27) & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - spdi.tRAS = (uint16_t)(get_spd(slot_idx, 30)/tckns); + spdi.tRAS = (uint16_t)((float)get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); spdi.tRC = 0; // Module manufacturer @@ -1000,6 +1033,7 @@ static spd_info parse_spd_rdram(uint8_t slot_idx) // Module Timings spdi.tCL = get_spd(slot_idx, 14); + spdi.tCL_dec = 0; spdi.tRCD = get_spd(slot_idx, 12); spdi.tRP = get_spd(slot_idx, 10); spdi.tRAS = get_spd(slot_idx, 11); @@ -1052,6 +1086,7 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) spdi.slot_num = slot_idx; spdi.sku_len = 0; spdi.XMP = 0; + spdi.tCL_dec = 0; uint8_t spd_byte3 = get_spd(slot_idx, 3) & 0x0F; // Number of Row Addresses (2 x 4 bits, upper part used if asymmetrical banking used) uint8_t spd_byte4 = get_spd(slot_idx, 4) & 0x0F; // Number of Column Addresses (2 x 4 bits, upper part used if asymmetrical banking used) @@ -1085,17 +1120,16 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) for (int shft = 0; shft < 7; shft++) { if ((spd_byte18 >> shft) & 1) { spdi.tCL = shft + 1; - break; } } tns = get_spd(slot_idx, 29); - spdi.tRCD = (uint16_t)(tns/tckns); + spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); tns = get_spd(slot_idx, 27); - spdi.tRP = (uint16_t)(tns/tckns); + spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - spdi.tRAS = (uint16_t)(get_spd(slot_idx, 30)/tckns); + spdi.tRAS = (uint16_t)(get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); spdi.tRC = 0; // Module manufacturer diff --git a/system/smbus.h b/system/smbus.h index 62d23ef..fdbbbb9 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -84,6 +84,15 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f +/** Rounding factors for timing computation + * + * These factors are used as a configurable CEIL() function + * to get the upper int from a float past a specific decimal point. + */ + +#define DDR5_ROUNDING_FACTOR 30 +#define ROUNDING_FACTOR 0.9f + struct pci_smbus_controller { unsigned vendor; unsigned device; @@ -104,6 +113,7 @@ typedef struct spd_infos { uint8_t fab_year; uint8_t fab_week; uint16_t tCL; + uint8_t tCL_dec; uint16_t tRCD; uint16_t tRP; uint16_t tRAS; @@ -113,6 +123,7 @@ typedef struct spd_infos { typedef struct ram_infos { uint16_t freq; uint16_t tCL; + uint8_t tCL_dec; uint16_t tRCD; uint16_t tRP; uint16_t tRAS; From 43b0f64ddb84b95275639bd0e6a615516836bf7d Mon Sep 17 00:00:00 2001 From: 01e3 <01e3@ans.pl> Date: Fri, 26 Aug 2022 21:21:20 -0700 Subject: [PATCH 035/113] smbus: refactor SPD SKU (part number) handling Replace SPD SKU reading code repeated multiple times across all the parse_spd_* functions with a dedicated read_sku function. Convert spd_infos.sku from len+data into classic NULL-terminated C-string. Takes the same space, but simplifies handling. Also, use char instead of uint8_t so no conversion is needed when printing. Change the way how the end of part number is handled. Stop on the first non-ASCII character and then trim all trailing spaces. This allows SKUs with two (or more) spaces inside the name to be handled properly. Finally, fix incorrect / inconsistent part number length handling, with the following end result: - parse_spd_sdram: 18 [73-90] (no change) - parse_spd_rdram: 18 [73-90] (no change) - parse_spd_ddr: 18 [73-90] (no change) - parse_spd_ddr2: 18 [73-90] (no change) - parse_spd_ddr3: 20+1=21 -> 18 [128-145] - parse_spd_ddr4: 20+1=21 -> 20 [329-348] - parse_spd_ddr5: 29+1=30 -> 30 [521-550] (technicaly no change) Before: text data bss total filename 13143 3795 18 16956 build32/system/smbus.o 11735 4359 18 16112 build64/system/smbus.o 81705 51133 13088 145926 build32/memtest_shared 79686 58109 294432 432227 build64/memtest_shared After: text data bss total filename 10784 3887 18 14689 build32/system/smbus.o 10486 4399 18 14903 build64/system/smbus.o 79353 51101 13088 143542 build32/memtest_shared 78438 58077 294432 430947 build64/memtest_shared gcc-11.3.0. --- system/smbus.c | 148 ++++++++++++++----------------------------------- system/smbus.h | 5 +- 2 files changed, 44 insertions(+), 109 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index cbfd586..6f4d08c 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -28,6 +28,7 @@ static int8_t spd_page = -1; static int8_t last_adr = -1; // Functions Prototypes +static void read_sku(char *sku, uint8_t slot_idx, uint16_t offset, uint8_t max_len); static spd_info parse_spd_rdram (uint8_t slot_idx); static spd_info parse_spd_sdram (uint8_t slot_idx); @@ -153,9 +154,8 @@ static void print_spdi(spd_info spdi, uint8_t lidx) } // Print SKU - for(i = 0; i < spdi.sku_len; i++) { - curcol = printc(LINE_SPD+lidx, i ? curcol : ++curcol, spdi.sku[i]); - } + if (*spdi.sku) + curcol = prints(LINE_SPD+lidx, curcol + 1, spdi.sku); // Check manufacturing date and print if valid. // fab_year is uint8_t and carries only the last two digits. @@ -183,6 +183,30 @@ static void print_spdi(spd_info spdi, uint8_t lidx) } } +static void read_sku(char *sku, uint8_t slot_idx, uint16_t offset, uint8_t max_len) +{ + uint8_t sku_len; + + if (max_len > SPD_SKU_LEN) + max_len = SPD_SKU_LEN; + + for (sku_len = 0; sku_len < max_len; sku_len++) { + uint8_t sku_byte = get_spd(slot_idx, offset + sku_len); + + // Stop on the first non-ASCII char + if (sku_byte < 0x20 || sku_byte > 0x7F) + break; + + sku[sku_len] = (char)sku_byte; + } + + // Trim spaces from the end + while (sku_len && sku[sku_len - 1] == 0x20) + sku_len--; + + sku[sku_len] = '\0'; +} + static spd_info parse_spd_ddr5(uint8_t slot_idx) { spd_info spdi; @@ -190,7 +214,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) spdi.isValid = false; spdi.type = "DDR5"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.module_size = 0; spdi.tCL_dec = 0; @@ -362,20 +386,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) spdi.jedec_code = (get_spd(slot_idx, 512) & 0x1F) << 8; spdi.jedec_code |= get_spd(slot_idx, 513) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j <= 29; j++) { - sku_byte = get_spd(slot_idx, 521+j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 521, 30); // Week & Date (BCD to Int) uint8_t bcd = get_spd(slot_idx, 515); @@ -395,7 +406,7 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) spdi.type = "DDR4"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.tCL_dec = 0; // Compute module size in MB with shifts @@ -507,20 +518,7 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) spdi.jedec_code = ((uint16_t)(get_spd(slot_idx, 320) & 0x1F)) << 8; spdi.jedec_code |= get_spd(slot_idx, 321) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j <= 20; j++) { - sku_byte = get_spd(slot_idx, 329+j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 329, 20); // Week & Date (BCD to Int) uint8_t bcd = get_spd(slot_idx, 323); @@ -540,7 +538,7 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) spdi.type = "DDR3"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.XMP = 0; spdi.tCL_dec = 0; @@ -670,20 +668,7 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) spdi.jedec_code = ((uint16_t)(get_spd(slot_idx, 117) & 0x1F)) << 8; spdi.jedec_code |= get_spd(slot_idx, 118) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j <= 20; j++) { - sku_byte = get_spd(slot_idx, 128+j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 128, 18); uint8_t bcd = get_spd(slot_idx, 120); spdi.fab_year = bcd - 6 * (bcd >> 4); @@ -702,7 +687,7 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) spdi.type = "DDR2"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.XMP = 0; spdi.tCL_dec = 0; @@ -837,20 +822,7 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j < 18; j++) { - sku_byte = get_spd(slot_idx, 73 + j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); spdi.fab_year = bcd - 6 * (bcd >> 4); @@ -869,7 +841,7 @@ static spd_info parse_spd_ddr(uint8_t slot_idx) spdi.type = "DDR"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.XMP = 0; // Compute module size in MB @@ -951,20 +923,7 @@ static spd_info parse_spd_ddr(uint8_t slot_idx) spdi.jedec_code = (contcode - 64) << 8; spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j < 18; j++) { - sku_byte = get_spd(slot_idx, 73 + j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); spdi.fab_year = bcd - 6 * (bcd >> 4); @@ -984,7 +943,7 @@ static spd_info parse_spd_rdram(uint8_t slot_idx) spdi.isValid = false; spdi.type = "RDRAM"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.XMP = 0; // Compute module size in MB @@ -1050,20 +1009,7 @@ static spd_info parse_spd_rdram(uint8_t slot_idx) spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j < 18; j++) { - sku_byte = get_spd(slot_idx, 73 + j); - - if ((sku_byte <= 0x20 || sku_byte == 0xFF) && j > 0 - && (spdi.sku[j - 1] <= 0x20 || spdi.sku[j - 1] == 0xFF)) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); spdi.fab_year = bcd - 6 * (bcd >> 4); @@ -1084,7 +1030,7 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) spdi.type = "SDRAM"; spdi.slot_num = slot_idx; - spdi.sku_len = 0; + spdi.sku[0] = '\0'; spdi.XMP = 0; spdi.tCL_dec = 0; @@ -1143,19 +1089,7 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - // Module SKU - uint8_t sku_byte; - for (int j = 0; j < 18; j++) { - sku_byte = get_spd(slot_idx, 73 + j); - - if (sku_byte <= 0x20 && j > 0 && spdi.sku[j - 1] <= 0x20) { - spdi.sku_len--; - break; - } else { - spdi.sku[j] = sku_byte; - spdi.sku_len++; - } - } + read_sku(spdi.sku, slot_idx, 73, 18); bcd = get_spd(slot_idx, 93); spdi.fab_year = bcd - 6 * (bcd >> 4); diff --git a/system/smbus.h b/system/smbus.h index fdbbbb9..de7883d 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -93,6 +93,8 @@ #define DDR5_ROUNDING_FACTOR 30 #define ROUNDING_FACTOR 0.9f +#define SPD_SKU_LEN 32 + struct pci_smbus_controller { unsigned vendor; unsigned device; @@ -105,8 +107,7 @@ typedef struct spd_infos { uint16_t jedec_code; uint32_t module_size; char *type; - uint8_t sku[32]; - uint8_t sku_len; + char sku[SPD_SKU_LEN + 1]; uint8_t XMP; uint16_t freq; bool hasECC; From 5686da4b1d8e40e7f4dabf6768db3adc2aa8699e Mon Sep 17 00:00:00 2001 From: 01e3 <01e3@ans.pl> Date: Fri, 26 Aug 2022 23:16:12 -0700 Subject: [PATCH 036/113] smbus: optimize parse_spd_* functions Convert calling / return convention for all parse_spd_* functions from returning the value of spd_info structure to updating the received reference. This also allows to move / remove some boilerplate code, like initializing spdi/curspd and setting slot_num. At the end, print_smbus_startup_info wants curspd to be updated, so we can do this in a more efficient way. Before: text data bss total filename 10784 3887 18 14689 build32/system/smbus.o 10486 4399 18 14903 build64/system/smbus.o 79353 51101 13088 143542 build32/memtest_shared 78438 58077 294432 430947 build64/memtest_shared After: text data bss total filename 10379 3871 18 14268 build32/system/smbus.o 9833 4399 18 14250 build64/system/smbus.o 78937 51101 13088 143126 build32/memtest_shared 77782 58077 294432 430291 build64/memtest_shared gcc-11.3.0. --- system/smbus.c | 480 +++++++++++++++++++++---------------------------- 1 file changed, 208 insertions(+), 272 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 6f4d08c..2aeca20 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -7,6 +7,7 @@ #include "tsc.h" #include "pci.h" #include "unistd.h" +#include "string.h" #include "cpuinfo.h" #include "smbus.h" @@ -30,13 +31,13 @@ static int8_t last_adr = -1; // Functions Prototypes static void read_sku(char *sku, uint8_t slot_idx, uint16_t offset, uint8_t max_len); -static spd_info parse_spd_rdram (uint8_t slot_idx); -static spd_info parse_spd_sdram (uint8_t slot_idx); -static spd_info parse_spd_ddr (uint8_t slot_idx); -static spd_info parse_spd_ddr2 (uint8_t slot_idx); -static spd_info parse_spd_ddr3 (uint8_t slot_idx); -static spd_info parse_spd_ddr4 (uint8_t slot_idx); -static spd_info parse_spd_ddr5 (uint8_t slot_idx); +static void parse_spd_rdram (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_sdram (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_ddr (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_ddr2 (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_ddr3 (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_ddr4 (spd_info *spdi, uint8_t slot_idx); +static void parse_spd_ddr5 (spd_info *spdi, uint8_t slot_idx); static void print_spdi(spd_info spdi, uint8_t lidx); static bool setup_smb_controller(void); @@ -71,32 +72,35 @@ void print_smbus_startup_info(void) for (spdidx = 0; spdidx < MAX_SPD_SLOT; spdidx++) { + memset(&curspd, 0, sizeof(curspd)); + curspd.slot_num = spdidx; + if (get_spd(spdidx, 0) != 0xFF) { switch(get_spd(spdidx, 2)) { default: continue; case 0x12: // DDR5 - curspd = parse_spd_ddr5(spdidx); + parse_spd_ddr5(&curspd, spdidx); break; case 0x0C: // DDR4 - curspd = parse_spd_ddr4(spdidx); + parse_spd_ddr4(&curspd, spdidx); break; case 0x0B: // DDR3 - curspd = parse_spd_ddr3(spdidx); + parse_spd_ddr3(&curspd, spdidx); break; case 0x08: // DDR2 - curspd = parse_spd_ddr2(spdidx); + parse_spd_ddr2(&curspd, spdidx); break; case 0x07: // DDR - curspd = parse_spd_ddr(spdidx); + parse_spd_ddr(&curspd, spdidx); break; case 0x04: // SDRAM - curspd = parse_spd_sdram(spdidx); + parse_spd_sdram(&curspd, spdidx); break; case 0x01: // RAMBUS - RDRAM if (get_spd(spdidx, 1) == 8) { - curspd = parse_spd_rdram(spdidx); + parse_spd_rdram(&curspd, spdidx); } break; } @@ -207,16 +211,9 @@ static void read_sku(char *sku, uint8_t slot_idx, uint16_t offset, uint8_t max_l sku[sku_len] = '\0'; } -static spd_info parse_spd_ddr5(uint8_t slot_idx) +static void parse_spd_ddr5(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.isValid = false; - spdi.type = "DDR5"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.module_size = 0; - spdi.tCL_dec = 0; + spdi->type = "DDR5"; // Compute module size for symmetric & asymmetric configuration for (int sbyte_adr = 1; sbyte_adr <= 2; sbyte_adr++) { @@ -260,7 +257,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) } sbyte = get_spd(slot_idx, 235); - spdi.hasECC = (((sbyte >> 3) & 3) > 0); + spdi->hasECC = (((sbyte >> 3) & 3) > 0); // Channels per DIMM if (((sbyte >> 5) & 3) == 1) { @@ -280,7 +277,7 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) cur_rank *= 1U << ((sbyte >> 3) & 7); // Add current rank to total package size - spdi.module_size += cur_rank; + spdi->module_size += cur_rank; // If not Asymmetrical, don't process the second rank if ((sbyte >> 6) == 0) { @@ -292,9 +289,9 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) uint16_t tCK, tCKtmp, tns; int xmp_offset = 0; - spdi.XMP = ((get_spd(slot_idx, 640) == 0x0C && get_spd(slot_idx, 641) == 0x4A)) ? 3 : 0; + spdi->XMP = ((get_spd(slot_idx, 640) == 0x0C && get_spd(slot_idx, 641) == 0x4A)) ? 3 : 0; - if (spdi.XMP == 3) { + if (spdi->XMP == 3) { // XMP 3.0 (enumerate all profiles to find the fastest) tCK = 0; for (int offset = 0; offset < 3*64; offset += 64) { @@ -313,14 +310,14 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) } if (tCK == 0) { - return spdi; + return; } - spdi.freq = (float)(1.0f / tCK * 2.0f * 1000.0f * 1000.0f); - spdi.freq = (spdi.freq + 50) / 100 * 100; + spdi->freq = (float)(1.0f / tCK * 2.0f * 1000.0f * 1000.0f); + spdi->freq = (spdi->freq + 50) / 100 * 100; // Module Timings - if (spdi.XMP == 3) { + if (spdi->XMP == 3) { // ------------------ // XMP Specifications // ------------------ @@ -328,28 +325,28 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) // CAS# Latency tns = (uint16_t)get_spd(slot_idx, 718 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 717 + xmp_offset); - spdi.tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; - spdi.tCL += spdi.tCL % 2; // if tCL is odd, round to upper even. + spdi->tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tCL += spdi->tCL % 2; // if tCL is odd, round to upper even. // RAS# to CAS# Latency tns = (uint16_t)get_spd(slot_idx, 720 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 719 + xmp_offset); - spdi.tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // RAS# Precharge tns = (uint16_t)get_spd(slot_idx, 722 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 721 + xmp_offset); - spdi.tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Active Time tns = (uint16_t)get_spd(slot_idx, 724 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 723 + xmp_offset); - spdi.tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Cycle Time tns = (uint16_t)get_spd(slot_idx, 726 + xmp_offset) << 8 | (uint16_t)get_spd(slot_idx, 725 + xmp_offset); - spdi.tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; } else { // -------------------- // JEDEC Specifications @@ -358,67 +355,60 @@ static spd_info parse_spd_ddr5(uint8_t slot_idx) // CAS# Latency tns = (uint16_t)get_spd(slot_idx, 31) << 8 | (uint16_t)get_spd(slot_idx, 30); - spdi.tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; - spdi.tCL += spdi.tCL % 2; + spdi->tCL = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tCL += spdi->tCL % 2; // RAS# to CAS# Latency tns = (uint16_t)get_spd(slot_idx, 33) << 8 | (uint16_t)get_spd(slot_idx, 32); - spdi.tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRCD = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // RAS# Precharge tns = (uint16_t)get_spd(slot_idx, 35) << 8 | (uint16_t)get_spd(slot_idx, 34); - spdi.tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRP = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Active Time tns = (uint16_t)get_spd(slot_idx, 37) << 8 | (uint16_t)get_spd(slot_idx, 36); - spdi.tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRAS = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; // Row Cycle Time tns = (uint16_t)get_spd(slot_idx, 39) << 8 | (uint16_t)get_spd(slot_idx, 38); - spdi.tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; + spdi->tRC = (tns + tCK - DDR5_ROUNDING_FACTOR) / tCK; } // Module manufacturer - spdi.jedec_code = (get_spd(slot_idx, 512) & 0x1F) << 8; - spdi.jedec_code |= get_spd(slot_idx, 513) & 0x7F; + spdi->jedec_code = (get_spd(slot_idx, 512) & 0x1F) << 8; + spdi->jedec_code |= get_spd(slot_idx, 513) & 0x7F; - read_sku(spdi.sku, slot_idx, 521, 30); + read_sku(spdi->sku, slot_idx, 521, 30); // Week & Date (BCD to Int) uint8_t bcd = get_spd(slot_idx, 515); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 516); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_ddr4(uint8_t slot_idx) +static void parse_spd_ddr4(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.type = "DDR4"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.tCL_dec = 0; + spdi->type = "DDR4"; // Compute module size in MB with shifts - spdi.module_size = 1U << ( - ((get_spd(slot_idx, 4) & 0xF) + 5) + // Total SDRAM capacity: (256 Mbits << byte4[3:0] with an oddity for values >= 8) / 1 KB - ((get_spd(slot_idx, 13) & 0x7) + 3) - // Primary Bus Width: 8 << byte13[2:0] - ((get_spd(slot_idx, 12) & 0x7) + 2) + // SDRAM Device Width: 4 << byte12[2:0] - ((get_spd(slot_idx, 12) >> 3) & 0x7) + // Number of Ranks: byte12[5:3] - ((get_spd(slot_idx, 6) >> 4) & 0x7) // Die count - 1: byte6[6:4] - ); + spdi->module_size = 1U << ( + ((get_spd(slot_idx, 4) & 0xF) + 5) + // Total SDRAM capacity: (256 Mbits << byte4[3:0] with an oddity for values >= 8) / 1 KB + ((get_spd(slot_idx, 13) & 0x7) + 3) - // Primary Bus Width: 8 << byte13[2:0] + ((get_spd(slot_idx, 12) & 0x7) + 2) + // SDRAM Device Width: 4 << byte12[2:0] + ((get_spd(slot_idx, 12) >> 3) & 0x7) + // Number of Ranks: byte12[5:3] + ((get_spd(slot_idx, 6) >> 4) & 0x7) // Die count - 1: byte6[6:4] + ); - spdi.hasECC = (((get_spd(slot_idx, 13) >> 3) & 1) == 1); + spdi->hasECC = (((get_spd(slot_idx, 13) >> 3) & 1) == 1); // Module max clock float tns, tCK, ramfreq, fround; @@ -428,14 +418,12 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) tCK = (uint8_t)get_spd(slot_idx, 396) * 0.125f + (int8_t)get_spd(slot_idx, 431) * 0.001f; - spdi.XMP = 2; + spdi->XMP = 2; } else { // Max JEDEC tCK = (uint8_t)get_spd(slot_idx, 18) * 0.125f + (int8_t)get_spd(slot_idx, 125) * 0.001f; - - spdi.XMP = 0; } ramfreq = 1.0f / tCK * 2.0f * 1000.0f; @@ -450,10 +438,10 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) ramfreq -= 34; } - spdi.freq = ramfreq; + spdi->freq = ramfreq; // Module Timings - if (spdi.XMP == 2) { + if (spdi->XMP == 2) { // ------------------ // XMP Specifications // ------------------ @@ -461,28 +449,28 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 401) * 0.125f + (int8_t)get_spd(slot_idx, 430) * 0.001f; - spdi.tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 402) * 0.125f + (int8_t)get_spd(slot_idx, 429) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 403) * 0.125f + (int8_t)get_spd(slot_idx, 428) * 0.001f; - spdi.tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 405) * 0.125f + (int8_t)get_spd(slot_idx, 427) * 0.001f + (uint8_t)(get_spd(slot_idx, 404) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 406) * 0.125f + (uint8_t)(get_spd(slot_idx, 404) >> 4) * 32.0f; - spdi.tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); } else { // -------------------- // JEDEC Specifications @@ -491,66 +479,58 @@ static spd_info parse_spd_ddr4(uint8_t slot_idx) // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 24) * 0.125f + (int8_t)get_spd(slot_idx, 123) * 0.001f; - spdi.tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tCL = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 25) * 0.125f + (int8_t)get_spd(slot_idx, 122) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 26) * 0.125f + (int8_t)get_spd(slot_idx, 121) * 0.001f; - spdi.tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 28) * 0.125f + (uint8_t)(get_spd(slot_idx, 27) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRAS = (uint16_t)(tns/tCK + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 29) * 0.125f + (uint8_t)(get_spd(slot_idx, 27) >> 4) * 32.0f; - spdi.tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); + spdi->tRC = (uint16_t)(tns/tCK + ROUNDING_FACTOR); } // Module manufacturer - spdi.jedec_code = ((uint16_t)(get_spd(slot_idx, 320) & 0x1F)) << 8; - spdi.jedec_code |= get_spd(slot_idx, 321) & 0x7F; + spdi->jedec_code = ((uint16_t)(get_spd(slot_idx, 320) & 0x1F)) << 8; + spdi->jedec_code |= get_spd(slot_idx, 321) & 0x7F; - read_sku(spdi.sku, slot_idx, 329, 20); + read_sku(spdi->sku, slot_idx, 329, 20); // Week & Date (BCD to Int) uint8_t bcd = get_spd(slot_idx, 323); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 324); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_ddr3(uint8_t slot_idx) +static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.type = "DDR3"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.XMP = 0; - spdi.tCL_dec = 0; + spdi->type = "DDR3"; // Compute module size in MB with shifts - spdi.module_size = 1U << ( - ((get_spd(slot_idx, 4) & 0xF) + 5) + // Total SDRAM capacity: (256 Mbits << byte4[3:0]) / 1 KB - ((get_spd(slot_idx, 8) & 0x7) + 3) - // Primary Bus Width: 8 << byte8[2:0] - ((get_spd(slot_idx, 7) & 0x7) + 2) + // SDRAM Device Width: 4 << byte7[2:0] - ((get_spd(slot_idx, 7) >> 3) & 0x7) // Number of Ranks: byte7[5:3] - ); + spdi->module_size = 1U << ( + ((get_spd(slot_idx, 4) & 0xF) + 5) + // Total SDRAM capacity: (256 Mbits << byte4[3:0]) / 1 KB + ((get_spd(slot_idx, 8) & 0x7) + 3) - // Primary Bus Width: 8 << byte8[2:0] + ((get_spd(slot_idx, 7) & 0x7) + 2) + // SDRAM Device Width: 4 << byte7[2:0] + ((get_spd(slot_idx, 7) >> 3) & 0x7) // Number of Ranks: byte7[5:3] + ); - spdi.hasECC = (((get_spd(slot_idx, 8) >> 3) & 1) == 1); + spdi->hasECC = (((get_spd(slot_idx, 8) >> 3) & 1) == 1); uint8_t tck = get_spd(slot_idx, 12); uint8_t tck2 = get_spd(slot_idx, 221); @@ -563,47 +543,47 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) tck = tck2; } - spdi.XMP = 1; + spdi->XMP = 1; } // Module jedec speed switch (tck) { default: - spdi.freq = 0; + spdi->freq = 0; break; case 20: - spdi.freq = 800; + spdi->freq = 800; break; case 15: - spdi.freq = 1066; + spdi->freq = 1066; break; case 12: - spdi.freq = 1333; + spdi->freq = 1333; break; case 10: - spdi.freq = 1600; + spdi->freq = 1600; // Quirk for early Kingston DDR3-1866 with XMP < 1.1 - if (spdi.XMP == 1 && get_spd(slot_idx, 181) == 0x0E) { - spdi.freq = 1866; + if (spdi->XMP == 1 && get_spd(slot_idx, 181) == 0x0E) { + spdi->freq = 1866; } break; case 9: - spdi.freq = 1866; + spdi->freq = 1866; break; case 8: - spdi.freq = 2133; + spdi->freq = 2133; break; case 7: - spdi.freq = 2400; + spdi->freq = 2400; break; case 6: - spdi.freq = 2666; + spdi->freq = 2666; break; } // Module Timings float tckns, tns; - if (spdi.XMP == 1) { + if (spdi->XMP == 1) { // ------------------ // XMP Specifications // ------------------ @@ -611,26 +591,26 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) // CAS# Latency tns = get_spd(slot_idx, 187); - spdi.tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = get_spd(slot_idx, 192); - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tns = get_spd(slot_idx, 191); - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = (uint16_t)((get_spd(slot_idx, 194) & 0xF0) << 3 | get_spd(slot_idx, 195)); ; - spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time tns = (uint16_t)((get_spd(slot_idx, 194) & 0x0F) << 8 | get_spd(slot_idx, 196)); - spdi.tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } else { // -------------------- // JEDEC Specifications @@ -641,88 +621,80 @@ static spd_info parse_spd_ddr3(uint8_t slot_idx) // CAS# Latency tns = (uint8_t)get_spd(slot_idx, 16) * 0.125f + (int8_t)get_spd(slot_idx, 35) * 0.001f; - spdi.tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = (uint8_t)get_spd(slot_idx, 18) * 0.125f + (int8_t)get_spd(slot_idx, 36) * 0.001f; - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tns = (uint8_t)get_spd(slot_idx, 20) * 0.125f + (int8_t)get_spd(slot_idx, 37) * 0.001f; - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = (uint8_t)get_spd(slot_idx, 22) * 0.125f + (uint8_t)(get_spd(slot_idx, 21) & 0x0F) * 32.0f; - spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time tns = (uint8_t)get_spd(slot_idx, 23) * 0.125f + (uint8_t)(get_spd(slot_idx, 21) >> 4) * 32.0f + 1; - spdi.tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } // Module manufacturer - spdi.jedec_code = ((uint16_t)(get_spd(slot_idx, 117) & 0x1F)) << 8; - spdi.jedec_code |= get_spd(slot_idx, 118) & 0x7F; + spdi->jedec_code = ((uint16_t)(get_spd(slot_idx, 117) & 0x1F)) << 8; + spdi->jedec_code |= get_spd(slot_idx, 118) & 0x7F; - read_sku(spdi.sku, slot_idx, 128, 18); + read_sku(spdi->sku, slot_idx, 128, 18); uint8_t bcd = get_spd(slot_idx, 120); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 121); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_ddr2(uint8_t slot_idx) +static void parse_spd_ddr2(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.type = "DDR2"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.XMP = 0; - spdi.tCL_dec = 0; + spdi->type = "DDR2"; // Compute module size in MB switch (get_spd(slot_idx, 31)) { case 1: - spdi.module_size = 1024; + spdi->module_size = 1024; break; case 2: - spdi.module_size = 2048; + spdi->module_size = 2048; break; case 4: - spdi.module_size = 4096; + spdi->module_size = 4096; break; case 8: - spdi.module_size = 8192; + spdi->module_size = 8192; break; case 16: - spdi.module_size = 16384; + spdi->module_size = 16384; break; case 32: - spdi.module_size = 128; + spdi->module_size = 128; break; case 64: - spdi.module_size = 256; + spdi->module_size = 256; break; default: case 128: - spdi.module_size = 512; + spdi->module_size = 512; break; } - spdi.module_size *= (get_spd(slot_idx, 5) & 7) + 1; + spdi->module_size *= (get_spd(slot_idx, 5) & 7) + 1; - spdi.hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); + spdi->hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); float tckns, tns; uint8_t tbyte; @@ -732,7 +704,7 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) if (get_spd(slot_idx, 99) == 0x6D && get_spd(slot_idx, 102) == 0xB1) { epp_offset = (get_spd(slot_idx, 103) & 0x3) * 12; tbyte = get_spd(slot_idx, 109 + epp_offset); - spdi.XMP = 20; + spdi->XMP = 20; } else { tbyte = get_spd(slot_idx, 9); } @@ -755,60 +727,54 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) tckns += 0.875f; } - spdi.freq = (float)(1.0f / tckns * 1000.0f * 2.0f); + spdi->freq = (float)(1.0f / tckns * 1000.0f * 2.0f); - if (spdi.XMP == 20) { + if (spdi->XMP == 20) { // Module Timings (EPP) // CAS# Latency tbyte = get_spd(slot_idx, 110 + epp_offset); for (int shft = 0; shft < 7; shft++) { if ((tbyte >> shft) & 1) { - spdi.tCL = shft; + spdi->tCL = shft; } } // RAS# to CAS# Latency tbyte = get_spd(slot_idx, 111 + epp_offset); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tbyte = get_spd(slot_idx, 112 + epp_offset); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = get_spd(slot_idx, 113 + epp_offset); - spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - - // Row Cycle Time - spdi.tRC = 0; + spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } else { // Module Timings (JEDEC) // CAS# Latency tbyte = get_spd(slot_idx, 18); for (int shft = 0; shft < 7; shft++) { if ((tbyte >> shft) & 1) { - spdi.tCL = shft; + spdi->tCL = shft; } } // RAS# to CAS# Latency tbyte = get_spd(slot_idx, 29); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge tbyte = get_spd(slot_idx, 27); tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time tns = get_spd(slot_idx, 30); - spdi.tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - - // Row Cycle Time - spdi.tRC = 0; + spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } // Module manufacturer @@ -819,98 +785,89 @@ static spd_info parse_spd_ddr2(uint8_t slot_idx) } } - spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; - spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; + spdi->jedec_code = ((uint16_t)(contcode - 64)) << 8; + spdi->jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - read_sku(spdi.sku, slot_idx, 73, 18); + read_sku(spdi->sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 94); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_ddr(uint8_t slot_idx) +static void parse_spd_ddr(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.type = "DDR"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.XMP = 0; + spdi->type = "DDR"; // Compute module size in MB switch (get_spd(slot_idx, 31)) { case 1: - spdi.module_size = 1024; + spdi->module_size = 1024; break; case 2: - spdi.module_size = 2048; + spdi->module_size = 2048; break; case 4: - spdi.module_size = 4096; + spdi->module_size = 4096; break; case 8: - spdi.module_size = 32; + spdi->module_size = 32; break; case 16: - spdi.module_size = 64; + spdi->module_size = 64; break; case 32: - spdi.module_size = 128; + spdi->module_size = 128; break; case 64: - spdi.module_size = 256; + spdi->module_size = 256; break; case 128: - spdi.module_size = 512; + spdi->module_size = 512; break; default: // we don't support asymmetric banking - spdi.module_size = 0; + spdi->module_size = 0; break; } - spdi.module_size *= get_spd(slot_idx, 5); + spdi->module_size *= get_spd(slot_idx, 5); - spdi.hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); + spdi->hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); // Module speed float tns, tckns; uint8_t spd_byte9 = get_spd(slot_idx, 9); tckns = (spd_byte9 >> 4) + (spd_byte9 & 0xF) * 0.1f; - spdi.freq = (uint16_t)(1.0f / tckns * 1000.0f * 2.0f); + spdi->freq = (uint16_t)(1.0f / tckns * 1000.0f * 2.0f); // Module Timings - spdi.tCL_dec = 0; uint8_t spd_byte18 = get_spd(slot_idx, 18); for (int shft = 0; shft < 7; shft++) { if ((spd_byte18 >> shft) & 1) { - spdi.tCL = 1.0f + shft * 0.5f; + spdi->tCL = 1.0f + shft * 0.5f; // Check tCL decimal (x.5 CAS) if (shft == 1 || shft == 3 || shft == 5) { - spdi.tCL_dec = 5; + spdi->tCL_dec = 5; } else { - spdi.tCL_dec = 0; + spdi->tCL_dec = 0; } } } tns = (get_spd(slot_idx, 29) >> 2) + (get_spd(slot_idx, 29) & 0x3) * 0.25f; - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); tns = (get_spd(slot_idx, 27) >> 2) + (get_spd(slot_idx, 27) & 0x3) * 0.25f; - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - spdi.tRAS = (uint16_t)((float)get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); - spdi.tRC = 0; + spdi->tRAS = (uint16_t)((float)get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); // Module manufacturer uint8_t contcode; @@ -920,83 +877,73 @@ static spd_info parse_spd_ddr(uint8_t slot_idx) } } - spdi.jedec_code = (contcode - 64) << 8; - spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; + spdi->jedec_code = (contcode - 64) << 8; + spdi->jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - read_sku(spdi.sku, slot_idx, 73, 18); + read_sku(spdi->sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 94); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_rdram(uint8_t slot_idx) +static void parse_spd_rdram(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - - spdi.isValid = false; - spdi.type = "RDRAM"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.XMP = 0; + spdi->type = "RDRAM"; // Compute module size in MB uint8_t tbyte = get_spd(slot_idx, 5); switch(tbyte) { case 0x84: - spdi.module_size = 8; + spdi->module_size = 8; break; case 0xC5: - spdi.module_size = 16; + spdi->module_size = 16; break; default: - return spdi; + return; } - spdi.module_size *= get_spd(slot_idx, 99); + spdi->module_size *= get_spd(slot_idx, 99); tbyte = get_spd(slot_idx, 4); if (tbyte > 0x96) { - spdi.module_size *= 1 + (((tbyte & 0xF0) >> 4) - 9) + ((tbyte & 0xF) - 6); + spdi->module_size *= 1 + (((tbyte & 0xF0) >> 4) - 9) + ((tbyte & 0xF) - 6); } - spdi.hasECC = (get_spd(slot_idx, 100) == 0x12) ? true : false; + spdi->hasECC = (get_spd(slot_idx, 100) == 0x12) ? true : false; // Module speed tbyte = get_spd(slot_idx, 15); switch(tbyte) { case 0x1A: - spdi.freq = 600; + spdi->freq = 600; break; case 0x15: - spdi.freq = 711; + spdi->freq = 711; break; case 0x13: - spdi.freq = 800; + spdi->freq = 800; break; case 0xe: - spdi.freq = 1066; + spdi->freq = 1066; break; case 0xc: - spdi.freq = 1200; + spdi->freq = 1200; break; default: - return spdi; + return; } // Module Timings - spdi.tCL = get_spd(slot_idx, 14); - spdi.tCL_dec = 0; - spdi.tRCD = get_spd(slot_idx, 12); - spdi.tRP = get_spd(slot_idx, 10); - spdi.tRAS = get_spd(slot_idx, 11); - spdi.tRC = 0; + spdi->tCL = get_spd(slot_idx, 14); + spdi->tRCD = get_spd(slot_idx, 12); + spdi->tRP = get_spd(slot_idx, 10); + spdi->tRAS = get_spd(slot_idx, 11); // Module manufacturer uint8_t contcode; @@ -1006,33 +953,25 @@ static spd_info parse_spd_rdram(uint8_t slot_idx) } } - spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; - spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; + spdi->jedec_code = ((uint16_t)(contcode - 64)) << 8; + spdi->jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - read_sku(spdi.sku, slot_idx, 73, 18); + read_sku(spdi->sku, slot_idx, 73, 18); uint8_t bcd = get_spd(slot_idx, 93); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 94); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } -static spd_info parse_spd_sdram(uint8_t slot_idx) +static void parse_spd_sdram(spd_info *spdi, uint8_t slot_idx) { - spd_info spdi; - uint8_t bcd; - spdi.type = "SDRAM"; - spdi.slot_num = slot_idx; - spdi.sku[0] = '\0'; - spdi.XMP = 0; - spdi.tCL_dec = 0; + spdi->type = "SDRAM"; uint8_t spd_byte3 = get_spd(slot_idx, 3) & 0x0F; // Number of Row Addresses (2 x 4 bits, upper part used if asymmetrical banking used) uint8_t spd_byte4 = get_spd(slot_idx, 4) & 0x0F; // Number of Column Addresses (2 x 4 bits, upper part used if asymmetrical banking used) @@ -1047,36 +986,35 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) && (spd_byte5 <= 8) && (spd_byte17 <= 8) ) { - spdi.module_size = (1U << (spd_byte3 + spd_byte4 - 17)) * ((uint16_t)spd_byte5 * spd_byte17); + spdi->module_size = (1U << (spd_byte3 + spd_byte4 - 17)) * ((uint16_t)spd_byte5 * spd_byte17); } else { - spdi.module_size = 0; + spdi->module_size = 0; } - spdi.hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); + spdi->hasECC = ((get_spd(slot_idx, 11) >> 1) == 1); // Module speed float tns, tckns; uint8_t spd_byte9 = get_spd(slot_idx, 9); tckns = (spd_byte9 >> 4) + (spd_byte9 & 0xF) * 0.1f; - spdi.freq = (uint16_t)(1000.0f / tckns); + spdi->freq = (uint16_t)(1000.0f / tckns); // Module Timings uint8_t spd_byte18 = get_spd(slot_idx, 18); for (int shft = 0; shft < 7; shft++) { if ((spd_byte18 >> shft) & 1) { - spdi.tCL = shft + 1; + spdi->tCL = shft + 1; } } tns = get_spd(slot_idx, 29); - spdi.tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); tns = get_spd(slot_idx, 27); - spdi.tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); - spdi.tRAS = (uint16_t)(get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); - spdi.tRC = 0; + spdi->tRAS = (uint16_t)(get_spd(slot_idx, 30)/tckns + ROUNDING_FACTOR); // Module manufacturer uint8_t contcode; @@ -1086,20 +1024,18 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) } } - spdi.jedec_code = ((uint16_t)(contcode - 64)) << 8; - spdi.jedec_code |= get_spd(slot_idx, contcode) & 0x7F; + spdi->jedec_code = ((uint16_t)(contcode - 64)) << 8; + spdi->jedec_code |= get_spd(slot_idx, contcode) & 0x7F; - read_sku(spdi.sku, slot_idx, 73, 18); + read_sku(spdi->sku, slot_idx, 73, 18); bcd = get_spd(slot_idx, 93); - spdi.fab_year = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd - 6 * (bcd >> 4); bcd = get_spd(slot_idx, 94); - spdi.fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_week = bcd - 6 * (bcd >> 4); - spdi.isValid = true; - - return spdi; + spdi->isValid = true; } From 540270513f7ab77071a9ac675aa9a2cfbfa8bb35 Mon Sep 17 00:00:00 2001 From: 01e3 <01e3@ans.pl> Date: Sat, 20 Aug 2022 20:45:05 -0700 Subject: [PATCH 037/113] smbus: introduce and use bcd_to_ui8 helper function Introduce bcd_to_ui8 for converting BCD into uint8_t. Currently, smbus.c is the only user of this code so I placed it there. Once (if?) there are more, we may want to move it to a dedicated ".h" file. Replace all BCD conversion in smbus.c with a call to bcd_to_ui8(). No change in the binary output. --- system/smbus.c | 58 +++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 2aeca20..fc8c8eb 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -54,6 +54,11 @@ 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 inline uint8_t bcd_to_ui8(uint8_t bcd) +{ + return bcd - 6 * (bcd >> 4); +} + void print_smbus_startup_info(void) { uint8_t spdidx = 0, spd_line_idx = 0; @@ -385,12 +390,8 @@ static void parse_spd_ddr5(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 521, 30); - // Week & Date (BCD to Int) - uint8_t bcd = get_spd(slot_idx, 515); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 516); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 515)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 516)); spdi->isValid = true; } @@ -508,12 +509,8 @@ static void parse_spd_ddr4(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 329, 20); - // Week & Date (BCD to Int) - uint8_t bcd = get_spd(slot_idx, 323); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 324); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 323)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 324)); spdi->isValid = true; } @@ -650,11 +647,8 @@ static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 128, 18); - uint8_t bcd = get_spd(slot_idx, 120); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 121); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 120)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 121)); spdi->isValid = true; } @@ -790,11 +784,8 @@ static void parse_spd_ddr2(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 73, 18); - uint8_t bcd = get_spd(slot_idx, 93); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 94); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); spdi->isValid = true; } @@ -882,11 +873,8 @@ static void parse_spd_ddr(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 73, 18); - uint8_t bcd = get_spd(slot_idx, 93); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 94); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); spdi->isValid = true; } @@ -958,19 +946,14 @@ static void parse_spd_rdram(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 73, 18); - uint8_t bcd = get_spd(slot_idx, 93); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 94); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); spdi->isValid = true; } static void parse_spd_sdram(spd_info *spdi, uint8_t slot_idx) { - uint8_t bcd; - spdi->type = "SDRAM"; uint8_t spd_byte3 = get_spd(slot_idx, 3) & 0x0F; // Number of Row Addresses (2 x 4 bits, upper part used if asymmetrical banking used) @@ -1029,11 +1012,8 @@ static void parse_spd_sdram(spd_info *spdi, uint8_t slot_idx) read_sku(spdi->sku, slot_idx, 73, 18); - bcd = get_spd(slot_idx, 93); - spdi->fab_year = bcd - 6 * (bcd >> 4); - - bcd = get_spd(slot_idx, 94); - spdi->fab_week = bcd - 6 * (bcd >> 4); + spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); + spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); spdi->isValid = true; } From 6799bfba3cf89f7faac74454f4081d673d973f06 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 29 Aug 2022 01:59:36 +0200 Subject: [PATCH 038/113] Fix timings decoding issues with DDR3 XMP Modules. Add quirks for early modules based on XMP Draft --- system/jedec_id.h | 2 +- system/smbus.c | 58 +++++++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/system/jedec_id.h b/system/jedec_id.h index 6b280c9..8e4ec90 100644 --- a/system/jedec_id.h +++ b/system/jedec_id.h @@ -742,7 +742,7 @@ static const struct spd_jedec_manufacturer jep106[] = { // { 0x055F, "Connect One Ltd" }, // { 0x0560, "Opulan Technologies" }, // { 0x0561, "Septentrio NV" }, -// { 0x0562, "Goldenmars Technology Inc" }, + { 0x0562, "Goldenmars" }, { 0x0563, "Kreton Corp." }, // { 0x0564, "Cochlear Ltd" }, // { 0x0565, "Altair Semiconductor" }, diff --git a/system/smbus.c b/system/smbus.c index fc8c8eb..333b7f7 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -559,10 +559,6 @@ static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) break; case 10: spdi->freq = 1600; - // Quirk for early Kingston DDR3-1866 with XMP < 1.1 - if (spdi->XMP == 1 && get_spd(slot_idx, 181) == 0x0E) { - spdi->freq = 1866; - } break; case 9: spdi->freq = 1866; @@ -578,65 +574,87 @@ static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) break; } + // Module Timings - float tckns, tns; + float tckns, tns, mtb; + if (spdi->XMP == 1) { // ------------------ // XMP Specifications // ------------------ - tckns = get_spd(slot_idx, 186); + float mtb_dividend = get_spd(slot_idx, 180); + float mtb_divisor = get_spd(slot_idx, 181); + + mtb = (mtb_divisor == 0) ? 0.125f : mtb_dividend / mtb_divisor; + + tckns = (float)get_spd(slot_idx, 186); + + // XMP Draft with non-standard MTB divisors (!= 0.125) + if (mtb_divisor == 12.0f && tckns == 10.0f) { + spdi->freq = 2400; + } else if (mtb_divisor == 14.0f && tckns == 15.0f) { + spdi->freq = 1866; + } + + if (spdi->freq >= 1866 && mtb_divisor == 8.0f) { + tckns -= 0.4f; + } + + tckns *= mtb; // CAS# Latency tns = get_spd(slot_idx, 187); - spdi->tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tCL = (uint16_t)((tns*mtb)/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency tns = get_spd(slot_idx, 192); - spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRCD = (uint16_t)((tns*mtb)/tckns + ROUNDING_FACTOR); // RAS# Precharge tns = get_spd(slot_idx, 191); - spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRP = (uint16_t)((tns*mtb)/tckns + ROUNDING_FACTOR); // Row Active Time - tns = (uint16_t)((get_spd(slot_idx, 194) & 0xF0) << 3 | + tns = (uint16_t)((get_spd(slot_idx, 194) & 0x0F) << 8 | get_spd(slot_idx, 195)); - ; - spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + + spdi->tRAS = (uint16_t)((tns*mtb)/tckns + ROUNDING_FACTOR); // Row Cycle Time - tns = (uint16_t)((get_spd(slot_idx, 194) & 0x0F) << 8 | + tns = (uint16_t)((get_spd(slot_idx, 194) & 0xF0) << 4 | get_spd(slot_idx, 196)); - spdi->tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); + spdi->tRC = (uint16_t)((tns*mtb)/tckns + ROUNDING_FACTOR); } else { // -------------------- // JEDEC Specifications // -------------------- - tckns = (uint8_t)get_spd(slot_idx, 12) * 0.125f + + mtb = 0.125f; + + tckns = (uint8_t)get_spd(slot_idx, 12) * mtb + (int8_t)get_spd(slot_idx, 34) * 0.001f; // CAS# Latency - tns = (uint8_t)get_spd(slot_idx, 16) * 0.125f + + tns = (uint8_t)get_spd(slot_idx, 16) * mtb + (int8_t)get_spd(slot_idx, 35) * 0.001f; spdi->tCL = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# to CAS# Latency - tns = (uint8_t)get_spd(slot_idx, 18) * 0.125f + + tns = (uint8_t)get_spd(slot_idx, 18) * mtb + (int8_t)get_spd(slot_idx, 36) * 0.001f; spdi->tRCD = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // RAS# Precharge - tns = (uint8_t)get_spd(slot_idx, 20) * 0.125f + + tns = (uint8_t)get_spd(slot_idx, 20) * mtb + (int8_t)get_spd(slot_idx, 37) * 0.001f; spdi->tRP = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Active Time - tns = (uint8_t)get_spd(slot_idx, 22) * 0.125f + + tns = (uint8_t)get_spd(slot_idx, 22) * mtb + (uint8_t)(get_spd(slot_idx, 21) & 0x0F) * 32.0f; spdi->tRAS = (uint16_t)(tns/tckns + ROUNDING_FACTOR); // Row Cycle Time - tns = (uint8_t)get_spd(slot_idx, 23) * 0.125f + + tns = (uint8_t)get_spd(slot_idx, 23) * mtb + (uint8_t)(get_spd(slot_idx, 21) >> 4) * 32.0f + 1; spdi->tRC = (uint16_t)(tns/tckns + ROUNDING_FACTOR); } From 385f9127768294ca1025aac92638886908cf647c Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 29 Aug 2022 02:12:05 +0200 Subject: [PATCH 039/113] Fix date decoding issue: week 53 is actually valid for some years --- system/smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index 333b7f7..a23ce42 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -171,7 +171,7 @@ static void print_spdi(spd_info spdi, uint8_t lidx) // - for 0..31 we assume 20xx, and 0 means 2000. // - for 96..99 we assume 19xx. // - values 32..95 and > 99 are considered invalid. - if (curcol <= 69 && spdi.fab_week < 53 && spdi.fab_week != 0 && + if (curcol <= 69 && spdi.fab_week <= 53 && spdi.fab_week != 0 && (spdi.fab_year < 32 || (spdi.fab_year >= 96 && spdi.fab_year <= 99))) { curcol = printf(LINE_SPD+lidx, ++curcol, "(%02i%02i-W%02i)", spdi.fab_year >= 96 ? 19 : 20, From 18f12116c09d749944002548a1de635331f31054 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 29 Aug 2022 02:50:11 +0200 Subject: [PATCH 040/113] Fix a rare capacity detection issue with DDR3 modules built using 3 or 4 ranks --- system/smbus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index a23ce42..fab647a 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -523,10 +523,11 @@ static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) spdi->module_size = 1U << ( ((get_spd(slot_idx, 4) & 0xF) + 5) + // Total SDRAM capacity: (256 Mbits << byte4[3:0]) / 1 KB ((get_spd(slot_idx, 8) & 0x7) + 3) - // Primary Bus Width: 8 << byte8[2:0] - ((get_spd(slot_idx, 7) & 0x7) + 2) + // SDRAM Device Width: 4 << byte7[2:0] - ((get_spd(slot_idx, 7) >> 3) & 0x7) // Number of Ranks: byte7[5:3] + ((get_spd(slot_idx, 7) & 0x7) + 2) // SDRAM Device Width: 4 << byte7[2:0] ); + spdi->module_size *= ((get_spd(slot_idx, 7) >> 3) & 0x7) + 1; // Number of Ranks: byte7[5:3] + spdi->hasECC = (((get_spd(slot_idx, 8) >> 3) & 1) == 1); uint8_t tck = get_spd(slot_idx, 12); From f265d1f1c50aa57116d5ac667be8003f706f9e0d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 8 Sep 2022 18:09:43 +0100 Subject: [PATCH 041/113] Fix EHCI and XHCI drivers to handle USB1 hubs (issue #156) --- system/ehci.c | 10 ++++------ system/ohci.c | 3 +-- system/uhci.c | 4 +--- system/usbhcd.c | 16 ++++++++++++++++ system/usbhcd.h | 21 +++++++++++++++++++++ system/xhci.c | 13 +++++-------- 6 files changed, 48 insertions(+), 19 deletions(-) diff --git a/system/ehci.c b/system/ehci.c index c65d0fb..981d840 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -405,10 +405,9 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_ usb_speed_t device_speed, int device_id, usb_ep_t *ep0) { // Store the extra information needed by build_ehci_qhd(). - ep0->driver_data = port_num << 8; - if (hub->level > 0) { - ep0->driver_data |= hub->ep0->device_id; - } + usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed); + ep0->driver_data = hs_parent.port_num << 8 | hs_parent.device_id; + if (!assign_usb_address(hcd, hub, port_num, device_speed, device_id, ep0)) { return false; } @@ -558,9 +557,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) // Construct a hub descriptor for the root hub. usb_hub_t root_hub; + memset(&root_hub, 0, sizeof(root_hub)); root_hub.ep0 = NULL; - root_hub.level = 0; - root_hub.route = 0; root_hub.num_ports = num_ehci_ports(hcs_params); root_hub.power_up_delay = 10; // 20ms diff --git a/system/ohci.c b/system/ohci.c index f002206..55a3a0a 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -498,9 +498,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) // Construct a hub descriptor for the root hub. usb_hub_t root_hub; + memset(&root_hub, 0, sizeof(root_hub)); root_hub.ep0 = NULL; - root_hub.level = 0; - root_hub.route = 0; root_hub.num_ports = rh_descriptor_a & 0xf; root_hub.power_up_delay = rh_descriptor_a >> 24; diff --git a/system/uhci.c b/system/uhci.c index 1ec06f3..6454ac6 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -474,11 +474,9 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) // Construct a hub descriptor for the root hub. usb_hub_t root_hub; + memset(&root_hub, 0, sizeof(root_hub)); root_hub.ep0 = NULL; - root_hub.level = 0; - root_hub.route = 0; root_hub.num_ports = MAX_UHCI_PORTS; - root_hub.power_up_delay = 0; usleep(100*MILLISEC); // USB maximum device attach time diff --git a/system/usbhcd.c b/system/usbhcd.c index 447dd72..6f218cc 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -136,6 +136,8 @@ static bool build_hub_info(const usb_hcd_t *hcd, const usb_hub_t *parent, int po hub->num_ports = hub_desc.num_ports; hub->tt_think_time = hub_desc.characteristics & 0x0060 >> 5; hub->power_up_delay = hub_desc.power_up_delay; + hub->hs_parent = usb_hs_parent(parent, port_num, ep0->device_speed); + usb_endpoint_desc_t *ep1_desc = find_hub_endpoint_descriptor(hcd->ws->data_buffer, hcd->ws->data_length); if (ep1_desc == NULL) { return false; @@ -456,6 +458,20 @@ uint32_t usb_route(const usb_hub_t *hub, int port_num) return hub->route | (port_num << (4 * (hub->level - 1))); } +usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed) +{ + usb_parent_t hs_parent = { 0, 0 }; + if (device_speed < USB_SPEED_HIGH && hub->level > 0) { + if (hub->ep0->device_speed < USB_SPEED_HIGH) { + hs_parent = hub->hs_parent; + } else { + hs_parent.device_id = hub->ep0->device_id; + hs_parent.port_num = port_num; + } + } + return hs_parent; +} + bool wait_until_clr(const volatile uint32_t *reg, uint32_t bit_mask, int max_time) { int timer = max_time >> 3; diff --git a/system/usbhcd.h b/system/usbhcd.h index df81288..fa7f0a5 100644 --- a/system/usbhcd.h +++ b/system/usbhcd.h @@ -62,6 +62,14 @@ typedef struct __attribute__ ((packed)) { uint8_t reserved; } usb_ep_t; +/** + * A USB parent device descriptor (used internally by the various HCI drivers). + */ +typedef struct __attribute__ ((packed)) { + uint8_t device_id; + uint8_t port_num; +} usb_parent_t; + /** * A USB hub descriptor (used internally by the various HCI drivers). */ @@ -72,6 +80,8 @@ typedef struct __attribute__ ((packed)) { uint8_t num_ports; uint8_t tt_think_time; uint8_t power_up_delay; + usb_parent_t hs_parent; + uint16_t reserved; } usb_hub_t; /** @@ -210,6 +220,17 @@ static inline bool valid_usb_config_descriptor(const uint8_t *buffer) */ uint32_t usb_route(const usb_hub_t *hub, int port_num); +/** + * Returns the high-speed parent device ID and port number (as defined by + * the EHCI and XHCI specifications) for the device attached to the hub + * port specified by hub and port_num. Returns zero values if the device + * is operating at high speed (as specified by device_speed) or is directly + * attached to a root hub port. + * + * Used internally by the various HCI drivers. + */ +usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed); + /** * Waits for all the bits set in bit_mask to be cleared in the register pointed * to by reg or for max_time microseconds to elapse. diff --git a/system/xhci.c b/system/xhci.c index 99cab67..c2e68be 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -729,10 +729,9 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_ uint32_t route = usb_route(hub, port_num); slot_context->params1 |= route & 0xfffff; slot_context->root_hub_port_num = route >> 24; - if (device_speed < USB_SPEED_HIGH && hub->ep0->device_speed == USB_SPEED_HIGH) { - slot_context->parent_slot_id = hub->ep0->device_id; - slot_context->parent_port_num = port_num; - } + usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed); + slot_context->parent_slot_id = hs_parent.device_id; + slot_context->parent_port_num = hs_parent.port_num; } else { slot_context->root_hub_port_num = port_num; } @@ -818,7 +817,7 @@ static bool configure_interrupt_endpoint(workspace_t *ws, const usb_ep_t *ep, in xhci_slot_context_t *slot_context = (xhci_slot_context_t *)(ws->input_context_addr + ws->context_size); slot_context->params1 = ep_id << 27 | hub_flag << 26 | (slot_context->params1 & 0x00ffffff); slot_context->num_ports = num_ports; - slot_context->params2 = tt_think_time; + slot_context->params2 = ep->device_speed == USB_SPEED_HIGH ? tt_think_time : 0; xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + (1 + ep_id) * ws->context_size); ep_context->params1 = 0; @@ -1093,11 +1092,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) // Construct a hub descriptor for the root hub. usb_hub_t root_hub; + memset(&root_hub, 0, sizeof(root_hub)); root_hub.ep0 = NULL; - root_hub.level = 0; - root_hub.route = 0; root_hub.num_ports = cap_regs->hcs_params1 & 0xff; - root_hub.power_up_delay = 0; usleep(100*MILLISEC); // USB maximum device attach time. From 03a5222ee2670209e155059c366874b6be151e83 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Fri, 9 Sep 2022 18:09:13 +0200 Subject: [PATCH 042/113] Add support for Zen4/AM5 DDR5 SPD --- system/cpuinfo.c | 6 ++++-- system/cpuinfo.h | 3 ++- system/smbus.c | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/system/cpuinfo.c b/system/cpuinfo.c index f8522ef..a8d1e40 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -296,10 +296,12 @@ static void determine_imc(void) imc_type = IMC_K18; // Hygon (Family 18h) break; case 0xA: - if(cpuid_info.version.extendedModel == 5) { + if (cpuid_info.version.extendedModel == 5) { imc_type = IMC_K19_CZN; // AMD Cezanne APU (Model 0x50-5F - Family 19h) + } else if (cpuid_info.version.extendedModel >= 6) { + imc_type = IMC_K19_RPL; // Zen4 (Family 19h) } else { - imc_type = IMC_K19; // Zen3 & Zen4 (Family 19h) + imc_type = IMC_K19; // Zen3 (Family 19h) } default: break; diff --git a/system/cpuinfo.h b/system/cpuinfo.h index 6bf3bd5..7e2f97b 100644 --- a/system/cpuinfo.h +++ b/system/cpuinfo.h @@ -59,8 +59,9 @@ #define IMC_K16 0x8050 // Kabini & related (Family 16h) #define IMC_K17 0x8060 // Zen & Zen2 (Family 17h) #define IMC_K18 0x8070 // Hygon (Family 18h) -#define IMC_K19 0x8080 // Zen3 & Zen4(Family 19h) +#define IMC_K19 0x8080 // Zen3 (Family 19h) #define IMC_K19_CZN 0x8081 // Cezanne APU +#define IMC_K19_RPL 0x8091 // Zen4 (Family 19h) /** * A string identifying the CPU make and model. diff --git a/system/smbus.c b/system/smbus.c index fab647a..d7ec682 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1366,8 +1366,8 @@ static bool fch_zen_get_smb(void) __outb(AMD_PM_INDEX, AMD_INDEX_IO_PORT); pm_reg |= __inb(AMD_DATA_IO_PORT); - // Special case for AMD Cezanne (get smb address in memory) - if (imc_type == IMC_K19_CZN && pm_reg == 0xFFFF) { + // Special case for AMD Family 19h & Extended Model > 4 (get smb address in memory) + if ((imc_type == IMC_K19_CZN || imc_type == IMC_K19_RPL) && pm_reg == 0xFFFF) { smbusbase = ((*(const uint32_t *)(0xFED80000 + 0x300) >> 8) & 0xFF) << 8; return true; } From c41159084d8e82fec018e1ff469e88c882eeacdb Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 9 Sep 2022 19:48:59 +0100 Subject: [PATCH 043/113] Guard against unsupported or invalid USB controller types. --- system/usbhcd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/usbhcd.c b/system/usbhcd.c index 6f218cc..e77ae21 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -751,6 +751,10 @@ void find_usb_keyboards(bool pause_if_none) uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a); if (class_code == 0x0c03) { controller_type[func] = pci_config_read8(bus, dev, func, 0x09) >> 4; + if (controller_type[func] >= MAX_HCI_TYPE) { + // Unsupported or invalid controller type - ignore it. + controller_type[func] = NOT_HCI; + } // We need to initialise EHCI controllers before initialising any of their companion // controllers, so do it now. if (controller_type[func] == EHCI) { From 1c4d7f40890be06d9da159c66d865e4f4a00c092 Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Wed, 14 Sep 2022 18:57:10 +0200 Subject: [PATCH 044/113] Document PCI vendor and device IDs for several SMBus controller models from SiS, EFAR and ALi; move the PCI vendor ID defines from system/smbus.h to system/pci.h and add several vendor IDs; use the defines from system/pci.h in system/hwquirks.c. (#154) Inspired by #126. --- system/hwquirks.c | 10 +++++----- system/pci.h | 13 +++++++++++++ system/smbus.c | 48 +++++++++++++++++++++++++++++++++++------------ system/smbus.h | 10 ---------- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/system/hwquirks.c b/system/hwquirks.c index b78ecbd..744691e 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -79,9 +79,9 @@ void quirks_init(void) // ------------------------- // -- ALi Aladdin V Quirk -- // ------------------------- - // As on many Socket 7 Motherboard, the L2 cache is external and must + // As on many Socket 7 Motherboards, the L2 cache is external and must // be detected by a proprietary way based on chipset registers - if (quirk.root_vid == 0x10B9 && quirk.root_did == 0x1541) { // ALi Aladdin V (M1541) + if (quirk.root_vid == PCI_VID_ALI && quirk.root_did == 0x1541) { // ALi Aladdin V (M1541) quirk.id = QUIRK_ALI_ALADDIN_V; quirk.type |= QUIRK_TYPE_MEM_SIZE; quirk.process = get_m1541_l2_cache_size; @@ -93,9 +93,9 @@ void quirks_init(void) // This motherboard has an ASB100 ASIC with a SMBUS Mux Integrated. // To access SPD later in the code, we need to configure the mux. // PS: Detection via DMI is unreliable, so using Root PCI Registers - if (quirk.root_vid == 0x8086 && quirk.root_did == 0x1130) { // Intel i815 - if (pci_config_read16(0, 0, 0, 0x2C) == 0x1043) { // ASUS - if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C + if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x1130) { // Intel i815 + if (pci_config_read16(0, 0, 0, 0x2C) == PCI_VID_ASUS) { // ASUS + if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C quirk.id = QUIRK_TUSL2; quirk.type |= QUIRK_TYPE_SMBUS; quirk.process = asus_tusl2_configure_mux; diff --git a/system/pci.h b/system/pci.h index e85d8dc..e82016f 100644 --- a/system/pci.h +++ b/system/pci.h @@ -12,6 +12,19 @@ #include +/* Vendor IDs */ +#define PCI_VID_ATI 0x1002 +#define PCI_VID_AMD 0x1022 +#define PCI_VID_SIS 0x1039 +#define PCI_VID_ASUS 0x1043 +#define PCI_VID_EFAR 0x1055 +#define PCI_VID_ALI 0x10B9 +#define PCI_VID_NVIDIA 0x10DE +#define PCI_VID_VIA 0x1106 +#define PCI_VID_SERVERWORKS 0x1166 +#define PCI_VID_HYGON 0x1D94 +#define PCI_VID_INTEL 0x8086 + #define PCI_MAX_BUS 256 #define PCI_MAX_DEV 32 #define PCI_MAX_FUNC 8 diff --git a/system/smbus.c b/system/smbus.c index d7ec682..d7a2c50 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1152,7 +1152,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) smbus_id = (((uint32_t)vid) << 16) | did; switch(vid) { - case VID_INTEL: + case PCI_VID_INTEL: { if (find_in_did_array(did, intel_ich5_dids, sizeof(intel_ich5_dids) / sizeof(intel_ich5_dids[0]))) { return ich5_get_smb(); @@ -1160,14 +1160,14 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) if (did == 0x7113) { // 82371AB/EB/MB PIIX4 return piix4_get_smb(); } - // 0x719B 82440/82443MX PMC ? + // 0x719B 82440/82443MX PMC - PIIX4 // 0x0F13 ValleyView SMBus Controller ? // 0x8119 US15W ? return false; } - case VID_HYGON: - case VID_AMD: + case PCI_VID_HYGON: + case PCI_VID_AMD: switch(did) { // case 0x740B: // AMD756 @@ -1184,7 +1184,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) } break; - case VID_ATI: + case PCI_VID_ATI: switch(did) { // case 0x4353: // SB200 @@ -1197,7 +1197,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) } break; - case VID_NVIDIA: + case PCI_VID_NVIDIA: switch(did) { // case 0x01B4: // nForce @@ -1221,17 +1221,22 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) } break; - case VID_SIS: + case PCI_VID_SIS: switch(did) { - case 0x0016: // SiS961/2/3 - // There are also SiS630 and SiS5595 SMBus controllers. + // case 0x0008: + // SiS5595, SiS630 or other SMBus controllers - it's complicated. + // case 0x0016: + // SiS961/2/3, known as "SiS96x" SMBus controllers. + // case 0x0018: + // case 0x0964: + // SiS630 SMBus controllers. default: return false; } break; - case VID_VIA: + case PCI_VID_VIA: switch(did) { // case 0x3040: // 82C586_3 @@ -1262,7 +1267,26 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) } break; - case VID_SERVERWORKS: + case PCI_VID_EFAR: + switch(did) + { + // case 0x9463: // SLC90E66_3: PIIX4 + default: + return false; + } + break; + + case PCI_VID_ALI: + switch(did) + { + // case 0x1563: // ali1563 (M1563) SMBus controller + // case 0x7101: // ali1535 (M1535) or ali15x3 (M1533/M1543) SMBus controllers + default: + return false; + } + break; + + case PCI_VID_SERVERWORKS: switch(did) { case 0x0201: // CSB5 @@ -1417,7 +1441,7 @@ 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 VID_NVIDIA: + case PCI_VID_NVIDIA: return nf_read_spd_byte(slot_idx, (uint8_t)spd_adr); default: return ich5_read_spd_byte(slot_idx, spd_adr); diff --git a/system/smbus.h b/system/smbus.h index de7883d..5a31352 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -10,16 +10,6 @@ * Copyright (C) 2004-2022 Samuel Demeulemeester. */ -/* Vendor IDs */ -#define VID_ATI 0x1002 -#define VID_AMD 0x1022 -#define VID_SIS 0x1039 -#define VID_NVIDIA 0x10DE -#define VID_VIA 0x1106 -#define VID_SERVERWORKS 0x1166 -#define VID_HYGON 0x1D94 -#define VID_INTEL 0x8086 - #define I2C_WRITE 0 #define I2C_READ 1 From ddbee66c854f0e88ddebaeed46011bea78526c7d Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Wed, 14 Sep 2022 20:47:29 +0200 Subject: [PATCH 045/113] Fix a cast issue that broke the run time clock on (very) fast CPUs --- app/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/display.c b/app/display.c index 2097e7e..d3446f5 100644 --- a/app/display.c +++ b/app/display.c @@ -509,7 +509,7 @@ void do_tick(int my_cpu) if (clks_per_msec > 0) { uint64_t current_time = get_tsc(); - int secs = (current_time - run_start_time) / (1000 * clks_per_msec); + int secs = (current_time - run_start_time) / (1000 * (uint64_t)clks_per_msec); int mins = secs / 60; secs %= 60; act_sec = secs; int hours = mins / 60; mins %= 60; display_run_time(hours, mins, secs); From 407fb811c2b9a751d90b98015caa81b455db90a7 Mon Sep 17 00:00:00 2001 From: martinwhitaker Date: Fri, 7 Oct 2022 09:32:09 +0100 Subject: [PATCH 046/113] Take ownership of all USB controllers before probing for devices. (#167) When two controllers are attached to a physical port (e.g. in the case of EHCI and its companion controllers, problems can occur if the BIOS still has control of one controller when we try to use the other one. So perform a first pass to scan the PCI bus and take ownership of and reset all the controllers we find, and perform a second pass to initialise the controllers and probe for attached devices. As we don't support hot plugging, split the second pass into two, with the first probing the EHCI controllers and handing over any low and full speed devices to the companion controllers, and the second probing the remaining controller types. --- system/ehci.c | 11 ++- system/ehci.h | 35 ++++++-- system/ohci.c | 72 ++++++++++------ system/ohci.h | 32 ++++++-- system/uhci.c | 7 +- system/uhci.h | 36 ++++++-- system/usbhcd.c | 214 +++++++++++++++++++++++++++++++----------------- system/xhci.c | 48 +++++++++-- system/xhci.h | 32 ++++++-- 9 files changed, 355 insertions(+), 132 deletions(-) diff --git a/system/ehci.c b/system/ehci.c index 981d840..9266cbe 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -486,7 +486,7 @@ static const hcd_methods_t methods = { // Public Functions //------------------------------------------------------------------------------ -bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) +bool ehci_reset(int bus, int dev, int func, uintptr_t base_addr) { ehci_cap_regs_t *cap_regs = (ehci_cap_regs_t *)base_addr; @@ -513,6 +513,15 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd) if (!halt_host_controller(op_regs)) return false; if (!reset_host_controller(op_regs)) return false; + return true; +} + +bool ehci_probe(uintptr_t base_addr, usb_hcd_t *hcd) +{ + ehci_cap_regs_t *cap_regs = (ehci_cap_regs_t *)base_addr; + + ehci_op_regs_t *op_regs = (ehci_op_regs_t *)(base_addr + cap_regs->cap_length); + // Record the heap state to allow us to free memory. uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); diff --git a/system/ehci.h b/system/ehci.h index aef36b1..0e0c8ef 100644 --- a/system/ehci.h +++ b/system/ehci.h @@ -15,12 +15,35 @@ #include "usbhcd.h" /** - * Initialises the EHCI device identified by bus, dev, func, and base_addr, - * scans all the attached USB devices, and configures any HID USB keyboard - * devices it finds to generate periodic interrupt transfers that report key - * presses. Initialises hcd and returns true if the device was successfully - * initialised and one or more keyboards were found. + * If necessary, takes ownership of the EHCI device at the specified base + * address, then resets it. + * + * \param bus - the PCI bus number for accessing the device + * \param dev - the PCI device number for accessing the device + * \param func - the PCI function number for accessing the device + * \param base_addr - the base address of the device in virtual memory + * + * \returns + * true if ownership was acquired and the device was successfully reset, + * otherwise false. */ -bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd); +bool ehci_reset(int bus, int dev, int func, uintptr_t base_addr); + +/** + * Initialises the EHCI device at the specified base address, probes all + * the attached USB devices, and configures any HID USB keyboard devices + * it finds to generate periodic interrupt transfers that report key + * presses. If successful, initialises the specified host controller + * driver object accordingly. + * + * \param base_addr - the base address of the device in virtual memory + * \param hcd - a pointer to a pre-allocated host controller + * driver object that can be used for this device + * + * \returns + * true if the device was successfully initialised and one or more + * keyboards were found, otherwise false. + */ +bool ehci_probe(uintptr_t base_addr, usb_hcd_t *hcd); #endif // EHCI_H diff --git a/system/ohci.c b/system/ohci.c index 55a3a0a..dce7eb3 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -243,6 +243,36 @@ typedef struct { // Private Functions //------------------------------------------------------------------------------ +static bool reset_host_controller(ohci_op_regs_t *op_regs) +{ + // Prepare for host controller setup (see section 5.1.1.3 of the OHCI spec.). + switch (read32(&op_regs->control) & OHCI_CTRL_HCFS) { + case OHCI_CTRL_HCFS_RST: + usleep(50*MILLISEC); + break; + case OHCI_CTRL_HCFS_SUS: + case OHCI_CTRL_HCFS_RES: + flush32(&op_regs->control, OHCI_CTRL_HCFS_RES); + usleep(20*MILLISEC); + break; + default: // operational + break; + } + + // Reset the host controller. + write32(&op_regs->command_status, OHCI_CMD_HCR); + if (!wait_until_clr(&op_regs->command_status, OHCI_CMD_HCR, 30)) { + return false; + } + + // Check we are now in SUSPEND state. + if ((read32(&op_regs->control) & OHCI_CTRL_HCFS) != OHCI_CTRL_HCFS_SUS) { + return false; + } + + return true; +} + static bool reset_ohci_port(ohci_op_regs_t *op_regs, int port_idx) { // The OHCI reset lasts for 10ms, but the USB specification calls for 50ms (but not necessarily continuously). @@ -406,7 +436,7 @@ static const hcd_methods_t methods = { // Public Functions //------------------------------------------------------------------------------ -bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) +bool ohci_reset(uintptr_t base_addr) { ohci_op_regs_t *op_regs = (ohci_op_regs_t *)base_addr; @@ -424,6 +454,20 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) } } + // Reset the controller, but preserve the frame interval set by the SMM or BIOS. + uint32_t fm_interval = read32(&op_regs->fm_interval); + if (!reset_host_controller(op_regs)) { + return false; + } + write32(&op_regs->fm_interval, fm_interval); + + return true; +} + +bool ohci_probe(uintptr_t base_addr, usb_hcd_t *hcd) +{ + ohci_op_regs_t *op_regs = (ohci_op_regs_t *)base_addr; + // Preserve the frame interval set by the SMM or BIOS. // If not set, use the default value. uint32_t frame_interval = read32(&op_regs->fm_interval) & 0x3fff; @@ -431,28 +475,10 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd) frame_interval = 0x2edf; } - // Prepare for host controller setup (see section 5.1.1.3 of the OHCI spec.). - switch (read32(&op_regs->control) & OHCI_CTRL_HCFS) { - case OHCI_CTRL_HCFS_RST: - usleep(50*MILLISEC); - break; - case OHCI_CTRL_HCFS_SUS: - case OHCI_CTRL_HCFS_RES: - flush32(&op_regs->control, OHCI_CTRL_HCFS_RES); - usleep(10*MILLISEC); - break; - default: // operational - break; - } - - // Reset the host controller. - write32(&op_regs->command_status, OHCI_CMD_HCR); - if (!wait_until_clr(&op_regs->command_status, OHCI_CMD_HCR, 30)) { - return false; - } - - // Check we are now in SUSPEND state. - if ((read32(&op_regs->control) & OHCI_CTRL_HCFS) != OHCI_CTRL_HCFS_SUS) { + // We will have already reset the controller, but can't guarantee to get + // here within the 2ms time limit for moving directly from suspend state + // to operational state. So reset it again. + if (!reset_host_controller(op_regs)) { return false; } diff --git a/system/ohci.h b/system/ohci.h index 45821e0..404126e 100644 --- a/system/ohci.h +++ b/system/ohci.h @@ -15,12 +15,32 @@ #include "usbhcd.h" /** - * Initialises the OHCI device found at base_addr, scans all the attached USB - * devices, and configures any HID USB keyboard devices it finds to generate - * periodic interrupt transfers that report key presses. Initialises hcd and - * returns true if the device was successfully initialised and one or more - * keyboards were found. + * If necessary, takes ownership of the OHCI device at the specified base + * address, then resets it. + * + * \param base_addr - the base address of the device in virtual memory + * + * \returns + * true if ownership was acquired and the device was successfully reset, + * otherwise false. */ -bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd); +bool ohci_reset(uintptr_t base_addr); + +/** + * Initialises the OHCI device at the specified base address, probes all + * the attached USB devices, and configures any HID USB keyboard devices + * it finds to generate periodic interrupt transfers that report key + * presses. If successful, initialises the specified host controller + * driver object accordingly. + * + * \param base_addr - the base address of the device in virtual memory + * \param hcd - a pointer to a pre-allocated host controller + * driver object that can be used for this device + * + * \returns + * true if the device was successfully initialised and one or more + * keyboards were found, otherwise false. + */ +bool ohci_probe(uintptr_t base_addr, usb_hcd_t *hcd); #endif // OHCI_H diff --git a/system/uhci.c b/system/uhci.c index 6454ac6..0669225 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -420,7 +420,7 @@ static const hcd_methods_t methods = { // Public Functions //------------------------------------------------------------------------------ -bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) +bool uhci_reset(int bus, int dev, int func, uint16_t io_base) { // Disable PCI and SMM interrupts. pci_config_write16(bus, dev, func, UHCI_LEGSUP, UHCI_LEGSUP_CLEAR); @@ -429,6 +429,11 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd) if (!halt_host_controller(io_base)) return false; if (!reset_host_controller(io_base)) return false; + return true; +} + +bool uhci_probe(uint16_t io_base, usb_hcd_t *hcd) +{ // Record the heap state to allow us to free memory. uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1); diff --git a/system/uhci.h b/system/uhci.h index 2c004d8..6a5003b 100644 --- a/system/uhci.h +++ b/system/uhci.h @@ -15,13 +15,35 @@ #include "usbhcd.h" /** - * Initialises the UHCI device found at bus, dev, func on the PCI bus and - * io_base in the I/O address space, scans all the attached USB devices, and - * configures any HID USB keyboard devices it finds to generate periodic - * interrupt transfers that report key presses. Initialises hcd and returns - * true if the device was successfully initialised and one or more keyboards - * were found. + * If necessary, takes ownership of the UHCI device at the specified base + * address, then resets it. + * + * \param bus - the PCI bus number for accessing the device + * \param dev - the PCI device number for accessing the device + * \param func - the PCI function number for accessing the device + * \param io_base - the base address of the device in I/O space + * + * \returns + * true if ownership was acquired and the device was successfully reset, + * otherwise false. */ -bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd); +bool uhci_reset(int bus, int dev, int func, uint16_t io_base); + +/** + * Initialises the UHCI device at the specified base address, probes all + * the attached USB devices, and configures any HID USB keyboard devices + * it finds to generate periodic interrupt transfers that report key + * presses. If successful, initialises the specified host controller + * driver object accordingly. + * + * \param io_base - the base address of the device in I/O space + * \param hcd - a pointer to a pre-allocated host controller + * driver object that can be used for this device + * + * \returns + * true if the device was successfully initialised and one or more + * keyboards were found, otherwise false. + */ +bool uhci_probe(uint16_t io_base, usb_hcd_t *hcd); #endif // UHCI_H diff --git a/system/usbhcd.c b/system/usbhcd.c index e77ae21..ad75b4c 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -22,7 +22,9 @@ // Constants //------------------------------------------------------------------------------ -#define MAX_USB_CONTROLLERS 8 // an arbitrary limit - must match the initialisation of usb_controllers +#define MAX_HCI 16 // an arbitrary limit - only affects stack usage + +#define MAX_HCD 8 // an arbitrary limit - must match the initialisation of hcd_list #define PAUSE_IF_NONE_TIME 10 // seconds @@ -41,6 +43,14 @@ typedef enum { MAX_HCI_TYPE = 4 } hci_type_t; +typedef struct { + hci_type_t type; + uint8_t bus; + uint8_t dev; + uint8_t func; + uintptr_t base_addr; +} hci_info_t; + //------------------------------------------------------------------------------ // Private Variables //------------------------------------------------------------------------------ @@ -60,7 +70,7 @@ static const hcd_methods_t methods = { }; // All entries in this array must be initialised in order to generate the necessary relocation records. -static usb_hcd_t usb_controllers[MAX_USB_CONTROLLERS] = { +static usb_hcd_t hcd_list[MAX_HCD] = { { &methods, NULL }, { &methods, NULL }, { &methods, NULL }, @@ -71,7 +81,7 @@ static usb_hcd_t usb_controllers[MAX_USB_CONTROLLERS] = { { &methods, NULL } }; -static int num_usb_controllers = 0; +static int num_hcd = 0; static int print_row = 0; static int print_col = 0; @@ -349,8 +359,56 @@ static bool scan_hub_ports(const usb_hcd_t *hcd, const usb_hub_t *hub, int *num_ return keyboard_found; } -static void probe_usb_controller(int bus, int dev, int func, hci_type_t controller_type) +static int find_usb_controllers(hci_info_t hci_list[]) { + int num_hci = 0; + for (int bus = 0; bus < PCI_MAX_BUS; bus++) { + for (int dev = 0; dev < PCI_MAX_DEV; dev++) { + for (int func = 0; func < PCI_MAX_FUNC; func++) { + // Test for device/function present. + uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00); + uint8_t hdr_type = pci_config_read8 (bus, dev, func, 0x0e); + if (vendor_id != 0xffff) { + // Test for a USB controller. + uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a); + if (class_code == 0x0c03) { + hci_type_t controller_type = pci_config_read8(bus, dev, func, 0x09) >> 4; + if (controller_type < MAX_HCI_TYPE) { + hci_list[num_hci].type = controller_type; + hci_list[num_hci].bus = bus; + hci_list[num_hci].dev = dev; + hci_list[num_hci].func = func; + num_hci++; + // If we've filled the table, abort now. + if (num_hci == MAX_HCI) { + return num_hci; + } + } + } + // Break out if this is a single function device. + if (func == 0 && (hdr_type & 0x80) == 0) { + break; + } + } else { + // Break out if no device is present. + if (func == 0) { + break; + } + } + } + } + } + return num_hci; +} + +static void reset_usb_controller(hci_info_t *hci) +{ + hci_type_t controller_type = hci->type; + + int bus = hci->bus; + int dev = hci->dev; + int func = hci->func; + uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00); uint16_t device_id = pci_config_read16(bus, dev, func, 0x02); uint16_t pci_status = pci_config_read16(bus, dev, func, 0x06); @@ -382,22 +440,27 @@ static void probe_usb_controller(int bus, int dev, int func, hci_type_t controll // Restore access to the device and set the bus master flag in case the BIOS hasn't. pci_config_write16(bus, dev, func, 0x04, pci_command | (in_io_space ? 0x0005 : 0x0006)); + hci->base_addr = base_addr; + print_usb_info("Found %s controller %04x:%04x at %08x size %08x in %s space", hci_name[controller_type], (uintptr_t)vendor_id, (uintptr_t)device_id, base_addr, mmio_size, in_io_space ? "I/O" : "Mem"); if (in_io_space) { if (controller_type != UHCI) { print_usb_info(" Unsupported address mapping for this controller type"); + hci->type = NOT_HCI; // mark this controller as unusable return; } } else { if (controller_type == UHCI) { print_usb_info(" Unsupported address mapping for this controller type"); + hci->type = NOT_HCI; // mark this controller as unusable return; } base_addr = map_region(base_addr, mmio_size, false); if (base_addr == 0) { print_usb_info(" Failed to map device into virtual memory"); + hci->type = NOT_HCI; // mark this controller as unusable return; } } @@ -422,22 +485,53 @@ static void probe_usb_controller(int bus, int dev, int func, hci_type_t controll } } - // Initialise the device according to its type. + // Reset the device according to its type. + bool success = false; + switch (controller_type) { + case UHCI: + success = uhci_reset(bus, dev, func, base_addr); + break; + case OHCI: + success = ohci_reset(base_addr); + break; + case EHCI: + success = ehci_reset(bus, dev, func, base_addr); + break; + case XHCI: + success = xhci_reset(base_addr); + break; + default: + break; + } + if (!success) { + hci->type = NOT_HCI; // mark this controller as unusable + } +} + +static void probe_usb_controller(hci_type_t controller_type, uintptr_t base_addr) +{ + print_usb_info("Probing %s controller at %08x", hci_name[controller_type], base_addr); + + // Probe the device according to its type. bool keyboards_found = false; - if (controller_type == UHCI) { - keyboards_found = uhci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]); - } - if (controller_type == OHCI) { - keyboards_found = ohci_init(base_addr, &usb_controllers[num_usb_controllers]); - } - if (controller_type == EHCI) { - keyboards_found = ehci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]); - } - if (controller_type == XHCI) { - keyboards_found = xhci_init(base_addr, &usb_controllers[num_usb_controllers]); + switch (controller_type) { + case UHCI: + keyboards_found = uhci_probe(base_addr, &hcd_list[num_hcd]); + break; + case OHCI: + keyboards_found = ohci_probe(base_addr, &hcd_list[num_hcd]); + break; + case EHCI: + keyboards_found = ehci_probe(base_addr, &hcd_list[num_hcd]); + break; + case XHCI: + keyboards_found = xhci_probe(base_addr, &hcd_list[num_hcd]); + break; + default: + break; } if (keyboards_found) { - num_usb_controllers++; + num_hcd++; } } @@ -735,66 +829,40 @@ void find_usb_keyboards(bool pause_if_none) clear_screen(); print_usb_info("Scanning for USB keyboards..."); - num_usb_controllers = 0; - for (int bus = 0; bus < PCI_MAX_BUS; bus++) { - for (int dev = 0; dev < PCI_MAX_DEV; dev++) { - hci_type_t controller_type[PCI_MAX_FUNC]; - for (int func = 0; func < PCI_MAX_FUNC; func++) { - controller_type[func] = NOT_HCI; - } - for (int func = 0; func < PCI_MAX_FUNC; func++) { - // Test for device/function present. - uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00); - uint8_t hdr_type = pci_config_read8 (bus, dev, func, 0x0e); - if (vendor_id != 0xffff) { - // Test for a USB controller. - uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a); - if (class_code == 0x0c03) { - controller_type[func] = pci_config_read8(bus, dev, func, 0x09) >> 4; - if (controller_type[func] >= MAX_HCI_TYPE) { - // Unsupported or invalid controller type - ignore it. - controller_type[func] = NOT_HCI; - } - // We need to initialise EHCI controllers before initialising any of their companion - // controllers, so do it now. - if (controller_type[func] == EHCI) { - if (~usb_init_options & USB_IGNORE_EHCI) { - probe_usb_controller(bus, dev, func, controller_type[func]); - } - // If we've filled the controller table, abort now. - if (num_usb_controllers == MAX_USB_CONTROLLERS) { - return; - } - controller_type[func] = NOT_HCI; // prevent reprobing - } - } - // Break out if this is a single function device. - if (func == 0 && (hdr_type & 0x80) == 0) { - break; - } - } else { - // Break out if no device is present. - if (func == 0) { - break; - } - } - } - for (int func = 0; func < PCI_MAX_FUNC; func++) { - if (controller_type[func] != NOT_HCI) { - probe_usb_controller(bus, dev, func, controller_type[func]); - // If we've filled the controller table, abort now. - if (num_usb_controllers == MAX_USB_CONTROLLERS) { - return; - } - } + hci_info_t hci_list[MAX_HCI]; + + int num_hci = find_usb_controllers(hci_list); + + // Take ownership of all controllers and reset them. + for (int i = 0; i < num_hci; i++) { + reset_usb_controller(&hci_list[i]); + } + + num_hcd = 0; + + // As we don't support hot plugging, we need to probe EHCI controllers before + // probing any of their companion controllers, to ensure any low and full speed + // devices are routed to the companion controllers before we probe them. + for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) { + if (hci_list[i].type == EHCI) { + if (~usb_init_options & USB_IGNORE_EHCI) { + probe_usb_controller(EHCI, hci_list[i].base_addr); } + hci_list[i].type = NOT_HCI; // prevent this controller from being scanned again + } + } + + // Now probe the other controllers. + for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) { + if (hci_list[i].type != NOT_HCI) { + probe_usb_controller(hci_list[i].type, hci_list[i].base_addr); } } if (usb_init_options & USB_DEBUG) { print_usb_info("Press any key to continue..."); while (get_key() == 0) {} - } else if (pause_if_none && num_usb_controllers == 0) { + } else if (pause_if_none && num_hcd == 0) { for (int i = PAUSE_IF_NONE_TIME; i > 0; i--) { print_usb_info("No USB keyboards found. Continuing in %i second%c ", i, i == 1 ? ' ' : 's'); sleep(1); @@ -805,10 +873,10 @@ void find_usb_keyboards(bool pause_if_none) uint8_t get_usb_keycode(void) { - for (int i = 0; i < num_usb_controllers; i++) { - const usb_hcd_t *hcd = &usb_controllers[i]; + for (int i = 0; i < num_hcd; i++) { + const usb_hcd_t *hcd = &hcd_list[i]; - usb_controllers[i].methods->poll_keyboards(hcd); + hcd->methods->poll_keyboards(hcd); int kc_index_o = hcd->ws->kc_index_o; if (kc_index_o != hcd->ws->kc_index_i) { diff --git a/system/xhci.c b/system/xhci.c index c2e68be..dbe6eb6 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -910,12 +910,8 @@ static const hcd_methods_t methods = { // Public Functions //------------------------------------------------------------------------------ -bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) +bool xhci_reset(uintptr_t base_addr) { - uint8_t port_type[XHCI_MAX_PORTS]; - - memset(port_type, 0, sizeof(port_type)); - xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)base_addr; #ifdef QEMU_WORKAROUND @@ -947,6 +943,44 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) timer--; } } + ext_cap_offs = ext_cap->next_offset; + } + + xhci_op_regs_t *op_regs = (xhci_op_regs_t *)(base_addr + cap_regs->cap_length); + + // Ensure the controller is halted and then reset it. + if (!halt_host_controller(op_regs)) return false; + if (!reset_host_controller(op_regs)) return false; + + return true; +} + +bool xhci_probe(uintptr_t base_addr, usb_hcd_t *hcd) +{ + uint8_t port_type[XHCI_MAX_PORTS]; + + memset(port_type, 0, sizeof(port_type)); + + xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)base_addr; + +#ifdef QEMU_WORKAROUND + xhci_cap_regs_t cap_regs_copy; + memcpy32(&cap_regs_copy, cap_regs, sizeof(cap_regs_copy)); + cap_regs = &cap_regs_copy; +#endif + + // Walk the extra capabilities list. + uintptr_t ext_cap_base = base_addr; + uintptr_t ext_cap_offs = cap_regs->hcc_params1 >> 16; + while (ext_cap_offs != 0) { + ext_cap_base += ext_cap_offs * sizeof(uint32_t); + xhci_ext_cap_t *ext_cap = (xhci_ext_cap_t *)ext_cap_base; + +#ifdef QEMU_WORKAROUND + xhci_ext_cap_t ext_cap_copy; + memcpy32(&ext_cap_copy, ext_cap, sizeof(ext_cap_copy)); + ext_cap = &ext_cap_copy; +#endif if (ext_cap->id == XHCI_EXT_CAP_SUPPORTED_PROTOCOL) { xhci_supported_protocol_t *protocol = (xhci_supported_protocol_t *)ext_cap_base; @@ -984,10 +1018,6 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd) xhci_rt_regs_t *rt_regs = (xhci_rt_regs_t *)(base_addr + cap_regs->rts_offset); xhci_db_reg_t *db_regs = (xhci_db_reg_t *)(base_addr + cap_regs->db_offset); - // Ensure the controller is halted and then reset it. - if (!halt_host_controller(op_regs)) return false; - if (!reset_host_controller(op_regs)) return false; - // Record the heap states to allow us to free memory. uintptr_t initial_lm_heap_mark = heap_mark(HEAP_TYPE_LM_1); uintptr_t initial_hm_heap_mark = heap_mark(HEAP_TYPE_HM_1); diff --git a/system/xhci.h b/system/xhci.h index e713906..648d426 100644 --- a/system/xhci.h +++ b/system/xhci.h @@ -15,12 +15,32 @@ #include "usbhcd.h" /** - * Initialises the XHCI device found at base_addr, scans all the attached USB - * devices, and configures any HID USB keyboard devices it finds to generate - * periodic interrupt transfers that report key presses. Initialises hcd and - * returns true if the device was successfully initialised and one or more - * keyboards were found. + * If necessary, takes ownership of the XHCI device at the specified base + * address, then resets it. + * + * \param base_addr - the base address of the device in virtual memory + * + * \returns + * true if ownership was acquired and the device was successfully reset, + * otherwise false. */ -bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd); +bool xhci_reset(uintptr_t base_addr); + +/** + * Initialises the XHCI device at the specified base address, probes all + * the attached USB devices, and configures any HID USB keyboard devices + * it finds to generate periodic interrupt transfers that report key + * presses. If successful, initialises the specified host controller + * driver object accordingly. + * + * \param base_addr - the base address of the device in virtual memory + * \param hcd - a pointer to a pre-allocated host controller + * driver object that can be used for this device + * + * \returns + * true if the device was successfully initialised and one or more + * keyboards were found, otherwise false. + */ +bool xhci_probe(uintptr_t base_addr, usb_hcd_t *hcd); #endif // XHCI_H From 66b138934891599ba1e20383ada789358009a63d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 7 Oct 2022 09:33:23 +0100 Subject: [PATCH 047/113] Revert workaround for issue #6 and issue #71 (commit 3a10701). The early USB handoff is a better fix for those issues. --- system/ehci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/system/ehci.c b/system/ehci.c index 9266cbe..1dab18e 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -654,7 +654,6 @@ bool ehci_probe(uintptr_t base_addr, usb_hcd_t *hcd) if (num_keyboards == 0) { (void)halt_host_controller(op_regs); - (void)reset_host_controller(op_regs); goto no_keyboards_found; } From aaa0cffaa62627dd32cbca9eecb71655d4770e70 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 7 Oct 2022 13:06:42 +0100 Subject: [PATCH 048/113] Use virtual memory base address when probing USB controllers (issue #180) We still want to display the physical address for debug purposes, but must access the controller via the possibly remapped virtual address. --- system/usbhcd.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/system/usbhcd.c b/system/usbhcd.c index ad75b4c..e588504 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -48,7 +48,8 @@ typedef struct { uint8_t bus; uint8_t dev; uint8_t func; - uintptr_t base_addr; + uintptr_t pm_base_addr; + uintptr_t vm_base_addr; } hci_info_t; //------------------------------------------------------------------------------ @@ -440,7 +441,7 @@ static void reset_usb_controller(hci_info_t *hci) // Restore access to the device and set the bus master flag in case the BIOS hasn't. pci_config_write16(bus, dev, func, 0x04, pci_command | (in_io_space ? 0x0005 : 0x0006)); - hci->base_addr = base_addr; + hci->pm_base_addr = base_addr; print_usb_info("Found %s controller %04x:%04x at %08x size %08x in %s space", hci_name[controller_type], (uintptr_t)vendor_id, (uintptr_t)device_id, base_addr, mmio_size, in_io_space ? "I/O" : "Mem"); @@ -465,6 +466,8 @@ static void reset_usb_controller(hci_info_t *hci) } } + hci->vm_base_addr = base_addr; + // Search for power management capability. //uint8_t pm_cap_ptr; if (pci_status & 0x10) { @@ -508,24 +511,24 @@ static void reset_usb_controller(hci_info_t *hci) } } -static void probe_usb_controller(hci_type_t controller_type, uintptr_t base_addr) +static void probe_usb_controller(hci_type_t controller_type, uintptr_t pm_base_addr, uintptr_t vm_base_addr) { - print_usb_info("Probing %s controller at %08x", hci_name[controller_type], base_addr); + print_usb_info("Probing %s controller at %08x", hci_name[controller_type], pm_base_addr); // Probe the device according to its type. bool keyboards_found = false; switch (controller_type) { case UHCI: - keyboards_found = uhci_probe(base_addr, &hcd_list[num_hcd]); + keyboards_found = uhci_probe(vm_base_addr, &hcd_list[num_hcd]); break; case OHCI: - keyboards_found = ohci_probe(base_addr, &hcd_list[num_hcd]); + keyboards_found = ohci_probe(vm_base_addr, &hcd_list[num_hcd]); break; case EHCI: - keyboards_found = ehci_probe(base_addr, &hcd_list[num_hcd]); + keyboards_found = ehci_probe(vm_base_addr, &hcd_list[num_hcd]); break; case XHCI: - keyboards_found = xhci_probe(base_addr, &hcd_list[num_hcd]); + keyboards_found = xhci_probe(vm_base_addr, &hcd_list[num_hcd]); break; default: break; @@ -846,7 +849,7 @@ void find_usb_keyboards(bool pause_if_none) for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) { if (hci_list[i].type == EHCI) { if (~usb_init_options & USB_IGNORE_EHCI) { - probe_usb_controller(EHCI, hci_list[i].base_addr); + probe_usb_controller(EHCI, hci_list[i].pm_base_addr, hci_list[i].vm_base_addr); } hci_list[i].type = NOT_HCI; // prevent this controller from being scanned again } @@ -855,7 +858,7 @@ void find_usb_keyboards(bool pause_if_none) // Now probe the other controllers. for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) { if (hci_list[i].type != NOT_HCI) { - probe_usb_controller(hci_list[i].type, hci_list[i].base_addr); + probe_usb_controller(hci_list[i].type, hci_list[i].pm_base_addr, hci_list[i].vm_base_addr); } } From 83d08db69ed808e8887390214017475745957de1 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 9 Oct 2022 13:45:26 +0100 Subject: [PATCH 049/113] Document the lack of support for USB hot-plugging in the README. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 455657f..e8e494e 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,10 @@ Many USB devices don't fully conform to the USB specification. If the USB keyboard probe hangs or fails to detect your keyboard, try the various workarounds provided by the "usbinit" boot option. +**NOTE**: Hot-plugging is not currently supported by the Memtest86+ USB +drivers. When using these, your USB keyboard should be plugged in before +running Memtest86+ and should remain plugged in throughout the test. + ## Operation Once booted, Memtest86+ will initialise its display, then pause for a few @@ -538,6 +542,7 @@ of all zeros and all ones. ## Known Limitations and Bugs Please see the list of [open issues](https://github.com/memtest86plus/memtest86plus/issues) +and [enhancement requests](https://github.com/memtest86plus/memtest86plus/discussions) on GitHub. Feel free to submit bug reports! From 85213a9a27f5a0ecdc060e1b35154db43a1ff585 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 9 Oct 2022 13:51:32 +0100 Subject: [PATCH 050/113] Add code contribution section to the README, referencing the README_DEVEL. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e8e494e..e0d295f 100644 --- a/README.md +++ b/README.md @@ -547,6 +547,11 @@ on GitHub. Feel free to submit bug reports! +## Code Contributions + +Code contributions are welcomed, either to fix bugs or to make enhancements. +See the README_DEVEL.md in the doc directory for some basic guidelines. + ## Acknowledgments Memtest86+ v6.0 was based on PCMemTest, developed by Martin Whitaker, which From 1278f026176cfddd12cc1092ec51e80bec1f3192 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 9 Oct 2022 18:26:51 +0100 Subject: [PATCH 051/113] Add new code contributions section to README table of contents. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0d295f..b8c7f51 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ later 32-bit or 64-bit CPU. * [Memtest86+ Test Algorithms](#memory-testing-philosophy) * [Individual Test Descriptions](#individual-test-descriptions) * [Known Limitations and Bugs](#known-limitations-and-bugs) + * [Code Contributions](#code-contributions) * [Acknowledgments](#acknowledgments) ## Origins From 5036aa197a4b7c80a4f60be7403da50a32c8610a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Wed, 12 Oct 2022 15:34:09 +0100 Subject: [PATCH 052/113] Provide a more user-oriented grub-memtest.iso. grub-memtest.iso was originally intended as a means of testing all the different boot modes. But as we publish it on memtest.org, let's have a more user-friendly version that provides menu entries for the most commonly needed boot options. The original test ISO can still be built by 'make GRUB_CFG=grub-test grub-iso'. --- build32/Makefile | 19 +++++++++++++------ build64/Makefile | 19 +++++++++++++------ grub/grub-efi.cfg | 14 ++++++-------- grub/grub-legacy.cfg | 14 ++++++-------- grub/grub-test-efi.cfg | 22 ++++++++++++++++++++++ grub/grub-test-legacy.cfg | 22 ++++++++++++++++++++++ 6 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 grub/grub-test-efi.cfg create mode 100644 grub/grub-test-legacy.cfg diff --git a/build32/Makefile b/build32/Makefile index 51cd440..8f3d427 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -169,8 +169,13 @@ iso: memtest.iso clean: rm -rf boot system lib tests app *.img *.iso memtest* iso grub-* -# grub-memtest.iso can be used for testing the various different boot modes, -# using GRUB as an intermediate bootloader. Upstream GRUB only supports the +# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+ +# to be started with the native USB keyboard drivers either enabled or disabled, +# or to be started in a fail-safe mode with SMP and memory identification & +# speed testing disabled. +# +# By setting GRUB_CFG to "grub-test", grub-memtest.iso can instead be used for +# testing the various different boot modes. Upstream GRUB only supports the # 16-bit and 32-bit boot protocols, via the "linux16" and "linux" commands. # Fedora add support for the EFI handover boot protocols, via the "linuxefi" # command, and, since 2019, remove support for the 32-bit protocol, aliasing @@ -180,6 +185,8 @@ clean: # doubt do their own thing. The boot menu on grub-memtest.iso attempts to # support all these options. +GRUB_CFG ?= grub + GRUB_FONT_DIR ?= /usr/share/grub GRUB_LIB_DIR ?= /usr/lib/grub @@ -195,22 +202,22 @@ grub-eltorito.img: grub-bootia32.efi: $(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format i386-efi $(GRUB_MODULES) -grub-esp.img: memtest.efi grub-bootia32.efi ../grub/grub-efi.cfg +grub-esp.img: memtest.efi grub-bootia32.efi ../grub/${GRUB_CFG}-efi.cfg @mkdir -p grub-iso/EFI/BOOT/grub/i386-efi grub-iso/EFI/BOOT/grub/fonts cp memtest.efi grub-iso/EFI/BOOT/memtest cp grub-bootia32.efi grub-iso/EFI/BOOT/bootia32.efi - cp ../grub/grub-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg + cp ../grub/${GRUB_CFG}-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/EFI/BOOT/grub/fonts/ cp $(GRUB_LIB_DIR)/i386-efi/*.mod grub-iso/EFI/BOOT/grub/i386-efi/ @rm -f grub-esp.img /sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192 mcopy -s -i grub-esp.img grub-iso/EFI :: -grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/grub-legacy.cfg grub-esp.img +grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/${GRUB_CFG}-legacy.cfg grub-esp.img @mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts cp memtest.bin grub-iso/boot/memtest cp grub-eltorito.img grub-iso/boot/eltorito.img - cp ../grub/grub-legacy.cfg grub-iso/boot/grub/grub.cfg + cp ../grub/${GRUB_CFG}-legacy.cfg grub-iso/boot/grub/grub.cfg cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/ cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/ xorrisofs -pad -R -J -volid MT86PLUS_32 -graft-points -hide-rr-moved \ diff --git a/build64/Makefile b/build64/Makefile index 67d3a3f..17f46a2 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -168,8 +168,13 @@ iso: memtest.iso clean: rm -rf boot system lib tests app *.img *.iso memtest* iso grub-* -# grub-memtest.iso can be used for testing the various different boot modes, -# using GRUB as an intermediate bootloader. Upstream GRUB only supports the +# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+ +# to be started with the native USB keyboard drivers either enabled or disabled, +# or to be started in a fail-safe mode with SMP and memory identification & +# speed testing disabled. +# +# By setting GRUB_CFG to "grub-test", grub-memtest.iso can instead be used for +# testing the various different boot modes. Upstream GRUB only supports the # 16-bit and 32-bit boot protocols, via the "linux16" and "linux" commands. # Fedora add support for the EFI handover boot protocols, via the "linuxefi" # command, and, since 2019, remove support for the 32-bit protocol, aliasing @@ -179,6 +184,8 @@ clean: # doubt do their own thing. The boot menu on grub-memtest.iso attempts to # support all these options. +GRUB_CFG ?= grub + GRUB_FONT_DIR ?= /usr/share/grub GRUB_LIB_DIR ?= /usr/lib/grub @@ -194,22 +201,22 @@ grub-eltorito.img: grub-bootx64.efi: $(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format x86_64-efi $(GRUB_MODULES) -grub-esp.img: memtest.efi grub-bootx64.efi ../grub/grub-efi.cfg +grub-esp.img: memtest.efi grub-bootx64.efi ../grub/${GRUB_CFG}-efi.cfg @mkdir -p grub-iso/EFI/BOOT/grub/x86_64-efi grub-iso/EFI/BOOT/grub/fonts cp memtest.efi grub-iso/EFI/BOOT/memtest cp grub-bootx64.efi grub-iso/EFI/BOOT/bootx64.efi - cp ../grub/grub-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg + cp ../grub/${GRUB_CFG}-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/EFI/BOOT/grub/fonts/ cp $(GRUB_LIB_DIR)/x86_64-efi/*.mod grub-iso/EFI/BOOT/grub/x86_64-efi/ @rm -f grub-esp.img /sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192 mcopy -s -i grub-esp.img grub-iso/EFI :: -grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/grub-legacy.cfg grub-esp.img +grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/${GRUB_CFG}-legacy.cfg grub-esp.img @mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts cp memtest.bin grub-iso/boot/memtest cp grub-eltorito.img grub-iso/boot/eltorito.img - cp ../grub/grub-legacy.cfg grub-iso/boot/grub/grub.cfg + cp ../grub/${GRUB_CFG}-legacy.cfg grub-iso/boot/grub/grub.cfg cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/ cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/ xorrisofs -pad -R -J -volid MT86PLUS_64 -graft-points -hide-rr-moved \ diff --git a/grub/grub-efi.cfg b/grub/grub-efi.cfg index f8b5d3f..dbb3dc5 100644 --- a/grub/grub-efi.cfg +++ b/grub/grub-efi.cfg @@ -8,15 +8,13 @@ set default=0 set timeout=-1 insmod linux -insmod linuxefi -insmod linux32 -menuentry "Start Memtest86+ using 'linux' command" { - linux /EFI/BOOT/memtest +menuentry "Start Memtest86+, use built-in support for USB keyboards" { + linux /EFI/BOOT/memtest keyboard=both } -menuentry "Start Memtest86+ using 'linuxefi' command" { - linuxefi /EFI/BOOT/memtest +menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" { + linux /EFI/BOOT/memtest keyboard=legacy } -menuentry "Start Memtest86+ using 'linux32' command" { - linux32 /EFI/BOOT/memtest +menuentry "Start Memtest86+, disable SMP and memory identification" { + linux /EFI/BOOT/memtest nosmp nosm nobench } diff --git a/grub/grub-legacy.cfg b/grub/grub-legacy.cfg index cc0b742..c18cdbc 100644 --- a/grub/grub-legacy.cfg +++ b/grub/grub-legacy.cfg @@ -8,15 +8,13 @@ set default=0 set timeout=-1 insmod linux -insmod linux16 -insmod linux32 -menuentry "Start Memtest86+ using 'linux' command" { - linux /boot/memtest +menuentry "Start Memtest86+, use built-in support for USB keyboards" { + linux /boot/memtest keyboard=both } -menuentry "Start Memtest86+ using 'linux16' command" { - linux16 /boot/memtest +menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" { + linux /boot/memtest keyboard=legacy } -menuentry "Start Memtest86+ using 'linux32' command" { - linux32 /boot/memtest +menuentry "Start Memtest86+, disable SMP and memory identification" { + linux /boot/memtest nosmp nosm nobench } diff --git a/grub/grub-test-efi.cfg b/grub/grub-test-efi.cfg new file mode 100644 index 0000000..f8b5d3f --- /dev/null +++ b/grub/grub-test-efi.cfg @@ -0,0 +1,22 @@ +if loadfont unicode ; then + set gfxmode=1024x768,800x600,auto + set gfxpayload=800x600,1024x768 + terminal_output gfxterm +fi + +set default=0 +set timeout=-1 + +insmod linux +insmod linuxefi +insmod linux32 + +menuentry "Start Memtest86+ using 'linux' command" { + linux /EFI/BOOT/memtest +} +menuentry "Start Memtest86+ using 'linuxefi' command" { + linuxefi /EFI/BOOT/memtest +} +menuentry "Start Memtest86+ using 'linux32' command" { + linux32 /EFI/BOOT/memtest +} diff --git a/grub/grub-test-legacy.cfg b/grub/grub-test-legacy.cfg new file mode 100644 index 0000000..cc0b742 --- /dev/null +++ b/grub/grub-test-legacy.cfg @@ -0,0 +1,22 @@ +if loadfont unicode ; then + set gfxmode=1024x768,800x600,auto + set gfxpayload=800x600,1024x768 + terminal_output gfxterm +fi + +set default=0 +set timeout=-1 + +insmod linux +insmod linux16 +insmod linux32 + +menuentry "Start Memtest86+ using 'linux' command" { + linux /boot/memtest +} +menuentry "Start Memtest86+ using 'linux16' command" { + linux16 /boot/memtest +} +menuentry "Start Memtest86+ using 'linux32' command" { + linux32 /boot/memtest +} From 1ee1078cf5a9a68f595af2fceac10ef95fb8aa27 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Sun, 23 Oct 2022 17:32:17 +0200 Subject: [PATCH 053/113] V6.00 Final Release PR (#187) * Avoid FAIL banner being partially overwriten by new errors * Remove beta on main title * Remove v6 Beta Disclaimer & some README.me changes for release --- README.md | 34 +++++++++++++++++++--------------- app/display.c | 13 +++++++++++-- app/error.c | 3 +++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b8c7f51..f96c31e 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,21 @@ ---- -[DISCLAIMER] Memtest86+ v6.0 is NOT READY FOR PRODUCTION yet. The base code has basically been rewritten from scratch and many side functions are still under active development. A lot of additional beta-testing is needed. Please consider the actual code as experimental and expect crashes and freezes. Bugs reports are welcome and very helpful! Binary beta release are available on [memtest.org](https://memtest.org). The first production-ready stable release is planned for this summer. - ---- - # Memtest86+ -Memtest86+ is a stand-alone memory tester for x86 and x86-64 architecture -computers. It provides a more thorough memory check than that provided by -BIOS memory tests. +Memtest86+ is a free, open-source, stand-alone memory tester for x86 and +x86-64 architecture computers. It provides a much more thorough memory +check than that provided by BIOS memory tests. + +It is also able to access almost all the computer's memory, not being +restricted by the memory used by the operating system and not depending +on any underlying software like UEFI libraries. Memtest86+ can be loaded and run either directly by a PC BIOS (legacy or UEFI) or via an intermediate bootloader that supports the Linux 16-bit, 32-bit, 64-bit, or EFI handover boot protocol. It should work on any Pentium class or later 32-bit or 64-bit CPU. +Binary releases (both stable and nightly dev builds) are available on +[memtest.org](https://memtest.org). + ## Table of Contents * [Origins](#origins) @@ -33,19 +35,19 @@ later 32-bit or 64-bit CPU. ## Origins -Memtest86+ v6.0 was based on PCMemTest, which was a fork and rewrite of the -earlier Memtest86+ v5.01, which in turn was a fork of Memtest86. The purpose +Memtest86+ v6.00 was based on PCMemTest, which was a fork and rewrite of the +earlier Memtest86+ v5, which in turn was a fork of MemTest-86. The purpose of the PCMemTest rewrite was to: * make the code more readable and easier to maintain * make the code 64-bit clean and support UEFI boot * fix failures seen when building with newer versions of GCC -In the process of creating PCMemTest, a number of features of Memtest86+ v5.01 +In the process of creating PCMemTest, a number of features of Memtest86+ v5 that were not strictly required for testing the system memory were dropped. In particular, no attempt was made to measure the cache and main memory speed, or -to identify and report the DRAM type. These features were added back in -Memtest86+ v6.0 to create a unified, fully-featured release. +to identify and report the DRAM type. These features were added back and expanded +in Memtest86+ v6.0 to create a unified, fully-featured release. ## Licensing @@ -106,8 +108,10 @@ For test purposes, there is also an option to build an ISO image that uses GRUB as an intermediate bootloader. See the `Makefile` in the `build32` or `build64` directory for details. The ISO image is both legacy and UEFI bootable, so you need GRUB modules for both legacy and EFI boot installed -on your build system. You may need to adjust some path and file names in -the make file to match the naming on your system. +on your build system (e.g. on Debian, the required GRUB modules are located +in packages `grub-pc-bin`, `grub-efi-ia32-bin` and `grub-efi-amd64-bin`). +You may need to adjust some path and file names in the Makefile to match +the naming on your system. The GRUB configuration files contained in the `grub` directory are there for use on the test ISO, but also serve as an example of how to boot Memtest86+ diff --git a/app/display.c b/app/display.c index d3446f5..8a638e0 100644 --- a/app/display.c +++ b/app/display.c @@ -103,7 +103,7 @@ void display_init(void) set_foreground_colour(BLACK); set_background_colour(WHITE); clear_screen_region(0, 0, 0, 27); - prints(0, 0, " Memtest86+ v6.00b3"); + prints(0, 0, " Memtest86+ v6.00"); set_foreground_colour(RED); printc(0, 14, '+'); set_foreground_colour(WHITE); @@ -390,6 +390,10 @@ void display_big_status(bool pass) void restore_big_status(void) { + if (!big_status_displayed) { + return; + } + restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer); big_status_displayed = false; } @@ -509,7 +513,7 @@ void do_tick(int my_cpu) if (clks_per_msec > 0) { uint64_t current_time = get_tsc(); - int secs = (current_time - run_start_time) / (1000 * (uint64_t)clks_per_msec); + int secs = (current_time - run_start_time) / (1000 * (uint64_t)clks_per_msec); int mins = secs / 60; secs %= 60; act_sec = secs; int hours = mins / 60; mins %= 60; display_run_time(hours, mins, secs); @@ -534,6 +538,11 @@ void do_tick(int my_cpu) // This only tick one time per second if (!timed_update_done) { + // Display FAIL banner if (new) errors detected + if (!big_status_displayed && error_count > 0) { + display_big_status(false); + } + // Update temperature display_temperature(); diff --git a/app/error.c b/app/error.c index b6da413..a47f313 100644 --- a/app/error.c +++ b/app/error.c @@ -151,6 +151,8 @@ static void common_err(error_type_t type, uintptr_t addr, testword_t good, testw { spin_lock(error_mutex); + restore_big_status(); + bool new_header = (error_count == 0) || (error_mode != last_error_mode); if (new_header) { clear_message_area(); @@ -369,6 +371,7 @@ void error_update(void) display_error_count(error_count); display_status("Failed!"); + // Display FAIL banner on first error if (error_count == 1) { display_big_status(false); } From d3bc8fa7c2a2400d9c4d58cee00168d39fa9d716 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 23 Oct 2022 20:21:09 +0200 Subject: [PATCH 054/113] V6.00 Final Release - Fix title '+' char shift --- app/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/display.c b/app/display.c index 8a638e0..32d40c0 100644 --- a/app/display.c +++ b/app/display.c @@ -105,7 +105,7 @@ void display_init(void) clear_screen_region(0, 0, 0, 27); prints(0, 0, " Memtest86+ v6.00"); set_foreground_colour(RED); - printc(0, 14, '+'); + printc(0, 15, '+'); set_foreground_colour(WHITE); set_background_colour(BLUE); prints(1, 0, "CLK/Temp: N/A | Pass %"); From 0beb172a0d834fab7d141745e4c3f941b8d4c7de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Oct 2022 11:04:33 +0200 Subject: [PATCH 055/113] Bump actions/stale from 5 to 6 (#175) Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/expired.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/expired.yml b/.github/workflows/expired.yml index 482bbcc..0874929 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@v5 + - uses: actions/stale@v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-milestones: 'future,alpha,beta,release' From 9a86f115f499ed0f5936453c7ad76055cc899bd5 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 27 Nov 2022 23:34:43 +0100 Subject: [PATCH 056/113] Add 'press any key to remove' message on banner By default, don't re-display FAIL banner after it has been discarded (#130 & #173) Add an option to re-display FAIL banner even if previously discarded --- app/config.c | 4 +++- app/config.h | 2 ++ app/display.c | 8 ++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/config.c b/app/config.c index 7a7ed82..d7aed27 100644 --- a/app/config.c +++ b/app/config.c @@ -104,7 +104,9 @@ power_save_t power_save = POWER_SAVE_HIGH; bool enable_tty = false; int tty_params_port = SERIAL_PORT_0x3F8; int tty_params_baud = SERIAL_DEFAULT_BAUDRATE; -int tty_update_period = 2; // Update TTY every 2 seconds (default) +int tty_update_period = 2; // Update TTY every 2 seconds (default) + +bool err_banner_redraw = false; // Redraw banner on new errors (if previsouly removed) //------------------------------------------------------------------------------ // Private Functions diff --git a/app/config.h b/app/config.h index 0a9f429..5b5e9a2 100644 --- a/app/config.h +++ b/app/config.h @@ -66,6 +66,8 @@ extern int tty_params_port; extern int tty_params_baud; extern int tty_update_period; +extern bool err_banner_redraw; + void config_init(void); void config_menu(bool initial); diff --git a/app/display.c b/app/display.c index 32d40c0..f9e879f 100644 --- a/app/display.c +++ b/app/display.c @@ -36,7 +36,7 @@ #define POP_STAT_C 18 #define POP_STAT_W 44 -#define POP_STAT_H 9 +#define POP_STAT_H 11 #define POP_STAT_LAST_R (POP_STAT_R + POP_STAT_H - 1) #define POP_STAT_LAST_C (POP_STAT_C + POP_STAT_W - 1) @@ -383,6 +383,10 @@ void display_big_status(bool pass) prints(POP_STAT_R+6, POP_STAT_C+5, "## ## ## ## ## "); prints(POP_STAT_R+7, POP_STAT_C+5, "## ## ## ###### ###### "); } + + prints(POP_STAT_R+8, POP_STAT_C+5, " "); + prints(POP_STAT_R+9, POP_STAT_C+5, "Press any key to remove this banner "); + set_background_colour(BLUE); set_foreground_colour(WHITE); big_status_displayed = true; @@ -539,7 +543,7 @@ void do_tick(int my_cpu) if (!timed_update_done) { // Display FAIL banner if (new) errors detected - if (!big_status_displayed && error_count > 0) { + if (err_banner_redraw && !big_status_displayed && error_count > 1) { display_big_status(false); } From 5a2bc4c960b4a15865a5d6823cf932b4d40df9a6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 10 Dec 2022 15:24:26 +0000 Subject: [PATCH 057/113] Skip segments in tests where the calculated chunk size is too small. If the memory map contains very small segments and we have many active CPUs, the tests that split the segments into chunks distributed across the CPUs may end up with chunks that are too small for the test algorithm. With 4K pages and the current limit of 256 active CPUs, this is currently only a problem for the block move and modulo-n tests, but if we ever support more than 512 active CPUs, it could affect the other tests too. For now, just skip segments that are too small in the affected tests. As it only affects the block move and modulo-n tests and only affects very small regions of memory, the loss of test coverage is negligable. This may fix issue #216. --- tests/block_move.c | 3 +++ tests/modulo_n.c | 3 +++ tests/mov_inv_fixed.c | 3 +++ tests/mov_inv_random.c | 2 ++ tests/mov_inv_walk1.c | 3 +++ 5 files changed, 14 insertions(+) diff --git a/tests/block_move.c b/tests/block_move.c index 979f05a..4dbafeb 100644 --- a/tests/block_move.c +++ b/tests/block_move.c @@ -39,6 +39,7 @@ int test_block_move(int my_cpu, int iterations) for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t)); + if ((end - start) < 15) continue; // we need at least 16 words for this test testword_t *p = start; testword_t *pe = start; @@ -89,6 +90,7 @@ int test_block_move(int my_cpu, int iterations) for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t)); + if ((end - start) < 15) continue; // we need at least 16 words for this test testword_t *p = start; testword_t *pe = start; @@ -201,6 +203,7 @@ int test_block_move(int my_cpu, int iterations) for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t)); + if ((end - start) < 15) continue; // we need at least 16 words for this test testword_t *p = start; testword_t *pe = start; diff --git a/tests/modulo_n.c b/tests/modulo_n.c index 75d01c8..00a1dda 100644 --- a/tests/modulo_n.c +++ b/tests/modulo_n.c @@ -39,6 +39,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t)); + if ((end - start) < (n - 1)) continue; // we need at least n words for this test end -= n; // avoids pointer overflow when incrementing p testword_t *p = start + offset; // we assume each chunk has at least 'n' words, so this won't overflow @@ -71,6 +72,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa for (int j = 0; j < vm_map_size; j++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if ((end - start) < (n - 1)) continue; // we need at least n words for this test int k = 0; testword_t *p = start; @@ -111,6 +113,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t)); + if ((end - start) < (n - 1)) continue; // we need at least n words for this test end -= n; // avoids pointer overflow when incrementing p testword_t *p = start + offset; // we assume each chunk has at least 'offset' words, so this won't overflow diff --git a/tests/mov_inv_fixed.c b/tests/mov_inv_fixed.c index 80124b3..8320766 100644 --- a/tests/mov_inv_fixed.c +++ b/tests/mov_inv_fixed.c @@ -41,6 +41,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; @@ -99,6 +100,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword for (int j = 0; j < vm_map_size; j++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; @@ -134,6 +136,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword for (int j = vm_map_size - 1; j >= 0; j--) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = end; testword_t *ps = end; diff --git a/tests/mov_inv_random.c b/tests/mov_inv_random.c index cbdaf34..d487c88 100644 --- a/tests/mov_inv_random.c +++ b/tests/mov_inv_random.c @@ -51,6 +51,7 @@ int test_mov_inv_random(int my_cpu) for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; @@ -88,6 +89,7 @@ int test_mov_inv_random(int my_cpu) for (int j = 0; j < vm_map_size; j++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; diff --git a/tests/mov_inv_walk1.c b/tests/mov_inv_walk1.c index aed8306..78ba7e5 100644 --- a/tests/mov_inv_walk1.c +++ b/tests/mov_inv_walk1.c @@ -41,6 +41,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse) for (int i = 0; i < vm_map_size; i++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; @@ -78,6 +79,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse) for (int j = 0; j < vm_map_size; j++) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = start; testword_t *pe = start; @@ -115,6 +117,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse) for (int j = vm_map_size - 1; j >= 0; j--) { testword_t *start, *end; calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t)); + if (end < start) continue; // we need at least one word for this test testword_t *p = end; testword_t *ps = end; From 036922ab26a39f5548b7e8707dd7bfd37b9a0a1e Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Fri, 30 Dec 2022 16:41:28 +0100 Subject: [PATCH 058/113] Bump version to v6.01 --- app/display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/display.c b/app/display.c index f9e879f..bd154e5 100644 --- a/app/display.c +++ b/app/display.c @@ -103,7 +103,7 @@ void display_init(void) set_foreground_colour(BLACK); set_background_colour(WHITE); clear_screen_region(0, 0, 0, 27); - prints(0, 0, " Memtest86+ v6.00"); + prints(0, 0, " Memtest86+ v6.01"); set_foreground_colour(RED); printc(0, 15, '+'); set_foreground_colour(WHITE); @@ -137,7 +137,7 @@ void display_init(void) set_background_colour(WHITE); clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1); prints(ROW_FOOTER, 0, " Exit Configuration Scroll Lock"); - prints(ROW_FOOTER, 64, "6.00."); + prints(ROW_FOOTER, 64, "6.01."); prints(ROW_FOOTER, 69, GIT_HASH); #if TESTWORD_WIDTH > 32 prints(ROW_FOOTER, 76, ".x64"); From da7b9b955d51db55960088422cc7e7723d5e1728 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Tue, 3 Jan 2023 00:39:10 +0100 Subject: [PATCH 059/113] Move Memtest86+ version number to an external file (along with the the latest GIT commit hash) (#75) --- app/display.c | 7 +++---- app/version.h | 2 ++ build32/Makefile | 12 +++++++----- build64/Makefile | 12 +++++++----- 4 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 app/version.h diff --git a/app/display.c b/app/display.c index bd154e5..d279a27 100644 --- a/app/display.c +++ b/app/display.c @@ -22,7 +22,7 @@ #include "config.h" #include "error.h" -#include "githash.h" +#include "build_version.h" #include "tests.h" @@ -103,7 +103,7 @@ void display_init(void) set_foreground_colour(BLACK); set_background_colour(WHITE); clear_screen_region(0, 0, 0, 27); - prints(0, 0, " Memtest86+ v6.01"); + prints(0, 0, " Memtest86+ v" MT_VERSION); set_foreground_colour(RED); printc(0, 15, '+'); set_foreground_colour(WHITE); @@ -137,8 +137,7 @@ void display_init(void) set_background_colour(WHITE); clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1); prints(ROW_FOOTER, 0, " Exit Configuration Scroll Lock"); - prints(ROW_FOOTER, 64, "6.01."); - prints(ROW_FOOTER, 69, GIT_HASH); + prints(ROW_FOOTER, 64, MT_VERSION "." GIT_HASH); #if TESTWORD_WIDTH > 32 prints(ROW_FOOTER, 76, ".x64"); #else diff --git a/app/version.h b/app/version.h new file mode 100644 index 0000000..24065ce --- /dev/null +++ b/app/version.h @@ -0,0 +1,2 @@ +#define MT_VERSION "6.01" +#define GIT_HASH "unknown" diff --git a/build32/Makefile b/build32/Makefile index 8f3d427..c02c6b3 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -106,20 +106,22 @@ tests/%.o: ../tests/%.c @mkdir -p tests $(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d) -app/%.o: ../app/%.c app/githash.h +app/%.o: ../app/%.c app/build_version.h @mkdir -p app $(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d) -app/githash.h: FORCE +app/build_version.h: FORCE @mkdir -p app @( \ + cp -f ../app/version.h $@.tmp; \ if $(GIT_AVAILABLE) && test -d ../.git ; then \ hash=`git rev-parse HEAD | cut -c1-7`; \ + sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \ else \ - hash="unknown"; \ + sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \ fi; \ - define=`echo "#define GIT_HASH \"$$hash\""`; \ - echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \ + cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \ + rm -f $@.tmp; \ ) FORCE: diff --git a/build64/Makefile b/build64/Makefile index 17f46a2..1696c80 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -105,20 +105,22 @@ tests/%.o: ../tests/%.c @mkdir -p tests $(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d) -app/%.o: ../app/%.c app/githash.h +app/%.o: ../app/%.c app/build_version.h @mkdir -p app $(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d) -app/githash.h: FORCE +app/build_version.h: FORCE @mkdir -p app @( \ + cp -f ../app/version.h $@.tmp; \ if $(GIT_AVAILABLE) && test -d ../.git ; then \ hash=`git rev-parse HEAD | cut -c1-7`; \ + sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \ else \ - hash="unknown"; \ + sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \ fi; \ - define=`echo "#define GIT_HASH \"$$hash\""`; \ - echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \ + cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \ + rm -f $@.tmp; \ ) FORCE: From 59a09960705a0630f48c61b0c210f00f26a7ea7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 00:40:55 +0100 Subject: [PATCH 060/113] Bump actions/stale from 6 to 7 (#222) Bumps [actions/stale](https://github.com/actions/stale) from 6 to 7. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/expired.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/expired.yml b/.github/workflows/expired.yml index 0874929..7e48f6e 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@v6 + - uses: actions/stale@v7 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-milestones: 'future,alpha,beta,release' From f96c5b5093ac9a3d26f7457b528239656fdad316 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 30 Mar 2022 14:58:49 -0400 Subject: [PATCH 061/113] Use gcc -x assembler-with-cpp instead of gcc -E --traditional This patch makes it so we use "gcc -x assembler-with-cpp" to build our .S files, instead of translating them to .s files and assembling directly. This allows us to use header files and simple symbolic arithmetic more conveniently in .S files, and at the same time reduces the number of temporary files created when building. Signed-off-by: Peter Jones --- build32/Makefile | 10 ++++------ build64/Makefile | 11 ++++------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/build32/Makefile b/build32/Makefile index c02c6b3..b38aa50 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -75,16 +75,14 @@ all: memtest.bin memtest.efi -include $(subst .o,.d,$(TST_OBJS)) -include $(subst .o,.d,$(APP_OBJS)) -boot/%.o: boot/%.s - $(AS) $< -o $@ -boot/startup.s: ../boot/startup32.S ../boot/boot.h +boot/startup.o: ../boot/startup32.S ../boot/boot.h @mkdir -p boot - $(CC) -m32 -E -traditional -I../boot -o $@ $< + $(CC) -m32 -x assembler-with-cpp -c -I../boot -o $@ $< -boot/%.s: ../boot/%.S ../boot/boot.h +boot/%.o: ../boot/%.S ../boot/boot.h @mkdir -p boot - $(CC) -m32 -E -traditional -I../boot -o $@ $< + $(CC) -m32 -x assembler-with-cpp -c -I../boot -o $@ $< boot/efisetup.o: ../boot/efisetup.c @mkdir -p boot diff --git a/build64/Makefile b/build64/Makefile index 1696c80..3539906 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -74,16 +74,13 @@ all: memtest.bin memtest.efi -include $(subst .o,.d,$(TST_OBJS)) -include $(subst .o,.d,$(APP_OBJS)) -boot/%.o: boot/%.s - $(AS) $< -o $@ - -boot/startup.s: ../boot/startup64.S ../boot/boot.h +boot/startup.o: ../boot/startup64.S ../boot/boot.h @mkdir -p boot - $(CC) -E -traditional -I../boot -o $@ $< + $(CC) -x assembler-with-cpp -c -I../boot -o $@ $< -boot/%.s: ../boot/%.S ../boot/boot.h +boot/%.o: ../boot/%.S ../boot/boot.h @mkdir -p boot - $(CC) -E -traditional -I../boot -o $@ $< + $(CC) -x assembler-with-cpp -c -I../boot -o $@ $< boot/efisetup.o: ../boot/efisetup.c @mkdir -p boot From 87f03f3b10ece1fa6b6d37f5716dfc5d99e1bf89 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 30 Mar 2022 15:02:54 -0400 Subject: [PATCH 062/113] Add declarations and defines for PE images This adds a header file to describe the PE binary we're building. This has constants defined for all the values we use in the PE headers, as well as the structures for reference (guarded by #ifdef __ASSEMBLY__). This particular peimage.h is originally from binutils-2.10.0.18, which is GPLv2 licensed, and is copyright the Free Software Foundation. I've added the few additional fields we need. Signed-off-by: Peter Jones --- boot/peimage.h | 292 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 boot/peimage.h diff --git a/boot/peimage.h b/boot/peimage.h new file mode 100644 index 0000000..ad18594 --- /dev/null +++ b/boot/peimage.h @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +// This is include/coff/pe.h from binutils-2.10.0.18 +// Copyright The Free Software Foundation + +/* PE COFF header information */ + +#ifndef _PE_H +#define _PE_H + +/* NT specific file attributes. */ +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* Additional flags to be set for section headers to allow the NT loader to + read and write to the section data (to replace the addresses of data in + dlls for one thing); also to execute the section in .text's case. */ +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +/* Section characteristics added for ppc-nt. */ + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */ + +#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ + +#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */ +#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */ +#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */ + +#define IMAGE_SCN_MEM_FARDATA 0x00008000 + +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000 +#define IMAGE_SCN_ALIGN_8129BYTES 0x00e00000 + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */ +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */ +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ +#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 + +/* COMDAT selection codes. */ + +#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */ +#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */ +#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */ +#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */ +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */ + +/* Machine numbers. */ + +#define IMAGE_FILE_MACHINE_UNKNOWN 0x0 +#define IMAGE_FILE_MACHINE_ALPHA 0x184 +#define IMAGE_FILE_MACHINE_ARM 0x1c0 +#define IMAGE_FILE_MACHINE_ALPHA64 0x284 +#define IMAGE_FILE_MACHINE_I386 0x14c +#define IMAGE_FILE_MACHINE_IA64 0x200 +#define IMAGE_FILE_MACHINE_M68K 0x268 +#define IMAGE_FILE_MACHINE_MIPS16 0x266 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x466 +#define IMAGE_FILE_MACHINE_POWERPC 0x1f0 +#define IMAGE_FILE_MACHINE_R3000 0x162 +#define IMAGE_FILE_MACHINE_R4000 0x166 +#define IMAGE_FILE_MACHINE_R10000 0x168 +#define IMAGE_FILE_MACHINE_SH3 0x1a2 +#define IMAGE_FILE_MACHINE_SH4 0x1a6 +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x1c2 +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 + +/* Magic values that are true for all dos/nt implementations */ +#define DOSMAGIC 0x5a4d +#define NT_SIGNATURE 0x00004550 + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b + +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +/* NT allows long filenames, we want to accommodate this. This may break + some of the bfd functions */ +#undef FILNMLEN +#define FILNMLEN 18 /* # characters in a file name */ + +#ifndef __ASSEMBLY__ +struct external_PEI_filehdr +{ + /* DOS header fields - always at offset zero in the EXE file */ + char e_magic[2]; /* Magic number, 0x5a4d */ + char e_cblp[2]; /* Bytes on last page of file, 0x90 */ + char e_cp[2]; /* Pages in file, 0x3 */ + char e_crlc[2]; /* Relocations, 0x0 */ + char e_cparhdr[2]; /* Size of header in paragraphs, 0x4 */ + char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0 */ + char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF */ + char e_ss[2]; /* Initial (relative) SS value, 0x0 */ + char e_sp[2]; /* Initial SP value, 0xb8 */ + char e_csum[2]; /* Checksum, 0x0 */ + char e_ip[2]; /* Initial IP value, 0x0 */ + char e_cs[2]; /* Initial (relative) CS value, 0x0 */ + char e_lfarlc[2]; /* File address of relocation table, 0x40 */ + char e_ovno[2]; /* Overlay number, 0x0 */ + char e_res[4][2]; /* Reserved words, all 0x0 */ + char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0 */ + char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0 */ + char e_res2[10][2]; /* Reserved words, all 0x0 */ + char e_lfanew[4]; /* File address of new exe header, usually 0x80 */ + char dos_message[16][4]; /* other stuff, always follow DOS header */ + + /* Note: additional bytes may be inserted before the signature. Use + the e_lfanew field to find the actual location of the NT signature */ + + char nt_signature[4]; /* required NT signature, 0x4550 */ + + /* From standard header */ + + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; +#endif + +#ifdef COFF_IMAGE_WITH_PE + +/* The filehdr is only weird in images. */ + +#undef FILHDR +#define FILHDR struct external_PEI_filehdr +#undef FILHSZ +#define FILHSZ 152 + +#endif /* COFF_IMAGE_WITH_PE */ + +/* 32-bit PE a.out header: */ + +#ifndef __ASSEMBLY__ +typedef struct +{ + AOUTHDR standard; + + /* NT extra fields; see internal.h for descriptions */ + char ImageBase[4]; + char SectionAlignment[4]; + char FileAlignment[4]; + char MajorOperatingSystemVersion[2]; + char MinorOperatingSystemVersion[2]; + char MajorImageVersion[2]; + char MinorImageVersion[2]; + char MajorSubsystemVersion[2]; + char MinorSubsystemVersion[2]; + char Reserved1[4]; + char SizeOfImage[4]; + char SizeOfHeaders[4]; + char CheckSum[4]; + char Subsystem[2]; + char DllCharacteristics[2]; + char SizeOfStackReserve[4]; + char SizeOfStackCommit[4]; + char SizeOfHeapReserve[4]; + char SizeOfHeapCommit[4]; + char LoaderFlags[4]; + char NumberOfRvaAndSizes[4]; + /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ + char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */ +} PEAOUTHDR; +#endif +#undef AOUTSZ +#define AOUTSZ (AOUTHDRSZ + 196) + +/* Like PEAOUTHDR, except that the "standard" member has no BaseOfData + (aka data_start) member and that some of the members are 8 instead + of just 4 bytes long. */ +#ifndef __ASSEMBLY__ +typedef struct +{ + AOUTHDR standard; + + /* NT extra fields; see internal.h for descriptions */ + char ImageBase[8]; + char SectionAlignment[4]; + char FileAlignment[4]; + char MajorOperatingSystemVersion[2]; + char MinorOperatingSystemVersion[2]; + char MajorImageVersion[2]; + char MinorImageVersion[2]; + char MajorSubsystemVersion[2]; + char MinorSubsystemVersion[2]; + char Reserved1[4]; + char SizeOfImage[4]; + char SizeOfHeaders[4]; + char CheckSum[4]; + char Subsystem[2]; + char DllCharacteristics[2]; + char SizeOfStackReserve[8]; + char SizeOfStackCommit[8]; + char SizeOfHeapReserve[8]; + char SizeOfHeapCommit[8]; + char LoaderFlags[4]; + char NumberOfRvaAndSizes[4]; + /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ + char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */ +} PEP64AOUTHDR; +#endif +#define PEP64AOUTSZ 240 + +#undef E_FILNMLEN +#define E_FILNMLEN 18 /* # characters in a file name */ + +/* Import Tyoes fot ILF format object files.. */ +#define IMPORT_CODE 0 +#define IMPORT_DATA 1 +#define IMPORT_CONST 2 + +/* Import Name Tyoes for ILF format object files. */ +#define IMPORT_ORDINAL 0 +#define IMPORT_NAME 1 +#define IMPORT_NAME_NOPREFIX 2 +#define IMPORT_NAME_UNDECORATE 3 + +#endif /* _PE_H */ From e3c0d6df60f577624f66e13c4fa230b8d4d062cc Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 30 Mar 2022 15:11:21 -0400 Subject: [PATCH 063/113] Make header.S use symbolic names for values This changes header.S to use the constants defined in peimage.h to for the values in its structure, making it a lot easier to debug. Signed-off-by: Peter Jones --- boot/header.S | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/boot/header.S b/boot/header.S index a101966..f6e1e31 100644 --- a/boot/header.S +++ b/boot/header.S @@ -21,6 +21,7 @@ #define __ASSEMBLY__ #include "boot.h" +#include "peimage.h" # The EFI loader loads the header at ImageBase, so we have to locate the main program # after that. This means we can't load the main program at HIGH_LOAD_ADDR. Pick a load @@ -85,9 +86,9 @@ pe_header: coff_header: #ifdef __x86_64__ - .word 0x8664 # Machine (x86-64) + .word IMAGE_FILE_MACHINE_X64 # Machine (x86-64) #else - .word 0x14c # Machine (i386) + .word IMAGE_FILE_MACHINE_I386 # Machine (i386) #endif .word 1 # NumberOfSections .long 0 # TimeDateStamp @@ -95,27 +96,25 @@ coff_header: .long 0 # NumberOfSymbols .word section_table - optional_header # SizeOfOptionalHeader #ifdef __x86_64__ - .word 0x20f # Characteristics - # IMAGE_FILE_DEBUG_STRIPPED | - # IMAGE_FILE_LOCAL_SYMS_STRIPPED | - # IMAGE_FILE_LINE_NUMS_STRIPPED | - # IMAGE_FILE_EXECUTABLE_IMAGE | - # IMAGE_FILE_RELOCS_STRIPPED + .word IMAGE_FILE_DEBUG_STRIPPED \ + | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ + | IMAGE_FILE_LINE_NUMS_STRIPPED \ + | IMAGE_FILE_EXECUTABLE_IMAGE \ + | IMAGE_FILE_RELOCS_STRIPPED # Characteristics #else - .word 0x30f # Characteristics. - # IMAGE_FILE_32BIT_MACHINE | - # IMAGE_FILE_DEBUG_STRIPPED | - # IMAGE_FILE_LOCAL_SYMS_STRIPPED | - # IMAGE_FILE_LINE_NUMS_STRIPPED | - # IMAGE_FILE_EXECUTABLE_IMAGE | - # IMAGE_FILE_RELOCS_STRIPPED + .word IMAGE_FILE_32BIT_MACHINE \ + | IMAGE_FILE_DEBUG_STRIPPED \ + | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ + | IMAGE_FILE_LINE_NUMS_STRIPPED \ + | IMAGE_FILE_EXECUTABLE_IMAGE \ + | IMAGE_FILE_RELOCS_STRIPPED # Characteristics. #endif optional_header: #ifdef __x86_64__ - .word 0x20b # PE32+ format + .word IMAGE_NT_OPTIONAL_HDR64_MAGIC # PE32+ format #else - .word 0x10b # PE32 format + .word IMAGE_NT_OPTIONAL_HDR32_MAGIC # PE32 format #endif .byte 0x02 # MajorLinkerVersion .byte 0x14 # MinorLinkerVersion @@ -128,7 +127,7 @@ optional_header: .long BASE_OF_CODE # BaseOfCode #ifndef __x86_64__ - .long 0 # data + .long 0 # BaseOfData #endif extra_header_fields: @@ -180,7 +179,10 @@ section_table: .long 0 # PointerToLineNumbers .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers - .long 0x60500020 # Characteristics (section flags) + .long IMAGE_SCN_MEM_READ \ + | IMAGE_SCN_MEM_EXECUTE \ + | IMAGE_SCN_ALIGN_16BYTES \ + | IMAGE_SCN_CNT_CODE # Characteristics (section flags) # Emulate the Linux boot header, to allow loading by intermediate boot loaders. From 3dd1fa89590d2b7c8e3f9d8a2c581ff02b899c20 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 31 Mar 2022 13:26:24 -0400 Subject: [PATCH 064/113] EFI: Add Data Directory space Currently, the PE headers we create in boot/header.S do not allocate space for any Data Directory entries, as they haven't been needed. In order to support signatures and compatibility with some loaders, we need the Data Directory to be populated at least enough to set DataDirectory.Certs and DataDirectory.BaseReloc. This patch extends that space enough to include those entries. Signed-off-by: Peter Jones --- boot/header.S | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/boot/header.S b/boot/header.S index f6e1e31..ddb7867 100644 --- a/boot/header.S +++ b/boot/header.S @@ -163,7 +163,20 @@ extra_header_fields: .long 0 # SizeOfHeapCommit #endif .long 0 # LoaderFlags - .long 0 # NumberOfRvaAndSizes + .long IMAGE_DIRECTORY_ENTRY_DEBUG # NumberOfRvaAndSizes + + .long 0 # DataDirectory.Export.VirtualAddress + .long 0 # DataDirectory.Export.Size + .long 0 # DataDirectory.Import.VirtualAddress + .long 0 # DataDirectory.Import.Size + .long 0 # DataDirectory.Resource.VirtualAddress + .long 0 # DataDirectory.Resource.Size + .long 0 # DataDirectory.Exception.VirtualAddress + .long 0 # DataDirectory.Exception.Size + .long 0 # DataDirectory.Certs.VirtualAddress + .long 0 # DataDirectory.Certs.Size + .long 0 # DataDirectory.BaseReloc.VirtualAddress + .long 0 # DataDirectory.BaseReloc.Size # Section table section_table: From e02244154456a663e3b3b3ff0ebf08bf3b5fcba6 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 31 Mar 2022 13:32:14 -0400 Subject: [PATCH 065/113] Fix Pe.OptHdr.SizeOfImage and SizeOfHeaders SizeOfImage is defined as: The size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of SectionAlignment. SizeOfHeaders likewise is defined as: The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment. Currently SizeOfImage represents .bss and .text, but it doesn't include .header or .setup, nor any sections we'll add later, and there's nothing enforcing that it matches SectionAlignment. Additionally, since .bss is being set up in our running code and /not/ by the loader, the current value is dangerously high, as in the event there is an error in the section table, it could potentially lead the loader to mark memory allocated at runtime holding user-supplied data by any EFI binary loaded before us as executable. This patch adds a new symbol, _img_end, which is after .text and is rounded up to 4kB (which is also what SectionAlignment is set to). It also adds a local label, anchored with ".org 512", and uses that to set SizeOfHeaders - this will ensure the build fails without outputting and invalid binary if the headers take too much space. Signed-off-by: Peter Jones --- boot/header.S | 7 +++++-- build32/ldscripts/memtest_efi.lds | 2 ++ build64/ldscripts/memtest_efi.lds | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/boot/header.S b/boot/header.S index ddb7867..90a4389 100644 --- a/boot/header.S +++ b/boot/header.S @@ -146,8 +146,8 @@ extra_header_fields: .word 0 # MinorSubsystemVersion .long 0 # Win32VersionValue - .long BASE_OF_CODE + _init_size # SizeOfImage - .long 512 # SizeOfHeaders + .long BASE_OF_CODE + _img_end # SizeOfImage + .long end_of_headers # SizeOfHeaders .long 0 # CheckSum .word 10 # Subsystem (EFI application) .word 0 # DllCharacteristics @@ -214,3 +214,6 @@ root_dev: .word 0 boot_flag: .word 0xAA55 + + .org 512 +end_of_headers: diff --git a/build32/ldscripts/memtest_efi.lds b/build32/ldscripts/memtest_efi.lds index 2b1fede..f9a4470 100644 --- a/build32/ldscripts/memtest_efi.lds +++ b/build32/ldscripts/memtest_efi.lds @@ -17,6 +17,8 @@ SECTIONS { . = ALIGN(512); _text_end = . ; } + . = ALIGN(4096); + _img_end = . ; /DISCARD/ : { *(*) } _text_size = (_text_end - _text_start); diff --git a/build64/ldscripts/memtest_efi.lds b/build64/ldscripts/memtest_efi.lds index c06b6d3..c783548 100644 --- a/build64/ldscripts/memtest_efi.lds +++ b/build64/ldscripts/memtest_efi.lds @@ -17,6 +17,8 @@ SECTIONS { . = ALIGN(512); _text_end = . ; } + . = ALIGN(4096); + _img_end = . ; /DISCARD/ : { *(*) } _text_size = (_text_end - _text_start); From d1014365c1a32376b190a4eda7c67314e582ef2c Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 31 Mar 2022 13:24:59 -0400 Subject: [PATCH 066/113] EFI: Add a dummy relocation section In the past, we've seen some problems with some EFI loaders refusing to load a binary that has both a .text section with the VMA set and no relocations, when the VMA set to load is already allocated for some other purpose. This patch adds a dummy absolute relocation from 0 to 0, so the loader can always feel like it has done something useful. Signed-off-by: Peter Jones --- boot/header.S | 32 ++++++++++++++++++++++++------- build32/ldscripts/memtest_efi.lds | 7 +++++++ build64/ldscripts/memtest_efi.lds | 7 +++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/boot/header.S b/boot/header.S index 90a4389..c922a44 100644 --- a/boot/header.S +++ b/boot/header.S @@ -90,7 +90,7 @@ coff_header: #else .word IMAGE_FILE_MACHINE_I386 # Machine (i386) #endif - .word 1 # NumberOfSections + .word 2 # NumberOfSections .long 0 # TimeDateStamp .long 0 # PointerToSymbolTable .long 0 # NumberOfSymbols @@ -99,15 +99,13 @@ coff_header: .word IMAGE_FILE_DEBUG_STRIPPED \ | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ | IMAGE_FILE_LINE_NUMS_STRIPPED \ - | IMAGE_FILE_EXECUTABLE_IMAGE \ - | IMAGE_FILE_RELOCS_STRIPPED # Characteristics + | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics #else .word IMAGE_FILE_32BIT_MACHINE \ | IMAGE_FILE_DEBUG_STRIPPED \ | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ | IMAGE_FILE_LINE_NUMS_STRIPPED \ - | IMAGE_FILE_EXECUTABLE_IMAGE \ - | IMAGE_FILE_RELOCS_STRIPPED # Characteristics. + | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics. #endif optional_header: @@ -175,8 +173,8 @@ extra_header_fields: .long 0 # DataDirectory.Exception.Size .long 0 # DataDirectory.Certs.VirtualAddress .long 0 # DataDirectory.Certs.Size - .long 0 # DataDirectory.BaseReloc.VirtualAddress - .long 0 # DataDirectory.BaseReloc.Size + .long _reloc_start # DataDirectory.BaseReloc.VirtualAddress + .long _reloc_size # DataDirectory.BaseReloc.Size # Section table section_table: @@ -197,6 +195,21 @@ section_table: | IMAGE_SCN_ALIGN_16BYTES \ | IMAGE_SCN_CNT_CODE # Characteristics (section flags) + .ascii ".reloc" + .byte 0 + .byte 0 + .long _reloc_size # VirtualSize + .long _reloc_start # VirtualAddress + .long _reloc_size # SizeOfRawData + .long _reloc_start # PointerToRawData + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long IMAGE_SCN_MEM_READ \ + | IMAGE_SCN_ALIGN_4BYTES \ + | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) + # Emulate the Linux boot header, to allow loading by intermediate boot loaders. .org 497 @@ -217,3 +230,8 @@ boot_flag: .org 512 end_of_headers: + +.section ".reloc", "a", @progbits + .long 0 // Page RVA + .long 10 // Block Size (2*4+2) + .word (IMAGE_REL_AMD64_ABSOLUTE<<12) + 0 // reloc 0 -> 0 diff --git a/build32/ldscripts/memtest_efi.lds b/build32/ldscripts/memtest_efi.lds index f9a4470..69dd6ae 100644 --- a/build32/ldscripts/memtest_efi.lds +++ b/build32/ldscripts/memtest_efi.lds @@ -17,12 +17,19 @@ SECTIONS { . = ALIGN(512); _text_end = . ; } + . = ALIGN(512); + .reloc : { + _reloc_start = . ; + *(.reloc) + _reloc_end = . ; + } . = ALIGN(4096); _img_end = . ; /DISCARD/ : { *(*) } _text_size = (_text_end - _text_start); + _reloc_size = (_reloc_end - _reloc_start); _sys_size = _text_size >> 4; _init_size = _text_size + _bss_size; } diff --git a/build64/ldscripts/memtest_efi.lds b/build64/ldscripts/memtest_efi.lds index c783548..408336a 100644 --- a/build64/ldscripts/memtest_efi.lds +++ b/build64/ldscripts/memtest_efi.lds @@ -17,12 +17,19 @@ SECTIONS { . = ALIGN(512); _text_end = . ; } + . = ALIGN(512); + .reloc : { + _reloc_start = . ; + *(.reloc) + _reloc_end = . ; + } . = ALIGN(4096); _img_end = . ; /DISCARD/ : { *(*) } _text_size = (_text_end - _text_start); + _reloc_size = (_reloc_end - _reloc_start); _sys_size = _text_size >> 4; _init_size = _text_size + _bss_size; } From 04980dfda346fd0f7e6cb51d8e5b1ea88327b9c4 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 30 Mar 2022 15:16:31 -0400 Subject: [PATCH 067/113] EFI: Add support for .sbat signature revocations This patch adds a new section, ".sbat", which allows for the revocation of signed binaries given a numeric value representing the set of bugs which allow for arbitrary code execution, and therefore a Secure Boot breakout, in a given family of binaries. In this case, the class is defined as "memtest86+", and the current set of bugs is 1. This doesn't imply that we're aware of bugs currently, merely that when we change it to 2, any bugs that /have/ been discovered have been fixed. Documentation for how SBAT works can be found at the following URLs: https://github.com/rhboot/shim/blob/main/SBAT.md https://github.com/rhboot/shim/blob/main/SBAT.example.md Signed-off-by: Peter Jones --- boot/header.S | 25 ++++++++++++++++++++++--- boot/sbat.csv | 2 ++ build32/Makefile | 1 + build32/ldscripts/memtest_efi.lds | 8 ++++++++ build64/Makefile | 2 ++ build64/ldscripts/memtest_efi.lds | 8 ++++++++ 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 boot/sbat.csv diff --git a/boot/header.S b/boot/header.S index c922a44..673bc67 100644 --- a/boot/header.S +++ b/boot/header.S @@ -90,7 +90,7 @@ coff_header: #else .word IMAGE_FILE_MACHINE_I386 # Machine (i386) #endif - .word 2 # NumberOfSections + .word 3 # NumberOfSections .long 0 # TimeDateStamp .long 0 # PointerToSymbolTable .long 0 # NumberOfSymbols @@ -118,14 +118,14 @@ optional_header: .byte 0x14 # MinorLinkerVersion .long _text_size # SizeOfCode - .long 0 # SizeOfInitializedData + .long _sbat_size # SizeOfInitializedData .long 0 # SizeOfUninitializedData .long BASE_OF_CODE + 0x1e0 # AddressOfEntryPoint .long BASE_OF_CODE # BaseOfCode #ifndef __x86_64__ - .long 0 # BaseOfData + .long _sbat_start # BaseOfData #endif extra_header_fields: @@ -210,6 +210,22 @@ section_table: | IMAGE_SCN_ALIGN_4BYTES \ | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) + .ascii ".sbat" + .byte 0 + .byte 0 + .byte 0 + .long _sbat_size # VirtualSize + .long _sbat_start # VirtualAddress + .long _sbat_size # SizeOfRawData + .long _sbat_start # PointerToRawData + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long IMAGE_SCN_MEM_READ \ + | IMAGE_SCN_ALIGN_4096BYTES \ + | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) + # Emulate the Linux boot header, to allow loading by intermediate boot loaders. .org 497 @@ -235,3 +251,6 @@ end_of_headers: .long 0 // Page RVA .long 10 // Block Size (2*4+2) .word (IMAGE_REL_AMD64_ABSOLUTE<<12) + 0 // reloc 0 -> 0 + +.section ".sbat", "a", @progbits +.incbin "../boot/sbat.csv" diff --git a/boot/sbat.csv b/boot/sbat.csv new file mode 100644 index 0000000..a32b1cc --- /dev/null +++ b/boot/sbat.csv @@ -0,0 +1,2 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +memtest86+,1,Memtest86+,6.0,https://github.com/memtest86plus diff --git a/build32/Makefile b/build32/Makefile index b38aa50..a6b933d 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -75,6 +75,7 @@ all: memtest.bin memtest.efi -include $(subst .o,.d,$(TST_OBJS)) -include $(subst .o,.d,$(APP_OBJS)) +boot/header.o : | ../boot/sbat.csv boot/startup.o: ../boot/startup32.S ../boot/boot.h @mkdir -p boot diff --git a/build32/ldscripts/memtest_efi.lds b/build32/ldscripts/memtest_efi.lds index 69dd6ae..6c09fdb 100644 --- a/build32/ldscripts/memtest_efi.lds +++ b/build32/ldscripts/memtest_efi.lds @@ -23,6 +23,13 @@ SECTIONS { *(.reloc) _reloc_end = . ; } + . = ALIGN(512); + .sbat : { + _sbat_start = . ; + *(.sbat) + . = ALIGN(512); + _sbat_end = . ; + } . = ALIGN(4096); _img_end = . ; /DISCARD/ : { *(*) } @@ -30,6 +37,7 @@ SECTIONS { _text_size = (_text_end - _text_start); _reloc_size = (_reloc_end - _reloc_start); + _sbat_size = (_sbat_end - _sbat_start); _sys_size = _text_size >> 4; _init_size = _text_size + _bss_size; } diff --git a/build64/Makefile b/build64/Makefile index 3539906..b1b6ec4 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -74,6 +74,8 @@ all: memtest.bin memtest.efi -include $(subst .o,.d,$(TST_OBJS)) -include $(subst .o,.d,$(APP_OBJS)) +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 $@ $< diff --git a/build64/ldscripts/memtest_efi.lds b/build64/ldscripts/memtest_efi.lds index 408336a..ec27bbf 100644 --- a/build64/ldscripts/memtest_efi.lds +++ b/build64/ldscripts/memtest_efi.lds @@ -23,6 +23,13 @@ SECTIONS { *(.reloc) _reloc_end = . ; } + . = ALIGN(512); + .sbat : { + _sbat_start = . ; + *(.sbat) + . = ALIGN(512); + _sbat_end = . ; + } . = ALIGN(4096); _img_end = . ; /DISCARD/ : { *(*) } @@ -30,6 +37,7 @@ SECTIONS { _text_size = (_text_end - _text_start); _reloc_size = (_reloc_end - _reloc_start); + _sbat_size = (_sbat_end - _sbat_start); _sys_size = _text_size >> 4; _init_size = _text_size + _bss_size; } From d3d52b8a116cd18c1a5eba537e0e3ebe713adcd3 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Tue, 3 Jan 2023 01:35:51 +0100 Subject: [PATCH 068/113] Add Memtest86+ Version String to Kernel Header (#75) --- boot/setup.S | 7 ++++++- build32/Makefile | 2 +- build64/Makefile | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/boot/setup.S b/boot/setup.S index 2511741..6f02ce5 100644 --- a/boot/setup.S +++ b/boot/setup.S @@ -18,6 +18,7 @@ #define __ASSEMBLY__ #include "boot.h" +#include "build_version.h" #define BOOT_PARAMS_START (SETUP_SECS * 512) #define BOOT_PARAMS_END (BOOT_PARAMS_START + 4096) @@ -41,7 +42,7 @@ realmode_swtch: start_sys_seg: .word 0x1000 kernel_version: - .word 0 + .word mt86plus_version-512 type_of_loader: .byte 0 loadflags: @@ -385,6 +386,10 @@ idt_descr: .word 0 # idt limit=0 .long 0 # idt base=0 +mt86plus_version: + .ascii "Memtest86+ v" , MT_VERSION + .byte 0 + # Pad to the declared size. .org (SETUP_SECS*512) diff --git a/build32/Makefile b/build32/Makefile index a6b933d..bf77455 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -83,7 +83,7 @@ boot/startup.o: ../boot/startup32.S ../boot/boot.h boot/%.o: ../boot/%.S ../boot/boot.h @mkdir -p boot - $(CC) -m32 -x assembler-with-cpp -c -I../boot -o $@ $< + $(CC) -m32 -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< boot/efisetup.o: ../boot/efisetup.c @mkdir -p boot diff --git a/build64/Makefile b/build64/Makefile index b1b6ec4..29d118d 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -82,7 +82,7 @@ boot/startup.o: ../boot/startup64.S ../boot/boot.h boot/%.o: ../boot/%.S ../boot/boot.h @mkdir -p boot - $(CC) -x assembler-with-cpp -c -I../boot -o $@ $< + $(CC) -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< boot/efisetup.o: ../boot/efisetup.c @mkdir -p boot From 03cd8d18985cd80757f709fa790f3cf1a746c1f5 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 3 Jan 2023 11:38:55 +0000 Subject: [PATCH 069/113] Fix disabling SMP using F2 at startup dialogue. smp_init() used to be called after the startup dialogue, so F2 only needed to change the enable_smp flag. Now smp_init() is called earlier, we also need to reset num_available_cpus. --- app/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/main.c b/app/main.c index e7fcbbd..19098e6 100644 --- a/app/main.c +++ b/app/main.c @@ -255,6 +255,10 @@ static void global_init(void) clear_message_area(); + if (!smp_enabled) { + num_available_cpus = 1; + } + num_enabled_cpus = 0; for (int i = 0; i < num_available_cpus; i++) { if (cpu_state[i] == CPU_STATE_ENABLED) { From a1af48a8cf6965743c30295b2adddfbe3709e587 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 3 Jan 2023 11:55:51 +0000 Subject: [PATCH 070/113] Fix and improve documentation in heap.h (issue #232) --- system/heap.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/system/heap.h b/system/heap.h index 4c7e0ef..f2e60d1 100644 --- a/system/heap.h +++ b/system/heap.h @@ -32,9 +32,9 @@ void heap_init(void); * region will be at least the requested size with the requested alignment. * This memory is always mapped to the identical address in virtual memory. * + * \param heap_id - the target heap. * \param size - the requested size in bytes. * \param alignment - the requested byte alignment (must be a power of 2). - * \param heap - the heap on which this allocation shall be performed. * * \returns * On success, the allocated address in physical memory. On failure, 0. @@ -46,6 +46,8 @@ uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment); * memory heap. This value may be passed to heap_rewind() to free any * memory from that heap allocated after this call. * + * \param heap_id - the target heap. + * * \returns * An opaque value indicating the current allocation state. */ @@ -55,8 +57,8 @@ uintptr_t heap_mark(heap_type_t heap_id); * Frees any memory allocated in the given heap since the specified mark was * obtained from a call to heap_mark(). * + * \param heap_id - the target heap. * \param mark - the mark that indicates how much memory to free. - * \param heap - the heap on which this rewind shall be performed. */ void heap_rewind(heap_type_t heap_id, uintptr_t mark); From 1fca6dbcabd991452fa8e7132a86d49b0ac70b0c Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 3 Jan 2023 12:01:05 +0000 Subject: [PATCH 071/113] Update ,gitignore for build_version.h. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b3a1a9b..1ebf692 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ *.o # Generated file -githash.h +build_version.h # Binaries memtest_shared From 68deff493f47afa488f8abb4b492b01cb4ca8684 Mon Sep 17 00:00:00 2001 From: Anders Wenhaug Date: Tue, 3 Jan 2023 23:12:47 +0100 Subject: [PATCH 072/113] Change how BadRAM patterns are aggregated to minimize the number of covered addresses (#178) * BadRAM: Rename pattern -> patterns * BadRAM: Refactor COMBINE_MASK and add clarifying comment * BadRAM: Extract DEFAULT_MASK into variable * BadRAM: Add is_covered() for checking if pattern is already covered by one of the existing patterns * BadRAM: Initialize patterns to 0 * BadRAM: Change how addr/masks are merged to minimize number of addresses covered by badram Prior to this patch, a list of up to MAX_PATTERNS (=10) addr/mask tuples (aka. pattern) were maintained, adding failing addresses one by one to the list until it was full. When full, space was created by forcing a merge of the new address with the existing pattern that would grow the least (with regards to number of addresses covered by the pattern) by merging it with the new address. This can lead to a great imbalance in the number of addresses covered by the patterns. Consider the following: MAX_PATTERNS=4 (for illustrative purposes). The following addresses are faulted and added to patterns: 0x00, 0x10, 0x20, 0x68, 0xa0, 0xb0, 0xc0, 0xd0 This is the end result with the implementation prior to this commit: patterns = [ (0x00, 0xe8), (0x00, 0x18), (0x68, 0xf8), (0x90, 0x98) ] Total addresses covered: 120. This commit changes how the merges are done, not only considering a merge between the new address and existing patterns, but also between existing patterns. It keeps the patterns in ascending order (by .addr) in patterns, and a new address is always inserted into patterns (even if num_patterns == MAX_PATTERNS, patterns is of MAX_PATTERNS+1 size). Then, if num_patterns > MAX_PATTERNS, we find the pair of patterns (only considering neighbours, assuming for any pattern i, i-1 or i+1 will be the best candidate for a merge) that would be the cheapest to merge (using the same metric as prior to this patch), and merge those. With this commit, this is the result of the exact same sequence of addresses as above: [ (0x00, 0xe0), (0x68, 0xf8), (0xa0, 0xe8), (0xc0, 0xe8) ] Total addresses covered: 72. A drawback of the current implementation (as compared to the prior) is that it does not make any attempt at merging patterns until num_patterns == MAX_PATTERNS, which can lead to having several patterns that could've been merged into one at no additional cost. I.e.: patterns = [ (0x00, 0xf8), (0x08, 0xf8) ] can appear, even if patterns = [ (0x00, 0xf0) ] represents the exact same addresses with one pattern instead of two. * fixup! BadRAM: Change how addr/masks are merged to minimize number of addresses covered by badram Co-authored-by: Anders Wenhaug --- app/badram.c | 177 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 123 insertions(+), 54 deletions(-) diff --git a/app/badram.c b/app/badram.c index bd8fb47..0c5e552 100644 --- a/app/badram.c +++ b/app/badram.c @@ -34,6 +34,7 @@ //------------------------------------------------------------------------------ #define MAX_PATTERNS 10 +#define PATTERNS_SIZE (MAX_PATTERNS + 1) // DEFAULT_MASK covers a uintptr_t, since that is the testing granularity. #ifdef __x86_64__ @@ -55,14 +56,16 @@ typedef struct { // Private Variables //------------------------------------------------------------------------------ -static pattern_t pattern[MAX_PATTERNS]; +static pattern_t patterns[PATTERNS_SIZE]; static int num_patterns = 0; //------------------------------------------------------------------------------ // Private Functions //------------------------------------------------------------------------------ -#define COMBINE_MASK(a,b,c,d) ((a & b & c & d) | (~a & b & ~c & d)) +// New mask is 1 where both masks were 1 (b & d) and the addresses were equal ~(a ^ c). +// If addresses were unequal the new mask must be 0 to allow for both values. +#define COMBINE_MASK(a,b,c,d) ((b & d) & ~(a ^ c)) /* * Combine two addr/mask pairs to one addr/mask pair. @@ -72,7 +75,7 @@ static void combine(uintptr_t addr1, uintptr_t mask1, uintptr_t addr2, uintptr_t *mask = COMBINE_MASK(addr1, mask1, addr2, mask2); *addr = addr1 | addr2; - *addr &= *mask; // Normalise, no fundamental need for this + *addr &= *mask; // Normalise to ensure sorting on .addr will work as intended } /* @@ -104,58 +107,110 @@ static uintptr_t combi_cost(uintptr_t addr1, uintptr_t mask1, uintptr_t addr2, u } /* - * Find the cheapest array index to extend with the given addr/mask pair. - * Return -1 if nothing below the given minimum cost can be found. + * Determine if pattern is already covered by an existing pattern. + * Return true if that's the case, else false. */ -static int cheap_index(uintptr_t addr1, uintptr_t mask1, uintptr_t min_cost) +static bool is_covered(pattern_t pattern) { - int i = num_patterns; - int idx = -1; - while (i-- > 0) { - uintptr_t tmp_cost = combi_cost(pattern[i].addr, pattern[i].mask, addr1, mask1); - if (tmp_cost < min_cost) { + for (int i = 0; i < num_patterns; i++) { + if (combi_cost(patterns[i].addr, patterns[i].mask, pattern.addr, pattern.mask) == 0) { + return true; + } + } + return false; +} + +/* + * Find the pair of entries that would be the cheapest to merge. + * Assumes patterns is sorted by .addr asc and that for each index i, the cheapest entry to merge with is at i-1 or i+1. + * Return -1 if <= 1 patterns exist, else the index of the first entry of the pair (the other being that + 1). + */ +static int cheapest_pair() +{ + // This is guaranteed to be overwritten with >= 0 as long as num_patterns > 1 + int merge_idx = -1; + + uintptr_t min_cost = UINTPTR_MAX; + for (int i = 0; i < num_patterns - 1; i++) { + uintptr_t tmp_cost = combi_cost( + patterns[i].addr, + patterns[i].mask, + patterns[i+1].addr, + patterns[i+1].mask + ); + if (tmp_cost <= min_cost) { min_cost = tmp_cost; - idx = i; + merge_idx = i; } } - return idx; + return merge_idx; } /* - * Try to find a relocation index for idx if it costs nothing. - * Return -1 if no such index exists. + * Remove entries at idx and idx+1. */ -static int relocate_index(int idx) +static void remove_pair(int idx) { - uintptr_t addr = pattern[idx].addr; - uintptr_t mask = pattern[idx].mask; - pattern[idx].addr = ~pattern[idx].addr; // Never select idx - int new = cheap_index(addr, mask, 1 + addresses(mask)); - pattern[idx].addr = addr; - return new; + for (int i = idx; i < num_patterns - 2; i++) { + patterns[i] = patterns[i + 2]; + } + patterns[num_patterns - 1].addr = 0u; + patterns[num_patterns - 1].mask = 0u; + patterns[num_patterns - 2].addr = 0u; + patterns[num_patterns - 2].mask = 0u; + num_patterns -= 2; } /* - * Relocate the given index idx only if free of charge. - * This is useful to combine to `neighbouring' sections to integrate. - * Inspired on the Buddy memalloc principle in the Linux kernel. + * Get the combined entry of idx1 and idx2. */ -static void relocate_if_free(int idx) +static pattern_t combined_pattern(int idx1, int idx2) { - int newidx = relocate_index(idx); - if (newidx >= 0) { - uintptr_t caddr, cmask; - combine(pattern[newidx].addr, pattern[newidx].mask, - pattern[ idx].addr, pattern[ idx].mask, - &caddr, &cmask); - pattern[newidx].addr = caddr; - pattern[newidx].mask = cmask; - if (idx < --num_patterns) { - pattern[idx].addr = pattern[num_patterns].addr; - pattern[idx].mask = pattern[num_patterns].mask; - } - relocate_if_free (newidx); + pattern_t combined; + combine( + patterns[idx1].addr, + patterns[idx1].mask, + patterns[idx2].addr, + patterns[idx2].mask, + &combined.addr, + &combined.mask + ); + return combined; +} + +/* + * Insert pattern at index idx, shuffling other entries on index towards the end. + */ +static void insert_at(pattern_t pattern, int idx) +{ + // Move all entries >= idx one index towards the end to make space for the new entry + for (int i = num_patterns - 1; i >= idx; i--) { + patterns[i + 1] = patterns[i]; } + + patterns[idx] = pattern; + num_patterns++; +} + +/* + * Insert entry (addr, mask) in patterns in an index i so that patterns[i-1].addr < patterns[i] + * NOTE: Assumes patterns is already sorted by .addr asc! + */ +static void insert_sorted(pattern_t pattern) +{ + // Normalise to ensure sorting on .addr will work as intended + pattern.addr &= pattern.mask; + + // Find index to insert entry into + int new_idx = num_patterns; + for (int i = 0; i < num_patterns; i++) { + if (pattern.addr < patterns[i].addr) { + new_idx = i; + break; + } + } + + insert_at(pattern, new_idx); } //------------------------------------------------------------------------------ @@ -165,26 +220,40 @@ static void relocate_if_free(int idx) void badram_init(void) { num_patterns = 0; + + for (int idx = 0; idx < PATTERNS_SIZE; idx++) { + patterns[idx].addr = 0u; + patterns[idx].mask = 0u; + } } bool badram_insert(uintptr_t addr) { - if (cheap_index(addr, DEFAULT_MASK, 1) != -1) { + pattern_t pattern = { + .addr = addr, + .mask = DEFAULT_MASK + }; + + // If covered by existing entry we return immediately + if (is_covered(pattern)) { return false; } - if (num_patterns < MAX_PATTERNS) { - pattern[num_patterns].addr = addr; - pattern[num_patterns].mask = DEFAULT_MASK; - num_patterns++; - relocate_if_free(num_patterns - 1); - } else { - int idx = cheap_index(addr, DEFAULT_MASK, UINTPTR_MAX); - uintptr_t caddr, cmask; - combine(pattern[idx].addr, pattern[idx].mask, addr, DEFAULT_MASK, &caddr, &cmask); - pattern[idx].addr = caddr; - pattern[idx].mask = cmask; - relocate_if_free(idx); + // Add entry in order sorted by .addr asc + insert_sorted(pattern); + + // If we have more patterns than the max we need to force a merge + if (num_patterns > MAX_PATTERNS) { + // Find the pair that is the cheapest to merge + // merge_idx will be -1 if num_patterns < 2, but that means MAX_PATTERNS = 0 which is not a valid state anyway + int merge_idx = cheapest_pair(); + + pattern_t combined = combined_pattern(merge_idx, merge_idx + 1); + + // Remove the source pair so that we can maintain order as combined does not necessarily belong in merge_idx + remove_pair(merge_idx); + + insert_sorted(combined); } return true; } @@ -214,8 +283,8 @@ void badram_display(void) col = 7; } display_scrolled_message(col, "0x%0*x,0x%0*x", - TESTWORD_DIGITS, pattern[i].addr, - TESTWORD_DIGITS, pattern[i].mask); + TESTWORD_DIGITS, patterns[i].addr, + TESTWORD_DIGITS, patterns[i].mask); col += text_width; } } From d0399fd287075bb83d749c457f323f2dba98b06d Mon Sep 17 00:00:00 2001 From: martinwhitaker Date: Wed, 4 Jan 2023 15:16:55 +0000 Subject: [PATCH 073/113] Add a command line option to disable the big PASS/FAIL status display. (#227) --- README.md | 2 ++ app/config.c | 3 +++ app/config.h | 1 + app/display.c | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f96c31e..c7c802d 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ recognised: * disables ACPI table parsing and the use of multiple CPU cores * nobench * disables the integrated memory benchmark + * nobigstatus + * disables the big PASS/FAIL pop-up status display * nosm * disables SMBUS/SPD parsing, DMI decoding and memory benchmark * nopause diff --git a/app/config.c b/app/config.c index d7aed27..052279a 100644 --- a/app/config.c +++ b/app/config.c @@ -91,6 +91,7 @@ bool exclude_ecores = true; bool smp_enabled = true; +bool enable_big_status = true; bool enable_temperature = true; bool enable_trace = false; @@ -194,6 +195,8 @@ static void parse_option(const char *option, const char *params) parse_serial_params(params); } else if (strncmp(option, "nobench", 8) == 0) { enable_bench = false; + } else if (strncmp(option, "nobigstatus", 12) == 0) { + enable_big_status = false; } else if (strncmp(option, "noehci", 7) == 0) { usb_init_options |= USB_IGNORE_EHCI; } else if (strncmp(option, "nopause", 8) == 0) { diff --git a/app/config.h b/app/config.h index 5b5e9a2..3d6b82a 100644 --- a/app/config.h +++ b/app/config.h @@ -51,6 +51,7 @@ extern bool exclude_ecores; extern bool smp_enabled; +extern bool enable_big_status; extern bool enable_temperature; extern bool enable_trace; diff --git a/app/display.c b/app/display.c index d279a27..8a981c5 100644 --- a/app/display.c +++ b/app/display.c @@ -355,7 +355,7 @@ void display_temperature(void) void display_big_status(bool pass) { - if (big_status_displayed) { + if (!enable_big_status || big_status_displayed) { return; } From 186ef6e91333badfe315c9b2616991bd238da3f6 Mon Sep 17 00:00:00 2001 From: martinwhitaker Date: Wed, 4 Jan 2023 22:26:22 +0000 Subject: [PATCH 074/113] Improved own addr test (#219) * For 64-bit images, use the physical address as the test pattern in test 2. This will make it easier to diagnose faults. * Disable test 1 by default (issue #155). Test 2 provides the same test coverage. Test 1 may make it slightly easier to diagnose faults with a 32-bit image, so leave it as an option. * For 32 bit images, use the physical address to generate the offset in test 2. Detecting a stage change and using that to reset the offset counter could fail when the config menu was used to skip to the next test (issue #224). --- README.md | 5 +++-- tests/own_addr.c | 19 ++++++++++++++----- tests/tests.c | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c7c802d..c9fafcf 100644 --- a/README.md +++ b/README.md @@ -483,8 +483,9 @@ selected by the user. ### Test 2 : Address test, own address + window -Across all memory regions, each address is written with its own address plus -the window number and then each address is checked for consistency. This +Across all memory regions, each address is written with its own virtual +address plus the window number (for 32-bit images) or own physical address +(for 64-bit images) and then each address is checked for consistency. This catches any errors in the high order address bits that would be missed when testing each window in turn. This test is performed sequentially with each available CPU, regardless of the CPU sequencing mode selected by the user. diff --git a/tests/own_addr.c b/tests/own_addr.c index b5a9223..249cf74 100644 --- a/tests/own_addr.c +++ b/tests/own_addr.c @@ -16,6 +16,8 @@ #include #include +#include "vmem.h" + #include "display.h" #include "error.h" #include "test.h" @@ -127,12 +129,20 @@ int test_own_addr1(int my_cpu) int test_own_addr2(int my_cpu, int stage) { - static testword_t offset = 0; - static int last_stage = -1; - int ticks = 0; - offset = (stage == last_stage) ? offset + 1 : 1; + testword_t offset; + + // Calculate the offset (in pages) between the virtual address and the physical address. + offset = (vm_map[0].pm_base_addr / VM_WINDOW_SIZE) * VM_WINDOW_SIZE; + offset = (offset >= VM_PINNED_SIZE) ? offset - VM_PINNED_SIZE : 0; +#ifdef __x86_64__ + // Convert to a byte address offset. This will translate the virtual address into a physical address. + offset *= PAGE_SIZE; +#else + // Convert to a VM window offset. This will get added into the LSBs of the virtual address. + offset /= VM_WINDOW_SIZE; +#endif switch (stage) { case 0: @@ -145,6 +155,5 @@ int test_own_addr2(int my_cpu, int stage) break; } - last_stage = stage; return ticks; } diff --git a/tests/tests.c b/tests/tests.c index b818127..b754081 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -51,7 +51,7 @@ test_pattern_t test_list[NUM_TEST_PATTERNS] = { // ena, cpu, stgs, itrs, errs, description { true, SEQ, 1, 6, 0, "[Address test, walking ones, no cache] "}, - { true, SEQ, 1, 6, 0, "[Address test, own address in window] "}, + {false, SEQ, 1, 6, 0, "[Address test, own address in window] "}, { true, SEQ, 2, 6, 0, "[Address test, own address + window] "}, { true, PAR, 1, 6, 0, "[Moving inversions, 1s & 0s] "}, { true, PAR, 1, 3, 0, "[Moving inversions, 8 bit pattern] "}, From 10e843560494a8d5a8dd362bc085d66992adecfe Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 23 Jan 2023 15:01:48 +0100 Subject: [PATCH 075/113] Add SPD support for legacy VIA Southbridges (VT82C686A/B & VT8235) (From PR #236) Author: Corentin Labbe clabbe.montjoie@gmail.com Co-developed-by: Lionel Debroux lionel_debroux@yahoo.fr --- system/smbus.c | 28 +++++++++++++++------------- system/smbus.h | 3 +++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index d7a2c50..ae04998 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -48,7 +48,7 @@ static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr); static bool nv_mcp_get_smb(void); static bool amd_sb_get_smb(void); static bool fch_zen_get_smb(void); -static bool piix4_get_smb(void); +static bool piix4_get_smb(uint8_t address); static bool ich5_get_smb(void); static uint8_t ich5_process(void); static uint8_t ich5_read_spd_byte(uint8_t adr, uint16_t cmd); @@ -1158,7 +1158,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) return ich5_get_smb(); } if (did == 0x7113) { // 82371AB/EB/MB PIIX4 - return piix4_get_smb(); + return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); } // 0x719B 82440/82443MX PMC - PIIX4 // 0x0F13 ValleyView SMBus Controller ? @@ -1243,15 +1243,16 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // via SMBus controller. // case 0x3050: // 82C596_3 // Try SMB base address = 0x90, then SMB base address = 0x80 - // viapro SMBus controller. + // viapro SMBus controller, i.e. PIIX4 with a small quirk. // case 0x3051: // 82C596B_3 - // case 0x3057: // 82C686_4 + case 0x3057: // 82C686_4 // case 0x8235: // 8231_4 // SMB base address = 0x90 - // viapro SMBus controller. + // viapro SMBus controller, i.e. PIIX4. + return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); // case 0x3074: // 8233_0 // case 0x3147: // 8233A - // case 0x3177: // 8235 + case 0x3177: // 8235 // case 0x3227: // 8237 // case 0x3337: // 8237A // case 0x3372: // 8237S @@ -1261,7 +1262,8 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x8409: // VX855 // case 0x8410: // VX900 // SMB base address = 0xD0 - // viapro I2C controller. + // viapro I2C controller, i.e. PIIX4 with a small quirk. + return piix4_get_smb(PIIX4_SMB_BASE_ADR_VIAPRO); default: return false; } @@ -1279,7 +1281,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) case PCI_VID_ALI: switch(did) { - // case 0x1563: // ali1563 (M1563) SMBus controller + // 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 default: return false; @@ -1297,7 +1299,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x0203: // CSB6 // case 0x0205: // HT1000SB // case 0x0408: // HT1100LD - return piix4_get_smb(); + return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); default: return false; } @@ -1312,9 +1314,9 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // PIIX4 SMBUS Controller // ---------------------- -static bool piix4_get_smb(void) +static bool piix4_get_smb(uint8_t address) { - uint16_t x = pci_config_read16(0, smbdev, smbfun, 0x90) & 0xFFF0; + uint16_t x = pci_config_read16(0, smbdev, smbfun, address) & 0xFFF0; if (x != 0) { smbusbase = x; @@ -1361,7 +1363,7 @@ static bool amd_sb_get_smb(void) if ((smbus_id & 0xFFFF) == 0x4385 && rev_id <= 0x3D) { // Older AMD SouthBridge (SB700 & older) use PIIX4 registers - return piix4_get_smb(); + return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); } else if ((smbus_id & 0xFFFF) == 0x780B && rev_id == 0x42) { // Latest Pre-Zen APUs use the newer Zen PM registers return fch_zen_get_smb(); @@ -1568,7 +1570,7 @@ static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) // Start transaction __outb(NVSMBCNT_BYTE_DATA | NVSMBCNT_READ, NVSMBCNT); - // Wait until transction complete + // Wait until transaction complete for (i = 500; i > 0; i--) { usleep(50); if (__inb(NVSMBCNT) == 0) { diff --git a/system/smbus.h b/system/smbus.h index 5a31352..116ae0c 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -85,6 +85,9 @@ #define SPD_SKU_LEN 32 +#define PIIX4_SMB_BASE_ADR_DEFAULT 0x90 +#define PIIX4_SMB_BASE_ADR_VIAPRO 0xD0 + struct pci_smbus_controller { unsigned vendor; unsigned device; From b6992b9ec04d1bfd0ba02617fae5fbbedd0d97e0 Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Mon, 23 Jan 2023 15:17:47 +0100 Subject: [PATCH 076/113] Fix parallel build after d3d52b: boot/setup.S now contains #include "build_version.h", so that file needs to be generated beforehand. (#235) --- build32/Makefile | 2 +- build64/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build32/Makefile b/build32/Makefile index bf77455..552c7b5 100644 --- a/build32/Makefile +++ b/build32/Makefile @@ -81,7 +81,7 @@ boot/startup.o: ../boot/startup32.S ../boot/boot.h @mkdir -p boot $(CC) -m32 -x assembler-with-cpp -c -I../boot -o $@ $< -boot/%.o: ../boot/%.S ../boot/boot.h +boot/%.o: ../boot/%.S ../boot/boot.h app/build_version.h @mkdir -p boot $(CC) -m32 -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< diff --git a/build64/Makefile b/build64/Makefile index 29d118d..ed76db0 100644 --- a/build64/Makefile +++ b/build64/Makefile @@ -80,7 +80,7 @@ boot/startup.o: ../boot/startup64.S ../boot/boot.h @mkdir -p boot $(CC) -x assembler-with-cpp -c -I../boot -o $@ $< -boot/%.o: ../boot/%.S ../boot/boot.h +boot/%.o: ../boot/%.S ../boot/boot.h app/build_version.h @mkdir -p boot $(CC) -x assembler-with-cpp -c -I../boot -Iapp -o $@ $< From 3aeda70e249a873388fddb877d46feebbcdaa73d Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Sat, 17 Sep 2022 16:06:29 +0200 Subject: [PATCH 077/113] Move more of the simple string functions to the header, to allow inlining and further optimization. Before: text data bss dec hex filename 10374 19 2712 13105 3331 app/config.o 106854 26720 13344 146918 23de6 memtest_shared 8734 19 2712 11465 2cc9 app/config.o 111310 28392 294688 434390 6a0d6 memtest_shared After: text data bss dec hex filename 10105 19 2712 12836 3224 app/config.o 106580 26720 13344 146644 23cd4 memtest_shared 8653 19 2712 11384 2c78 app/config.o 110969 28392 294688 434049 69f81 memtest_shared --- lib/string.c | 34 ---------------------------------- lib/string.h | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/lib/string.c b/lib/string.c index 257b6ce..e5ddfe1 100644 --- a/lib/string.c +++ b/lib/string.c @@ -31,18 +31,6 @@ void reverse(char s[]) // Public Functions //------------------------------------------------------------------------------ -int memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *src1 = s1, *src2 = s2; - - for (size_t i = 0; i < n; i++) { - if (src1[i] != src2[i]) { - return (int)src1[i] - (int)src2[i]; - } - } - return 0; -} - void *memmove(void *dest, const void *src, size_t n) { char *d = (char *)dest, *s = (char *)src; @@ -64,28 +52,6 @@ void *memmove(void *dest, const void *src, size_t n) return dest; } -size_t strlen(const char *s) -{ - size_t len = 0; - while (*s++) { - len++; - } - return len; -} - -int strncmp(const char *s1, const char *s2, size_t n) -{ - for (size_t i = 0; i < n; i++) { - if (s1[i] != s2[i]) { - return (int)s1[i] - (int)s2[i]; - } - if (s1[i] == '\0') { - return 0; - } - } - return 0; -} - char *strstr(const char *haystack, const char *needle) { size_t haystack_len = strlen(haystack); diff --git a/lib/string.h b/lib/string.h index b24e704..9bca9af 100644 --- a/lib/string.h +++ b/lib/string.h @@ -18,7 +18,17 @@ * between the first mismatching byte in s1 (interpreted as an unsigned * value) and the corresponding byte in s2. */ -int memcmp(const void *s1, const void *s2, size_t n); +static inline int memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *src1 = s1, *src2 = s2; + + for (size_t i = 0; i < n; i++) { + if (src1[i] != src2[i]) { + return (int)src1[i] - (int)src2[i]; + } + } + return 0; +} /** * Copies n bytes from the memory area pointed to by src to the memory area @@ -45,7 +55,14 @@ void *memmove(void *dest, const void *src, size_t n); /** * Returns the string length, excluding the terminating null character. */ -size_t strlen(const char *s); +static inline size_t strlen(const char *s) +{ + size_t len = 0; + while (*s++) { + len++; + } + return len; +} /** * Compares at most the first n characters in the strings s1 and s2 and @@ -53,7 +70,18 @@ size_t strlen(const char *s); * between the first mismatching character in s1 (interpreted as a signed * value) and the corresponding character in s2. */ -int strncmp(const char *s1, const char *s2, size_t n); +static inline int strncmp(const char *s1, const char *s2, size_t n) +{ + for (size_t i = 0; i < n; i++) { + if (s1[i] != s2[i]) { + return (int)s1[i] - (int)s2[i]; + } + if (s1[i] == '\0') { + return 0; + } + } + return 0; +} /** * Finds the first occurrence of the substring needle in the string haystack From f24e8978838df2fe4d7f496640af1315e116768e Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Mon, 19 Sep 2022 07:39:17 +0200 Subject: [PATCH 078/113] Add support for configuring the CPU sequencing mode through the command line. Reorder tests in app/config.c::parse_option alphabetically. Fixes #82. --- app/config.c | 34 +++++++++++++++++++++------------- app/display.c | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/config.c b/app/config.c index 052279a..8d61279 100644 --- a/app/config.c +++ b/app/config.c @@ -175,7 +175,17 @@ static void parse_option(const char *option, const char *params) { if (option[0] == '\0') return; - if (strncmp(option, "keyboard", 9) == 0 && params != NULL) { + if (strncmp(option, "console", 8) == 0) { + parse_serial_params(params); + } else if (strncmp(option, "cpuseqmode", 11) == 0) { + if (strncmp(params, "par", 4) == 0) { + cpu_mode = PAR; + } else if (strncmp(params, "seq", 4) == 0) { + cpu_mode = SEQ; + } else if (strncmp(params, "rr", 3) == 0 || strncmp(params, "one", 4) == 0) { + cpu_mode = ONE; + } + } else if (strncmp(option, "keyboard", 9) == 0 && params != NULL) { if (strncmp(params, "legacy", 7) == 0) { keyboard_types = KT_LEGACY; } else if (strncmp(params, "usb", 4) == 0) { @@ -183,16 +193,6 @@ static void parse_option(const char *option, const char *params) } else if (strncmp(params, "both", 5) == 0) { keyboard_types = KT_USB|KT_LEGACY; } - } else if (strncmp(option, "powersave", 10) == 0) { - if (strncmp(params, "off", 4) == 0) { - power_save = POWER_SAVE_OFF; - } else if (strncmp(params, "low", 4) == 0) { - power_save = POWER_SAVE_LOW; - } else if (strncmp(params, "high", 5) == 0) { - power_save = POWER_SAVE_HIGH; - } - } else if (strncmp(option, "console", 8) == 0) { - parse_serial_params(params); } else if (strncmp(option, "nobench", 8) == 0) { enable_bench = false; } else if (strncmp(option, "nobigstatus", 12) == 0) { @@ -201,8 +201,18 @@ static void parse_option(const char *option, const char *params) usb_init_options |= USB_IGNORE_EHCI; } else if (strncmp(option, "nopause", 8) == 0) { pause_at_start = false; + } else if (strncmp(option, "nosm", 5) == 0) { + enable_sm = false; } else if (strncmp(option, "nosmp", 6) == 0) { smp_enabled = false; + } else if (strncmp(option, "powersave", 10) == 0) { + if (strncmp(params, "off", 4) == 0) { + power_save = POWER_SAVE_OFF; + } else if (strncmp(params, "low", 4) == 0) { + power_save = POWER_SAVE_LOW; + } else if (strncmp(params, "high", 5) == 0) { + power_save = POWER_SAVE_HIGH; + } } else if (strncmp(option, "trace", 6) == 0) { enable_trace = true; } else if (strncmp(option, "usbdebug", 9) == 0) { @@ -215,8 +225,6 @@ static void parse_option(const char *option, const char *params) } else if (strncmp(params, "3", 2) == 0) { usb_init_options |= USB_2_STEP_INIT|USB_EXTRA_RESET; } - } else if (strncmp(option, "nosm", 5) == 0) { - enable_sm = false; } } diff --git a/app/display.c b/app/display.c index 8a981c5..4e6b14a 100644 --- a/app/display.c +++ b/app/display.c @@ -49,7 +49,7 @@ static const char spin_state[NUM_SPIN_STATES] = { '|', '/', '-', '\\' }; -static const char *cpu_mode_str[] = { "PAR", "SEQ", "RR " }; +static const char cpu_mode_str[3][4] = { "PAR", "SEQ", "RR " }; //------------------------------------------------------------------------------ // Private Variables From 8f788b27e1042aa5630d04d188f47f8e87bcbd0f Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Mon, 19 Sep 2022 07:51:20 +0200 Subject: [PATCH 079/113] Add support for configuring the error reporting mode through the command line. Fixes #83. --- app/config.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/config.c b/app/config.c index 8d61279..61a216c 100644 --- a/app/config.c +++ b/app/config.c @@ -185,6 +185,16 @@ static void parse_option(const char *option, const char *params) } else if (strncmp(params, "rr", 3) == 0 || strncmp(params, "one", 4) == 0) { cpu_mode = ONE; } + } else if (strncmp(option, "reportmode", 11) == 0) { + if (strncmp(params, "none", 5) == 0) { + error_mode = ERROR_MODE_NONE; + } else if (strncmp(params, "summary", 8) == 0) { + error_mode = ERROR_MODE_SUMMARY; + } else if (strncmp(params, "address", 8) == 0) { + error_mode = ERROR_MODE_ADDRESS; + } else if (strncmp(params, "badram", 7) == 0) { + error_mode = ERROR_MODE_BADRAM; + } } else if (strncmp(option, "keyboard", 9) == 0 && params != NULL) { if (strncmp(params, "legacy", 7) == 0) { keyboard_types = KT_LEGACY; From 327495ec615e9ad6c16181484fe9157acd0b63d7 Mon Sep 17 00:00:00 2001 From: martinwhitaker Date: Mon, 23 Jan 2023 14:50:52 +0000 Subject: [PATCH 080/113] Allow use on headless EFI systems. (#242) A headless EFI system may have no GOP devices. In this case, disable output to the physical display, but continue to write to the shadow buffer. This allows operation via a serial console. --- boot/bootparams.h | 1 + boot/efisetup.c | 15 +++++++-------- system/screen.c | 8 ++++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/boot/bootparams.h b/boot/bootparams.h index 45d95c4..273a562 100644 --- a/boot/bootparams.h +++ b/boot/bootparams.h @@ -58,6 +58,7 @@ typedef struct { #define VIDEO_TYPE_VLFB 0x23 // VESA VGA in graphic mode #define VIDEO_TYPE_EFI 0x70 // EFI graphic mode +#define VIDEO_TYPE_NONE 0xff // no video display (added for Memtest86+) #define LFB_CAPABILITY_64BIT_BASE (1 << 1) diff --git a/boot/efisetup.c b/boot/efisetup.c index 5fc92df..4362215 100644 --- a/boot/efisetup.c +++ b/boot/efisetup.c @@ -334,9 +334,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha efi_graphics_output_t *gop = find_gop(handles, handles_size); if (!gop) { -#if DEBUG - print_string("GOP not found\n"); -#endif + print_string("No graphics display found\n"); return EFI_NOT_FOUND; } @@ -365,9 +363,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha efi_call_bs(free_pool, info); } if (best_mode == UINT32_MAX) { -#if DEBUG - print_string("No suitable GOP screen resolution\n"); -#endif + print_string("No suitable screen resolution found\n"); return EFI_NOT_FOUND; } @@ -469,9 +465,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha status = efi_call_proto(gop, set_mode, best_mode); if (status != EFI_SUCCESS) { -#if DEBUG print_string("Set GOP mode failed\n"); -#endif return status; } @@ -502,6 +496,11 @@ static efi_status_t set_screen_info(boot_params_t *boot_params) if (status == EFI_SUCCESS) { status = set_screen_info_from_gop(&boot_params->screen_info, handles, handles_size); } + 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; + } efi_call_bs(free_pool, handles); } diff --git a/system/screen.c b/system/screen.c index 4c63513..b745f16 100644 --- a/system/screen.c +++ b/system/screen.c @@ -42,7 +42,7 @@ static const rgb_value_t vga_pallete[16] = { { 255, 255, 255 } // BOLD+WHITE }; -static vga_buffer_t *vga_buffer = (vga_buffer_t *)(0xb8000); +static vga_buffer_t *vga_buffer = NULL; vga_buffer_t shadow_buffer; @@ -64,7 +64,9 @@ static void vga_put_char(int row, int col, uint8_t ch, uint8_t attr) shadow_buffer[row][col].ch = ch; shadow_buffer[row][col].attr = attr; - (*vga_buffer)[row][col].value = shadow_buffer[row][col].value; + if (vga_buffer) { + (*vga_buffer)[row][col].value = shadow_buffer[row][col].value; + } } static void lfb8_put_char(int row, int col, uint8_t ch, uint8_t attr) @@ -239,6 +241,8 @@ void screen_init(void) uint32_t b = ((vga_pallete[i].b * b_max) / 255) << screen_info->blue_pos; lfb_pallete[i] = r | g | b; } + } else if (screen_info->orig_video_isVGA != VIDEO_TYPE_NONE) { + vga_buffer = (vga_buffer_t *)(0xb8000); } } From b15a8bb63261d033c7844f9676385c09fd2c854a Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 23 Jan 2023 16:09:32 +0100 Subject: [PATCH 081/113] Add SPD support for ATI SB400 Southbridge --- system/smbus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index ae04998..7053c63 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1189,7 +1189,8 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) { // case 0x4353: // SB200 // case 0x4363: // SB300 - // case 0x4372: // SB400 + case 0x4372: // SB400 + return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); case 0x4385: // SB600+ return amd_sb_get_smb(); default: From 485bfa46a3482a5c4190478e74202aa019bea30b Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:47:54 +0100 Subject: [PATCH 082/113] Add a quirk to disable SMP on SuperMicro X10SDV (#244) --- system/hwquirks.c | 23 ++++++++++++++++++----- system/hwquirks.h | 3 ++- system/pci.h | 6 ++++++ system/smp.c | 7 +++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/system/hwquirks.c b/system/hwquirks.c index 744691e..dbff37b 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -72,8 +72,8 @@ void quirks_init(void) { quirk.id = QUIRK_NONE; quirk.type = QUIRK_TYPE_NONE; - quirk.root_vid = pci_config_read16(0, 0, 0, 0); - quirk.root_did = pci_config_read16(0, 0, 0, 2); + quirk.root_vid = pci_config_read16(0, 0, 0, PCI_VID_REG); + quirk.root_did = pci_config_read16(0, 0, 0, PCI_DID_REG); quirk.process = NULL; // ------------------------- @@ -93,13 +93,26 @@ void quirks_init(void) // This motherboard has an ASB100 ASIC with a SMBUS Mux Integrated. // To access SPD later in the code, we need to configure the mux. // PS: Detection via DMI is unreliable, so using Root PCI Registers - if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x1130) { // Intel i815 - if (pci_config_read16(0, 0, 0, 0x2C) == PCI_VID_ASUS) { // ASUS - if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C + if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x1130) { // Intel i815 + if (pci_config_read16(0, 0, 0, PCI_SUB_VID_REG) == PCI_VID_ASUS) { // ASUS + if (pci_config_read16(0, 0, 0, PCI_SUB_DID_REG) == 0x8027) { // TUSL2-C quirk.id = QUIRK_TUSL2; quirk.type |= QUIRK_TYPE_SMBUS; quirk.process = asus_tusl2_configure_mux; } } } + + // ------------------------------------------------- + // -- SuperMicro X10SDV Quirk (GitHub Issue #233) -- + // ------------------------------------------------- + // Memtest86+ crashs on Super Micro X10SDV motherboard with SMP Enabled + // We were unable to find a solution so far, so disable SMP by default + if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x6F00) { // Broadwell-E (Xeon-D) + if (pci_config_read16(0, 0, 0, PCI_SUB_VID_REG) == PCI_VID_SUPERMICRO) { // Super Micro + quirk.id = QUIRK_X10SDV_NOSMP; + quirk.type |= QUIRK_TYPE_SMP; + quirk.process = NULL; + } + } } diff --git a/system/hwquirks.h b/system/hwquirks.h index cca30c1..6005611 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -23,7 +23,8 @@ typedef enum { QUIRK_NONE, QUIRK_TUSL2, - QUIRK_ALI_ALADDIN_V + QUIRK_ALI_ALADDIN_V, + QUIRK_X10SDV_NOSMP } quirk_id_t; typedef struct { diff --git a/system/pci.h b/system/pci.h index e82016f..3dccd89 100644 --- a/system/pci.h +++ b/system/pci.h @@ -12,6 +12,11 @@ #include +#define PCI_VID_REG 0x00 +#define PCI_DID_REG 0x02 +#define PCI_SUB_VID_REG 0x2C +#define PCI_SUB_DID_REG 0x2E + /* Vendor IDs */ #define PCI_VID_ATI 0x1002 #define PCI_VID_AMD 0x1022 @@ -22,6 +27,7 @@ #define PCI_VID_NVIDIA 0x10DE #define PCI_VID_VIA 0x1106 #define PCI_VID_SERVERWORKS 0x1166 +#define PCI_VID_SUPERMICRO 0x15D9 #define PCI_VID_HYGON 0x1D94 #define PCI_VID_INTEL 0x8086 diff --git a/system/smp.c b/system/smp.c index c8f8c6e..538f166 100644 --- a/system/smp.c +++ b/system/smp.c @@ -21,6 +21,7 @@ #include "cpuid.h" #include "heap.h" +#include "hwquirks.h" #include "memrw32.h" #include "memsize.h" #include "msr.h" @@ -539,6 +540,12 @@ void smp_init(bool smp_enable) } } + // Process SMP Quirks + if (quirk.type & QUIRK_TYPE_SMP) { + // quirk.process(); + smp_enable = false; + } + if (smp_enable) { (void)(find_cpus_in_madt() || find_cpus_in_floating_mp_struct()); From a4c9adc4452af331a1fae5a30fbbe91f689330a0 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 29 Jan 2023 21:52:59 +0000 Subject: [PATCH 083/113] Fix the virtual memory addresses and sizes in the EFI image headers. When the reloc and sbat sections were added by PR #34, three bugs were introduced: 1. The virtual address and size fields in the PE headers were set to the same values as the raw address and size fields. This is incorrect, because the sections in the image file are aligned on 512 byte boundaries, but when loaded into memory they need to be aligned on 4096 byte boundaries. 2. The value programmed into the SizeOfImage field was too large, as it double-counted the region before the start of the .text section. 3. The value programmed into the SizeOfImage field no longer included the bss size. That potentially allowed the EFI loader to load the image immediately before a reserved region of memory without leaving enough space for the bss section. This commit fixes those bugs by calculating both file and virtual memory offsets & sizes in the ld script. Note that we can't add a bss section to the EFI image because many EFI loaders fail to load images that have uninitialised data sections. Instead the text region size in virtual memory is increased to include the bss size. This fixes issue #243. It also eliminates the gaps between sections observed in issue #202. --- boot/header.S | 43 +++++++++++++------------- build32/ldscripts/memtest_efi.lds | 51 ++++++++++++++++++++----------- build64/ldscripts/memtest_efi.lds | 51 ++++++++++++++++++++----------- 3 files changed, 87 insertions(+), 58 deletions(-) diff --git a/boot/header.S b/boot/header.S index 673bc67..37525b8 100644 --- a/boot/header.S +++ b/boot/header.S @@ -7,7 +7,7 @@ // end of the boot sector), with the remainder of the header being provided by // setup.S. // -// Copyright (C) 2020 Martin Whitaker. +// Copyright (C) 2020-2023 Martin Whitaker. // // Derived from Linux 5.6 arch/x86/boot/header.S: // @@ -28,7 +28,6 @@ # address well away from HIGH_LOAD_ADDR, to avoid overlap when relocating the code. #define IMAGE_BASE 0x200000 -#define BASE_OF_CODE 0x1000 .section ".header", "ax", @progbits .code16 @@ -117,15 +116,15 @@ optional_header: .byte 0x02 # MajorLinkerVersion .byte 0x14 # MinorLinkerVersion - .long _text_size # SizeOfCode - .long _sbat_size # SizeOfInitializedData + .long _virt_text_size # SizeOfCode + .long _virt_sbat_size # SizeOfInitializedData .long 0 # SizeOfUninitializedData - .long BASE_OF_CODE + 0x1e0 # AddressOfEntryPoint + .long _virt_text_start + 0x1e0 # AddressOfEntryPoint - .long BASE_OF_CODE # BaseOfCode + .long _virt_text_start # BaseOfCode #ifndef __x86_64__ - .long _sbat_start # BaseOfData + .long _virt_sbat_start # BaseOfData #endif extra_header_fields: @@ -144,7 +143,7 @@ extra_header_fields: .word 0 # MinorSubsystemVersion .long 0 # Win32VersionValue - .long BASE_OF_CODE + _img_end # SizeOfImage + .long _virt_img_size # SizeOfImage .long end_of_headers # SizeOfHeaders .long 0 # CheckSum .word 10 # Subsystem (EFI application) @@ -173,8 +172,8 @@ extra_header_fields: .long 0 # DataDirectory.Exception.Size .long 0 # DataDirectory.Certs.VirtualAddress .long 0 # DataDirectory.Certs.Size - .long _reloc_start # DataDirectory.BaseReloc.VirtualAddress - .long _reloc_size # DataDirectory.BaseReloc.Size + .long _virt_reloc_start # DataDirectory.BaseReloc.VirtualAddress + .long _real_reloc_size # DataDirectory.BaseReloc.Size # Section table section_table: @@ -182,10 +181,10 @@ section_table: .byte 0 .byte 0 .byte 0 - .long _text_size # VirtualSize - .long BASE_OF_CODE # VirtualAddress - .long _text_size # SizeOfRawData - .long _text_start # PointerToRawData + .long _virt_text_size # VirtualSize + .long _virt_text_start # VirtualAddress + .long _file_text_size # SizeOfRawData + .long _file_text_start # PointerToRawData .long 0 # PointerToRelocations .long 0 # PointerToLineNumbers .word 0 # NumberOfRelocations @@ -198,10 +197,10 @@ section_table: .ascii ".reloc" .byte 0 .byte 0 - .long _reloc_size # VirtualSize - .long _reloc_start # VirtualAddress - .long _reloc_size # SizeOfRawData - .long _reloc_start # PointerToRawData + .long _virt_reloc_size # VirtualSize + .long _virt_reloc_start # VirtualAddress + .long _file_reloc_size # SizeOfRawData + .long _file_reloc_start # PointerToRawData .long 0 # PointerToRelocations .long 0 # PointerToLineNumbers .word 0 # NumberOfRelocations @@ -214,10 +213,10 @@ section_table: .byte 0 .byte 0 .byte 0 - .long _sbat_size # VirtualSize - .long _sbat_start # VirtualAddress - .long _sbat_size # SizeOfRawData - .long _sbat_start # PointerToRawData + .long _virt_sbat_size # VirtualSize + .long _virt_sbat_start # VirtualAddress + .long _file_sbat_size # SizeOfRawData + .long _file_sbat_start # PointerToRawData .long 0 # PointerToRelocations .long 0 # PointerToLineNumbers .word 0 # NumberOfRelocations diff --git a/build32/ldscripts/memtest_efi.lds b/build32/ldscripts/memtest_efi.lds index 6c09fdb..4b83fdd 100644 --- a/build32/ldscripts/memtest_efi.lds +++ b/build32/ldscripts/memtest_efi.lds @@ -12,32 +12,47 @@ SECTIONS { } . = ALIGN(512); .text : { - _text_start = . ; + _file_text_start = . ; *(.data) + _real_text_end = . ; . = ALIGN(512); - _text_end = . ; + _file_text_end = . ; } - . = ALIGN(512); .reloc : { - _reloc_start = . ; + _file_reloc_start = . ; *(.reloc) - _reloc_end = . ; - } - . = ALIGN(512); - .sbat : { - _sbat_start = . ; - *(.sbat) + _real_reloc_end = . ; . = ALIGN(512); - _sbat_end = . ; + _file_reloc_end = . ; + } + .sbat : { + _file_sbat_start = . ; + *(.sbat) + _real_sbat_end = . ; + . = ALIGN(512); + _file_sbat_end = . ; } - . = ALIGN(4096); - _img_end = . ; /DISCARD/ : { *(*) } - _text_size = (_text_end - _text_start); + _real_text_size = _real_text_end - _file_text_start; + _real_reloc_size = _real_reloc_end - _file_reloc_start; + _real_sbat_size = _real_sbat_end - _file_sbat_start; - _reloc_size = (_reloc_end - _reloc_start); - _sbat_size = (_sbat_end - _sbat_start); - _sys_size = _text_size >> 4; - _init_size = _text_size + _bss_size; + _file_text_size = _file_text_end - _file_text_start; + _file_reloc_size = _file_reloc_end - _file_reloc_start; + _file_sbat_size = _file_sbat_end - _file_sbat_start; + + _sys_size = (_real_text_size + 15) >> 4; + _init_size = _real_text_size + _bss_size; + + _virt_head_size = ((_file_text_start + 4095) >> 12) << 12; + _virt_text_size = ((_init_size + 4095) >> 12) << 12; + _virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12; + _virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12; + + _virt_text_start = _virt_head_size; + _virt_reloc_start = _virt_text_start + _virt_text_size; + _virt_sbat_start = _virt_reloc_start + _virt_reloc_size; + + _virt_img_size = _virt_sbat_start + _virt_sbat_size; } diff --git a/build64/ldscripts/memtest_efi.lds b/build64/ldscripts/memtest_efi.lds index ec27bbf..784382b 100644 --- a/build64/ldscripts/memtest_efi.lds +++ b/build64/ldscripts/memtest_efi.lds @@ -12,32 +12,47 @@ SECTIONS { } . = ALIGN(512); .text : { - _text_start = . ; + _file_text_start = . ; *(.data) + _real_text_end = . ; . = ALIGN(512); - _text_end = . ; + _file_text_end = . ; } - . = ALIGN(512); .reloc : { - _reloc_start = . ; + _file_reloc_start = . ; *(.reloc) - _reloc_end = . ; - } - . = ALIGN(512); - .sbat : { - _sbat_start = . ; - *(.sbat) + _real_reloc_end = . ; . = ALIGN(512); - _sbat_end = . ; + _file_reloc_end = . ; + } + .sbat : { + _file_sbat_start = . ; + *(.sbat) + _real_sbat_end = . ; + . = ALIGN(512); + _file_sbat_end = . ; } - . = ALIGN(4096); - _img_end = . ; /DISCARD/ : { *(*) } - _text_size = (_text_end - _text_start); + _real_text_size = _real_text_end - _file_text_start; + _real_reloc_size = _real_reloc_end - _file_reloc_start; + _real_sbat_size = _real_sbat_end - _file_sbat_start; - _reloc_size = (_reloc_end - _reloc_start); - _sbat_size = (_sbat_end - _sbat_start); - _sys_size = _text_size >> 4; - _init_size = _text_size + _bss_size; + _file_text_size = _file_text_end - _file_text_start; + _file_reloc_size = _file_reloc_end - _file_reloc_start; + _file_sbat_size = _file_sbat_end - _file_sbat_start; + + _sys_size = (_real_text_size + 15) >> 4; + _init_size = _real_text_size + _bss_size; + + _virt_head_size = ((_file_text_start + 4095) >> 12) << 12; + _virt_text_size = ((_init_size + 4095) >> 12) << 12; + _virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12; + _virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12; + + _virt_text_start = _virt_head_size; + _virt_reloc_start = _virt_text_start + _virt_text_size; + _virt_sbat_start = _virt_reloc_start + _virt_reloc_size; + + _virt_img_size = _virt_sbat_start + _virt_sbat_size; } From e5d7119abfd57b4cfbd45d281daae477028b312d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 31 Jan 2023 18:02:28 +0000 Subject: [PATCH 084/113] White space changes to improve readability. --- boot/header.S | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/boot/header.S b/boot/header.S index 37525b8..e69babf 100644 --- a/boot/header.S +++ b/boot/header.S @@ -96,15 +96,15 @@ coff_header: .word section_table - optional_header # SizeOfOptionalHeader #ifdef __x86_64__ .word IMAGE_FILE_DEBUG_STRIPPED \ - | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ - | IMAGE_FILE_LINE_NUMS_STRIPPED \ - | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics + | IMAGE_FILE_LOCAL_SYMS_STRIPPED \ + | IMAGE_FILE_LINE_NUMS_STRIPPED \ + | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics #else .word IMAGE_FILE_32BIT_MACHINE \ - | IMAGE_FILE_DEBUG_STRIPPED \ - | IMAGE_FILE_LOCAL_SYMS_STRIPPED\ - | IMAGE_FILE_LINE_NUMS_STRIPPED \ - | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics. + | IMAGE_FILE_DEBUG_STRIPPED \ + | IMAGE_FILE_LOCAL_SYMS_STRIPPED \ + | IMAGE_FILE_LINE_NUMS_STRIPPED \ + | IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics. #endif optional_header: @@ -190,9 +190,9 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ - | IMAGE_SCN_MEM_EXECUTE \ - | IMAGE_SCN_ALIGN_16BYTES \ - | IMAGE_SCN_CNT_CODE # Characteristics (section flags) + | IMAGE_SCN_MEM_EXECUTE \ + | IMAGE_SCN_ALIGN_16BYTES \ + | IMAGE_SCN_CNT_CODE # Characteristics (section flags) .ascii ".reloc" .byte 0 @@ -206,8 +206,8 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ - | IMAGE_SCN_ALIGN_4BYTES \ - | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) + | IMAGE_SCN_ALIGN_4BYTES \ + | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) .ascii ".sbat" .byte 0 @@ -222,8 +222,8 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ - | IMAGE_SCN_ALIGN_4096BYTES \ - | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) + | IMAGE_SCN_ALIGN_4096BYTES \ + | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) # Emulate the Linux boot header, to allow loading by intermediate boot loaders. From 2fa2346ae07c3cb528f1c549efec1997f619703d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 31 Jan 2023 18:06:15 +0000 Subject: [PATCH 085/113] Use the correct name for the relocation type in the EFI image .reloc section. The coding is the same, but IMAGE_REL_AMD64_ABSOLUTE is used for COFF relocations, not for base relocations. --- boot/header.S | 2 +- boot/peimage.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/header.S b/boot/header.S index e69babf..05eb4a3 100644 --- a/boot/header.S +++ b/boot/header.S @@ -249,7 +249,7 @@ end_of_headers: .section ".reloc", "a", @progbits .long 0 // Page RVA .long 10 // Block Size (2*4+2) - .word (IMAGE_REL_AMD64_ABSOLUTE<<12) + 0 // reloc 0 -> 0 + .word (IMAGE_REL_BASED_ABSOLUTE << 12) + 0 // reloc 0 -> 0 .section ".sbat", "a", @progbits .incbin "../boot/sbat.csv" diff --git a/boot/peimage.h b/boot/peimage.h index ad18594..b80e530 100644 --- a/boot/peimage.h +++ b/boot/peimage.h @@ -80,7 +80,7 @@ #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ #define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ -#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_BASED_ABSOLUTE 0x0000 /* COMDAT selection codes. */ From 040e253b540fcd03c296c75cce9da717fa59968d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 31 Jan 2023 18:08:09 +0000 Subject: [PATCH 086/113] Remove the alignment characteristics from the EFI image PE section table. The alignment characteristics are only valid in COFF files. The section alignment for image files is determined by the SectionAlignment field in the image header. --- boot/header.S | 3 --- 1 file changed, 3 deletions(-) diff --git a/boot/header.S b/boot/header.S index 05eb4a3..d4c2383 100644 --- a/boot/header.S +++ b/boot/header.S @@ -191,7 +191,6 @@ section_table: .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ | IMAGE_SCN_MEM_EXECUTE \ - | IMAGE_SCN_ALIGN_16BYTES \ | IMAGE_SCN_CNT_CODE # Characteristics (section flags) .ascii ".reloc" @@ -206,7 +205,6 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ - | IMAGE_SCN_ALIGN_4BYTES \ | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) .ascii ".sbat" @@ -222,7 +220,6 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long IMAGE_SCN_MEM_READ \ - | IMAGE_SCN_ALIGN_4096BYTES \ | IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags) # Emulate the Linux boot header, to allow loading by intermediate boot loaders. From 9c16a0568abba855dcc992bc4bb7e648ef862338 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 31 Jan 2023 18:17:33 +0000 Subject: [PATCH 087/113] Fix assembler warning about incorrect type/attributes for .reloc section. --- boot/header.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/header.S b/boot/header.S index d4c2383..2177713 100644 --- a/boot/header.S +++ b/boot/header.S @@ -243,7 +243,7 @@ boot_flag: .org 512 end_of_headers: -.section ".reloc", "a", @progbits +.section ".reloc" .long 0 // Page RVA .long 10 // Block Size (2*4+2) .word (IMAGE_REL_BASED_ABSOLUTE << 12) + 0 // reloc 0 -> 0 From d088740757262f43cde173c147ff4fbfa34a369a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 31 Jan 2023 18:25:28 +0000 Subject: [PATCH 088/113] Fix the bss section size in 32-bit builds. The AP stacks section was being discarded by the linker because the change in section name and attributes hadn't been propagated from the startup64.S to startup32.S. --- boot/startup32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/startup32.S b/boot/startup32.S index ca5535a..c40d24e 100644 --- a/boot/startup32.S +++ b/boot/startup32.S @@ -812,7 +812,7 @@ startup_stack_top: # Main stack area. - .section "stacks", "aw", @progbits + .section ".stacks", "aw", @nobits .align 16 . = . + STACKS_SIZE From b01c8e438890485160d63195ebc91e08943ca9af Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 2 Feb 2023 09:32:47 +0000 Subject: [PATCH 089/113] Avoid sbverify warning about gap in section table. We have a .setup section in the EFI image that contains the remainder of the Linux boot header and the real-mode setup code to support booting via an intermediate bootloader. This sits between the PE header and the .text section. We don't want the EFI loader to load this section, so simply increase the SizeOfHeader field in the PE header to cover it. --- boot/header.S | 3 +-- build32/ldscripts/memtest_efi.lds | 3 ++- build64/ldscripts/memtest_efi.lds | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/boot/header.S b/boot/header.S index 2177713..23e9a14 100644 --- a/boot/header.S +++ b/boot/header.S @@ -144,7 +144,7 @@ extra_header_fields: .long 0 # Win32VersionValue .long _virt_img_size # SizeOfImage - .long end_of_headers # SizeOfHeaders + .long _file_head_size # SizeOfHeaders .long 0 # CheckSum .word 10 # Subsystem (EFI application) .word 0 # DllCharacteristics @@ -241,7 +241,6 @@ boot_flag: .word 0xAA55 .org 512 -end_of_headers: .section ".reloc" .long 0 // Page RVA diff --git a/build32/ldscripts/memtest_efi.lds b/build32/ldscripts/memtest_efi.lds index 4b83fdd..2c84de5 100644 --- a/build32/ldscripts/memtest_efi.lds +++ b/build32/ldscripts/memtest_efi.lds @@ -38,6 +38,7 @@ SECTIONS { _real_reloc_size = _real_reloc_end - _file_reloc_start; _real_sbat_size = _real_sbat_end - _file_sbat_start; + _file_head_size = _file_text_start; _file_text_size = _file_text_end - _file_text_start; _file_reloc_size = _file_reloc_end - _file_reloc_start; _file_sbat_size = _file_sbat_end - _file_sbat_start; @@ -45,7 +46,7 @@ SECTIONS { _sys_size = (_real_text_size + 15) >> 4; _init_size = _real_text_size + _bss_size; - _virt_head_size = ((_file_text_start + 4095) >> 12) << 12; + _virt_head_size = ((_file_head_size + 4095) >> 12) << 12; _virt_text_size = ((_init_size + 4095) >> 12) << 12; _virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12; _virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12; diff --git a/build64/ldscripts/memtest_efi.lds b/build64/ldscripts/memtest_efi.lds index 784382b..14d1a49 100644 --- a/build64/ldscripts/memtest_efi.lds +++ b/build64/ldscripts/memtest_efi.lds @@ -38,6 +38,7 @@ SECTIONS { _real_reloc_size = _real_reloc_end - _file_reloc_start; _real_sbat_size = _real_sbat_end - _file_sbat_start; + _file_head_size = _file_text_start; _file_text_size = _file_text_end - _file_text_start; _file_reloc_size = _file_reloc_end - _file_reloc_start; _file_sbat_size = _file_sbat_end - _file_sbat_start; @@ -45,7 +46,7 @@ SECTIONS { _sys_size = (_real_text_size + 15) >> 4; _init_size = _real_text_size + _bss_size; - _virt_head_size = ((_file_text_start + 4095) >> 12) << 12; + _virt_head_size = ((_file_head_size + 4095) >> 12) << 12; _virt_text_size = ((_init_size + 4095) >> 12) << 12; _virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12; _virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12; From ce2c29eddc627350f96be5cdd176f61ab99e070a Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Thu, 2 Feb 2023 23:52:18 +0100 Subject: [PATCH 090/113] Bump version to v6.10 --- app/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/version.h b/app/version.h index 24065ce..8b321b9 100644 --- a/app/version.h +++ b/app/version.h @@ -1,2 +1,2 @@ -#define MT_VERSION "6.01" +#define MT_VERSION "6.10" #define GIT_HASH "unknown" From 68e9542c1ec1bbc026d9d2035646108b64e6ce2d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 4 Feb 2023 10:10:05 +0000 Subject: [PATCH 091/113] Restore ability to build 64-bit binaries when building on 32-bit system. --- build64/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From a47f681151f1975807da1acc4bee84fb685b470b Mon Sep 17 00:00:00 2001 From: Jonathan Teh Date: Sun, 5 Feb 2023 00:46:02 +0000 Subject: [PATCH 092/113] smbus: Add support for VIA VT8237 Tested on Jetway J7F2 with VT8237R+. Signed-off-by: Jonathan Teh --- system/smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index 7053c63..fb2e640 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1254,7 +1254,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // case 0x3074: // 8233_0 // case 0x3147: // 8233A case 0x3177: // 8235 - // case 0x3227: // 8237 + case 0x3227: // 8237 // case 0x3337: // 8237A // case 0x3372: // 8237S // case 0x3287: // 8251 From 8305d47675e52f84d52482adbf1d158233e311b7 Mon Sep 17 00:00:00 2001 From: Jonathan Teh <30538043+jonathan-teh@users.noreply.github.com> Date: Fri, 10 Feb 2023 21:32:31 +0000 Subject: [PATCH 093/113] Support cache and temperature info for VIA/Centaur/Zhaoxin CPUs (#259) * Support cache and temperature info for VIA/Centaur/Zhaoxin CPUs Use extended CPUID for VIA C3/C7/Nano cache information. Use MSR reads for Nano/Zhaoxin and VIA C7 processor temperature. Tested on VIA C7-D 1.5GHz. * Small code conventions fixes * Fix overallocation of cpuid_cache_info_t union (From PR #263) --------- Co-authored-by: Sam Demeulemeester --- system/cpuid.c | 20 ++++++++++++++++++++ system/cpuid.h | 2 +- system/cpuinfo.c | 10 ++++++++-- system/temperature.c | 20 +++++++++++++++++++- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/system/cpuid.c b/system/cpuid.c index 260f138..c11965f 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -128,6 +128,26 @@ void cpuid_init(void) ); } break; + case 'C': + if (cpuid_info.vendor_id.str[5] == 'I') break; // Cyrix + // VIA / CentaurHauls + 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. diff --git a/system/cpuid.h b/system/cpuid.h index a16c1ae..009772f 100644 --- a/system/cpuid.h +++ b/system/cpuid.h @@ -122,7 +122,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..7d4b58c 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -71,10 +71,16 @@ 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') break; // Cyrix + // VIA C3/C7/Nano + if (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': // Intel Processors diff --git a/system/temperature.c b/system/temperature.c index 5d29cb5..4d3c0aa 100644 --- a/system/temperature.c +++ b/system/temperature.c @@ -47,7 +47,7 @@ int get_cpu_temperature(void) } // 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.extendedFamily > 0 && cpuid_info.version.extendedFamily < 8) { // Untested yet uint32_t rtcr = pci_config_read32(0, 24, 3, 0xA4); @@ -69,5 +69,23 @@ int get_cpu_temperature(void) return offset + 0.125f * (float)((tval >> 21) & 0x7FF); } + // 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 msrl, msrh, msr_temp; + + if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) { + msr_temp = 0x1423; // Zhaoxin, Nano + } else if (cpuid_info.version.model == 0xA || cpuid_info.version.model == 0xD) { + msr_temp = 0x1169; // C7 A/D + } else { + return 0; + } + + rdmsr(msr_temp, msrl, msrh); + return (int)(msrl & 0xffffff); + } + return 0; } From f62bbfde324a7e1006965c470ad0c3602cd2962d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 11 Feb 2023 09:14:56 +0000 Subject: [PATCH 094/113] Additional fix to support use on headless EFI systems (issue #240) --- boot/efisetup.c | 4 ++++ 1 file changed, 4 insertions(+) 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; From dfc41f71969d9b2b3d406fb62c74320a6fa1dd1b Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 11 Feb 2023 19:00:36 +0100 Subject: [PATCH 095/113] Solve incorrect core/thread count on some VIA CPUs No Cyrix / VIA / CentaurHauls / Zhaoxin CPUs support HT, so disable it. --- system/cpuid.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/system/cpuid.c b/system/cpuid.c index c11965f..1ca7eca 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -4,7 +4,7 @@ // // Derived from memtest86+ cpuid.h - +#include #include #include "cpuid.h" @@ -196,7 +196,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 From c38b0cbc5fc9bde7508b6c92fe3b8532bca19340 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 13 Feb 2023 19:43:09 +0100 Subject: [PATCH 096/113] [SMBUS] Add support for nVidia nForce 3 --- system/smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index fb2e640..20d2f29 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1204,7 +1204,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 From 22663f89bb3280cf7ca2415cfd93910c2ba2bd1a Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Mon, 13 Feb 2023 22:29:17 +0100 Subject: [PATCH 097/113] Add support for AMD K8 temperature reporting. (#268) Add various quirks to handle AMD temp sensors erratas --- app/main.c | 2 ++ system/cpuid.c | 4 +-- system/cpuid.h | 3 +- system/hwquirks.c | 86 +++++++++++++++++++++++++++++++++++++++++++- system/hwquirks.h | 6 +++- system/msr.h | 3 ++ system/temperature.c | 53 ++++++++++++++++++--------- system/temperature.h | 14 ++++++++ 8 files changed, 150 insertions(+), 21 deletions(-) diff --git a/app/main.c b/app/main.c index 19098e6..734b0e7 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(); diff --git a/system/cpuid.c b/system/cpuid.c index 1ca7eca..8217ee9 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -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] ); } diff --git a/system/cpuid.h b/system/cpuid.h index 009772f..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; 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/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/temperature.c b/system/temperature.c index 4d3c0aa..1bcc945 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,18 +17,32 @@ #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 //------------------------------------------------------------------------------ +void temperature_init(void) +{ + // Process temperature-related quirks + if (quirk.type & QUIRK_TYPE_TEMP) { + quirk.process(); + } +} + int get_cpu_temperature(void) { - // Intel CPU if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) { if (cpuid_info.dts_pmp & 1) { @@ -47,26 +62,32 @@ int get_cpu_temperature(void) } // AMD CPU - else 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; + uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP); - } else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily >= 8) { + if ((tval >> 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)((tval >> 21) & 0x7FF); - float offset = 0; + } else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer) - if((tval >> 19) & 0x01) { - offset = -49.0f; + uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10); + int raw_temp = ((rtcr >> 21) & 0x7FF) / 8; + + return (raw_temp > 0) ? raw_temp : 0; + + } else { // Target K8 (CPUID ExtFamily = 0) + + uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8); + int raw_temp = ((rtcr >> 16) & 0xFF) - 49 + cpu_temp_offset; + + return (raw_temp > 0) ? raw_temp : 0; } - - return offset + 0.125f * (float)((tval >> 21) & 0x7FF); } // VIA/Centaur/Zhaoxin CPU @@ -76,9 +97,9 @@ int get_cpu_temperature(void) uint32_t msrl, msrh, msr_temp; if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) { - msr_temp = 0x1423; // Zhaoxin, Nano + msr_temp = MSR_VIA_TEMP_NANO; // Zhaoxin, Nano } else if (cpuid_info.version.model == 0xA || cpuid_info.version.model == 0xD) { - msr_temp = 0x1169; // C7 A/D + msr_temp = MSR_VIA_TEMP_C7; // C7 A/D } else { 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. From 1a38f513de8eca354729ecd5f81bfaf3c3f2d138 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Sat, 18 Feb 2023 18:43:38 +0100 Subject: [PATCH 098/113] [Temperature] Add support for CPUs with specific TjMax (#269) Solve an issue where reading MSR_IA32_TEMPERATURE_TARGET makes the system crash (e.g. Early Mobile Yonah) --- system/temperature.c | 73 +++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/system/temperature.c b/system/temperature.c index 1bcc945..89382ec 100644 --- a/system/temperature.c +++ b/system/temperature.c @@ -33,32 +33,57 @@ 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 @@ -66,25 +91,25 @@ int get_cpu_temperature(void) if (cpuid_info.version.extendedFamily >= 8) { // Target Zen µarch and newer. Use SMN to get temperature. - uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP); + regl = amd_smn_read(SMN_THM_TCON_CUR_TMP); - if ((tval >> 19) & 0x01) { - cpu_temp_offset = -49.0f; + if ((regl >> 19) & 0x01) { + cpu_temp_offset = -49.0f; } - return cpu_temp_offset + 0.125f * (float)((tval >> 21) & 0x7FF); + return cpu_temp_offset + 0.125f * (float)((regl >> 21) & 0x7FF); } else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer) - uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10); - int raw_temp = ((rtcr >> 21) & 0x7FF) / 8; + 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) - uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8); - int raw_temp = ((rtcr >> 16) & 0xFF) - 49 + cpu_temp_offset; + 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; } @@ -94,7 +119,7 @@ int get_cpu_temperature(void) 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 msrl, msrh, msr_temp; + uint32_t msr_temp; if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) { msr_temp = MSR_VIA_TEMP_NANO; // Zhaoxin, Nano @@ -104,8 +129,8 @@ int get_cpu_temperature(void) return 0; } - rdmsr(msr_temp, msrl, msrh); - return (int)(msrl & 0xffffff); + rdmsr(msr_temp, regl, regh); + return (int)(regl & 0xffffff); } return 0; From a1d046fc3ade2b60f5051175e66011774f0d258e Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 18 Feb 2023 18:51:02 +0100 Subject: [PATCH 099/113] Fix a typo in README.md (serial console baud rate) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From e1fc02bfe0ddb41e931776399f7b2d09cdf0142b Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 18 Feb 2023 18:58:34 +0100 Subject: [PATCH 100/113] [SMBUS] Add support for VIA VT8233A Southbridge --- system/smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index 20d2f29..599f3e4 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1252,7 +1252,7 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) // viapro SMBus controller, i.e. PIIX4. return piix4_get_smb(PIIX4_SMB_BASE_ADR_DEFAULT); // case 0x3074: // 8233_0 - // case 0x3147: // 8233A + case 0x3147: // 8233A case 0x3177: // 8235 case 0x3227: // 8237 // case 0x3337: // 8237A From ee0c400821c28155f1f2a78243529c974a6d9f3f Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sat, 18 Feb 2023 19:01:59 +0100 Subject: [PATCH 101/113] [SMBUS] Add support for VIA VT8233 Southbridge --- system/smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/smbus.c b/system/smbus.c index 599f3e4..2e1ef21 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1251,7 +1251,7 @@ 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 0x3074: // 8233 case 0x3147: // 8233A case 0x3177: // 8235 case 0x3227: // 8237 From 66bd82f12a7eb6d269ad0bdbe295e71297ae1cef Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Sun, 19 Feb 2023 17:29:56 +0100 Subject: [PATCH 102/113] [SMBus] Add support for ALi M1563 Southbridge (#272) --- system/smbus.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- system/smbus.h | 14 +++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 2e1ef21..e0fe4e9 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" @@ -53,6 +53,7 @@ static bool ich5_get_smb(void); 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_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr); static inline uint8_t bcd_to_ui8(uint8_t bcd) { @@ -1282,8 +1283,9 @@ 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/1543 + case 0x1563: // ALi M1563 + return piix4_get_smb(PIIX4_SMB_BASE_ADR_ALI1563); default: return false; } @@ -1444,6 +1446,8 @@ 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: + return ali_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 +1590,38 @@ static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) return __inb(NVSMBDAT(0)); } + +static uint8_t ali_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); +} diff --git a/system/smbus.h b/system/smbus.h index 116ae0c..fd179c1 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,17 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f +/* ALi-Specific constants */ +#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 + /** Rounding factors for timing computation * * These factors are used as a configurable CEIL() function @@ -87,6 +98,7 @@ #define PIIX4_SMB_BASE_ADR_DEFAULT 0x90 #define PIIX4_SMB_BASE_ADR_VIAPRO 0xD0 +#define PIIX4_SMB_BASE_ADR_ALI1563 0x80 struct pci_smbus_controller { unsigned vendor; From 262aac4f85f36c7181e5d39c12c15694390e2229 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:31:33 +0100 Subject: [PATCH 103/113] [SMBUS] Add support for ALi M1533/1535/1543C (#273) Closes #126 --- system/smbus.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++--- system/smbus.h | 14 ++++++++- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index e0fe4e9..46b1f8e 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -50,10 +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_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) { @@ -1283,7 +1285,8 @@ static bool find_smb_controller(uint16_t vid, uint16_t did) case PCI_VID_ALI: switch(did) { - // case 0x7101: // ALi M1533/1535/1543 + 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: @@ -1439,6 +1442,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 // ------------------ @@ -1447,7 +1479,10 @@ static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) { switch ((smbus_id >> 16) & 0xFFFF) { case PCI_VID_ALI: - return ali_read_spd_byte(slot_idx, (uint8_t)spd_adr); + 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: @@ -1591,7 +1626,7 @@ static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) return __inb(NVSMBDAT(0)); } -static uint8_t ali_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) { int i; @@ -1625,3 +1660,38 @@ static uint8_t ali_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr) 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 fd179c1..3925845 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -74,7 +74,7 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f -/* ALi-Specific constants */ +/* ALi-Specific constants (M1563 & newer) */ #define ALI_SMBHSTCNT_SIZEMASK 0x03 #define ALI_SMBHSTSTS_BAD 0x1C @@ -85,6 +85,17 @@ #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 @@ -99,6 +110,7 @@ #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; From dcca756e48517eb8438fb5afd98f73870cefb4a3 Mon Sep 17 00:00:00 2001 From: Jonathan Teh <30538043+jonathan-teh@users.noreply.github.com> Date: Fri, 3 Mar 2023 12:21:27 +0000 Subject: [PATCH 104/113] [cpuinfo] Fix old CPUs (P5/P6-class) name and cache info (#267) * cpuinfo: Fix WinChip and Cyrix/NSC CPU name and cache info Always populate the cache info from extended CPUID, it is not used for Intel CPUs, even though it is present, and is useful for non-Intel CPUs. Fix the CPU name and cache sizes for Centaur and Cyrix/NSC CPUs without brand string, which are the WinChip C6 and all Cyrix CPUs except the Media GXm. For the Media GXm and Geode GXm/GXLV/GX1, which are available with both Cyrix and NSC vendor strings, hardcode the L1 cache size. The Geode GX2 uses standard cache info. * Add 'Intel' in CPU names for older CPUs * Add 'Transmeta' and 'IDT' in CPU names for older CPUs ------- Co-authored-by: Sam Demeulemeester --- system/cpuid.c | 59 +++++------------- system/cpuinfo.c | 155 ++++++++++++++++++++++------------------------- 2 files changed, 87 insertions(+), 127 deletions(-) diff --git a/system/cpuid.c b/system/cpuid.c index 8217ee9..2200b56 100644 --- a/system/cpuid.c +++ b/system/cpuid.c @@ -108,50 +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 'C': - if (cpuid_info.vendor_id.str[5] == 'I') break; // Cyrix - // VIA / CentaurHauls - 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 diff --git a/system/cpuinfo.c b/system/cpuinfo.c index 7d4b58c..97a3b82 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -71,9 +71,17 @@ static void determine_cache_size() l3_cache *= 512; break; case 'C': - if (cpuid_info.vendor_id.str[5] == 'I') break; // Cyrix - // VIA C3/C7/Nano - if (cpuid_info.version.family == 6) { + 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; @@ -83,6 +91,25 @@ static void determine_cache_size() // 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; @@ -605,9 +632,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; @@ -653,14 +680,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; } @@ -673,54 +700,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: @@ -728,7 +755,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"; } @@ -743,17 +770,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: @@ -773,78 +800,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; @@ -855,10 +844,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"; From bf0dae04bc70bc9f971e9fb6fbb199ca4b523bf0 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Tue, 7 Mar 2023 00:34:31 +0100 Subject: [PATCH 105/113] Remove deprecated ubuntu-18.04 job --- .github/workflows/Linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 5cbcd2046b4283d0c9d231c89fe7ae207055b3ad Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Thu, 9 Mar 2023 23:08:01 +0100 Subject: [PATCH 106/113] Add 'Jade Star' & 'InnoDisk' JEDEC Manufacturers --- system/jedec_id.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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" }, From c6b04e5414c0872cf845cbd0f3c12d46d2839239 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Wed, 29 Mar 2023 17:58:12 +0200 Subject: [PATCH 107/113] Display big banner only once --- app/display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/display.c b/app/display.c index 4e6b14a..c3be373 100644 --- a/app/display.c +++ b/app/display.c @@ -399,6 +399,7 @@ void restore_big_status(void) restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer); big_status_displayed = false; + enable_big_status = false; } void check_input(void) From 79bb781431036e22d459544aa59f3d127fd0fa6b Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Wed, 29 Mar 2023 18:29:59 +0200 Subject: [PATCH 108/113] Better handling of big FAIL banned in case of errors --- app/display.c | 2 +- app/main.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/display.c b/app/display.c index c3be373..27f0e1e 100644 --- a/app/display.c +++ b/app/display.c @@ -399,7 +399,6 @@ void restore_big_status(void) restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer); big_status_displayed = false; - enable_big_status = false; } void check_input(void) @@ -410,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 734b0e7..565ff78 100644 --- a/app/main.c +++ b/app/main.c @@ -671,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); } } } From bfbb167a72cfa9981318bc9fabc93548befba8f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 18:34:20 +0200 Subject: [PATCH 109/113] Bump actions/stale from 7 to 8 (#287) Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/expired.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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' From fa4e9035099f4f983fc769aa4a6cfbd2dc13720a Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 23 Apr 2023 22:45:11 +0200 Subject: [PATCH 110/113] Fix APIC Timer detection fail on some modern mobile/embedded PCH On some modern ULV cores (eg: Gracemont), the 2 following I/O reads to check APIC Timer working status are fused in the frontend, leading to the same value being reported twice and the code falling back to the (unusually disabled on these platforms) PIT timer. Whether this behavior is intentional or not is unknown. As usleep/sleep is not available at this point, a dirty delay is added between the two reads. --- system/timers.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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) { From 0fd2e4c37a1d32cfaeaa075e7d33e77f25e1f778 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Mon, 24 Apr 2023 00:29:37 +0200 Subject: [PATCH 111/113] Add support for Intel AlderLake-N CPUs --- system/cpuinfo.c | 3 +++ system/cpuinfo.h | 3 ++- system/hwquirks.c | 18 ++++++++++++++++++ system/hwquirks.h | 3 ++- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/system/cpuinfo.c b/system/cpuinfo.c index 97a3b82..cba579c 100644 --- a/system/cpuinfo.c +++ b/system/cpuinfo.c @@ -493,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; } 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 f1fd0ed..e5e9359 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -99,6 +99,15 @@ static void amd_k8_revfg_temp(void) cpu_temp_offset = 21.0f; } +static void adl_unlock_smbus(void) +{ + uint16_t x = pci_config_read16(0, 31, 4, 0x04); + + if (!(x & 1)) { + pci_config_write16(0, 31, 4, 0x04, x | 1); + } +} + // --------------------- // -- Public function -- // --------------------- @@ -199,4 +208,13 @@ void quirks_init(void) } } } + + // -------------------------------------------------- + // -- SMBus unlock for ADL-N (and probably others) -- + // -------------------------------------------------- + if (imc_type == IMC_ADL_N && pci_config_read16(0, 31, 4, 0x2) == 0x54A3) { // ADL-N + quirk.id = QUIRK_ADL_SMB_UNLOCK; + quirk.type |= QUIRK_TYPE_SMBUS; + quirk.process = adl_unlock_smbus; + } } diff --git a/system/hwquirks.h b/system/hwquirks.h index daf22b8..152877f 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -28,7 +28,8 @@ typedef enum { QUIRK_X10SDV_NOSMP, QUIRK_K8_BSTEP_NOTEMP, QUIRK_K8_REVFG_TEMP, - QUIRK_AMD_ERRATA_319 + QUIRK_AMD_ERRATA_319, + QUIRK_ADL_SMB_UNLOCK } quirk_id_t; typedef struct { From 1f1fe5bfe871600dad3bd9a0de538d8e051353a9 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Wed, 26 Apr 2023 00:42:52 +0200 Subject: [PATCH 112/113] Generalize the SMBus IO Enable quirk on all Intel ICHs This has been tested safe on every ICH since the very first one by CPU-Z. It also solves various SMBus access issues on Mobile PCHs (like #157) --- system/hwquirks.c | 18 ------------------ system/hwquirks.h | 3 +-- system/smbus.c | 10 +++++++++- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/system/hwquirks.c b/system/hwquirks.c index e5e9359..f1fd0ed 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -99,15 +99,6 @@ static void amd_k8_revfg_temp(void) cpu_temp_offset = 21.0f; } -static void adl_unlock_smbus(void) -{ - uint16_t x = pci_config_read16(0, 31, 4, 0x04); - - if (!(x & 1)) { - pci_config_write16(0, 31, 4, 0x04, x | 1); - } -} - // --------------------- // -- Public function -- // --------------------- @@ -208,13 +199,4 @@ void quirks_init(void) } } } - - // -------------------------------------------------- - // -- SMBus unlock for ADL-N (and probably others) -- - // -------------------------------------------------- - if (imc_type == IMC_ADL_N && pci_config_read16(0, 31, 4, 0x2) == 0x54A3) { // ADL-N - quirk.id = QUIRK_ADL_SMB_UNLOCK; - quirk.type |= QUIRK_TYPE_SMBUS; - quirk.process = adl_unlock_smbus; - } } diff --git a/system/hwquirks.h b/system/hwquirks.h index 152877f..daf22b8 100644 --- a/system/hwquirks.h +++ b/system/hwquirks.h @@ -28,8 +28,7 @@ typedef enum { QUIRK_X10SDV_NOSMP, QUIRK_K8_BSTEP_NOTEMP, QUIRK_K8_REVFG_TEMP, - QUIRK_AMD_ERRATA_319, - QUIRK_ADL_SMB_UNLOCK + QUIRK_AMD_ERRATA_319 } quirk_id_t; typedef struct { diff --git a/system/smbus.c b/system/smbus.c index 46b1f8e..a014ea2 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -1340,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); From 5dcd424ea7afb857c1171e747ef064d98d26afeb Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester Date: Sun, 7 May 2023 16:55:03 +0200 Subject: [PATCH 113/113] Bump version to v6.20 --- app/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"