raw-cpuid-11.6.0/.cargo_vcs_info.json0000644000000001360000000000100130140ustar { "git": { "sha1": "aefadf7dd8d9e37ad94171d617158cad2133f3f7" }, "path_in_vcs": "" }raw-cpuid-11.6.0/.github/dependabot.yml000064400000000000000000000012121046102023000157700ustar 00000000000000# See # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/enabling-and-disabling-version-updates # for details version: 2 updates: # Enable crate version updates for the main crate - package-ecosystem: "cargo" # Look `Cargo.toml` in the repository root directory: "/" # Check for updates every day (weekdays) schedule: interval: "daily" # Enable version updates for Github Actions - package-ecosystem: "github-actions" # Set to `/` to check the Actions used in `.github/workflows` directory: "/" # Check for updates every day (weekdays) schedule: interval: "daily" raw-cpuid-11.6.0/.github/workflows/coverage.yml000064400000000000000000000021451046102023000175210ustar 00000000000000name: Coverage on: [push, pull_request] jobs: check: name: Coverage runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4.2.2 - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly components: llvm-tools-preview override: true - name: Restore cache uses: Swatinem/rust-cache@v2 - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Generate code coverage uses: actions-rs/cargo@v1 with: command: llvm-cov args: --all-features --workspace --lcov --output-path coverage.info --ignore-filename-regex tests.rs - name: Upload to codecov.io uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage.info fail_ci_if_error: true - name: Archive code coverage results uses: actions/upload-artifact@v4 with: name: code-coverage-report path: coverage.inforaw-cpuid-11.6.0/.github/workflows/standard.yml000064400000000000000000000023071046102023000175260ustar 00000000000000name: Standard checks on: push: branches: [master] pull_request: branches: [master] jobs: ci: runs-on: ubuntu-latest strategy: matrix: rust: - stable - nightly steps: - uses: actions/checkout@v4.2.2 - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.rust }} override: true components: rustfmt, clippy target: aarch64-unknown-linux-gnu - uses: actions-rs/cargo@v1.0.3 with: command: build - uses: actions-rs/cargo@v1.0.3 with: command: build args: --all-features - name: Build on target without native cpuid uses: actions-rs/cargo@v1.0.3 with: command: build args: --target aarch64-unknown-linux-gnu - uses: actions-rs/cargo@v1.0.3 with: command: test args: --all-features --all-targets - uses: actions-rs/cargo@v1.0.3 with: command: fmt args: --all -- --check - name: Run clippy uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} raw-cpuid-11.6.0/.gitignore000064400000000000000000000000321046102023000135670ustar 00000000000000target/ Cargo.lock .vscoderaw-cpuid-11.6.0/AUTHORS000064400000000000000000000017001046102023000126520ustar 00000000000000Gerd Zellweger Bence Meszaros Rafal Mielniczuk Stefan Lankes Mingshen Sun Niklas Fiekas Philipp Schuster Gabriel Majeri Bruce Mitchener John Ericson Paul Sbarra Pireax Tyler Hall Alex McKenna BenoĆ®t du Garreau Colin Finck Gabriel John Bartholomew Nathaniel McCallum Olivier Lemasle IsaacDynamo <61521674+IsaacDynamo@users.noreply.github.com> Zavier Divelbiss Umio Yasuno <53935716+Umio-Yasuno@users.noreply.github.com> Matt Keeter raw-cpuid-11.6.0/CHANGELOG.md000064400000000000000000000214431046102023000134210ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [11.1.0] - 2024-07-17 - Support for more AVX512 Extended Features ## [11.0.2] - 2024-04-29 - Fix bug in `has_waitpkg` using wrong bit flag. ## [11.0.1] - 2023-05-03 - Fix a regression from v10.7.0. CpuIdReader was falsely required to implement Debug for `CpuId::debug()` which is too strict. ## [11.0.0] - 2023-04-17 ### Breaking changes - The `CpuId` type now takes a generic reader argument `CpuId`: which allows for more flexibility on how cpuid is queried and better support for using the library on non-x86 targets. This is a breaking change for users of `with_cpuid_fn` and potentially when specifying `CpuId` as a type argument somewhere. To make existing code compile again, whenever a generic type argument for CpuId is needed, you can use the `cpuid::NativeCpuIdReader` type which provides the default behavior of execution the `cpuid` instruction. For example, in your code there might be cases where the compiler now asks you to specify the generic type of CpuId: e.g., `fn take_cpuid(cpuid: CpuId)` would become: `fn take_cpuid(cpuid: CpuId)` See also [#140](https://github.com/gz/rust-cpuid/pull/140) and [#138](https://github.com/gz/rust-cpuid/pull/138) for the original discussion. - If you're using the `serialization` feature: It go revamped by fixing some long-standing problems with it that made it difficult to use [#87](https://github.com/gz/rust-cpuid/issues/87). All types except `CpuIdResult` types lost their `Serialize` and `Deserialize` derives. Check the [new example](examples/serialize_deserialize.rs) on how to serialize and deserialize cpuid information. ## Other changes - Updated bitflags to v2. ## [10.7.0] - 2023-02-27 - Include the pretty printing code in the library (instead of only having it in the binary) ([#137](https://github.com/gz/rust-cpuid/pull/137)) This introduces a new (optional) `display` feature. `display` will also enable `std` so it can't be used in `no_std` environments. ## [10.6.1] - 2023-02-03 - Fix potential overflow during formatting when using the in cpuid binary to display cache information. ([#133](https://github.com/gz/rust-cpuid/issues/133)) ## [10.6.0] - 2022-09-12 - Updated termimad to 0.20 (only affects `cpuid` binary version) - Add support for AMD leaf `0x8000_001E` - Add support for AMD leaf `0x8000_0019` - Updated `ExtendedFeatures` to include new features ## [10.5.0] - 2022-08-17 - Updated phf to 0.11 (only affects `cfg(test)`) - Add support for AMD leaf `0x8000_001D` - Add support for AMD leaf `0x8000_001A` ## [10.4.0] - 2022-08-01 - Added support for cpuid leaf 0x1f (Extended Topology Information v2) - Improved debug formatting for `ProcessorCapacityAndFeatureInfo` ## [10.3.0] - 2022-03-15 ### Added - Added ExtendedFeatures::has_avx512vnni(). - Allow to build/use the crate even if `native_cpuid` is not available on the target (one can still instantiate CpuId using `with_cpuid_fn` in this case). ## Changed - Updated clap dependency. ## [10.2.0] - 2021-07-30 ### Added - Fix Cache and TLB (leaf 0x02) formatting in cpuid binary. ## Changed - Added JSON and raw formatting to cpuid binary. ## [10.1.0] - 2021-07-30 ### Added - AMD SVM feature leaf (0x8000_000A) - Added methods to display upper 64-96 bits of processor serial number (`serial_all`, `serial_upper`) - Implement `Display` for `CacheType` - Implement `Display` for `TopologyType` - Implement `Display` for `DatType` - Implement `Display` for `Associativity` - Added `location()` method for `ExtendedState` as an alternative for `is_in_ia32_xss` and `is_in_xcr0`. - Added new `register()` method for `ExtendedState` to identify which register this instance refers to. ## Changed - Better formatting for cpuid binary. ## [10.0.0] - 2021-07-14 ### Breaking changes for v10 - Removed `get_extended_function_info` / `ExtendedFunctionInfo` due to added AMD support: Use `get_processor_brand_string`, `get_extended_processor_and_feature_identifiers`, `get_l1_cache_and_tlb_info`, `get_l2_l3_cache_and_tlb_info`, `get_advanced_power_mgmt_info`, `get_processor_capacity_feature_info` instead: Migration guide for replacing `get_extended_function_info` / `ExtendedFunctionInfo`: | <= v9 | >= v10 | | -------------------------- | ------------------------------------------------------------------------------ | | `processor_brand_string()` | `CpuId.get_processor_brand_string` | | `cache_line_size()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_line_size()` | | `l2_associativity()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_associativity()` | | `cache_size()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_size()` | | `physical_address_bits()` | `CpuId.get_processor_capacity_feature_info().physical_address_bits()` | | `linear_address_bits()` | `CpuId.get_processor_capacity_feature_info().linear_address_bits()` | | `has_invariant_tsc()` | `CpuId.get_advanced_power_mgmt_info.has_invariant_tsc()` | | `has_lahf_sahf()` | `CpuId.get_extended_processor_and_feature_identifiers().has_lahf_sahf()` | | `has_lzcnt()` | `CpuId.get_extended_processor_and_feature_identifiers().has_lzcnt()` | | `has_prefetchw()` | `CpuId.get_extended_processor_and_feature_identifiers().has_prefetchw()` | | `has_syscall_sysret()` | `CpuId.get_extended_processor_and_feature_identifiers().has_syscall_sysret()` | | `has_execute_disable()` | `CpuId.get_extended_processor_and_feature_identifiers().has_execute_disable()` | | `has_1gib_pages()` | `CpuId.get_extended_processor_and_feature_identifiers().has_1gib_pages()` | | `has_rdtscp()` | `CpuId.get_extended_processor_and_feature_identifiers().has_rdtscp()` | | `has_64bit_mode()` | `CpuId.get_extended_processor_and_feature_identifiers().has_64bit_mode()` | - Removed `CpuId.deterministic_address_translation_info`. Use `CpuId.get_deterministic_address_translation_info` instead. - Renamed `model_id` and `family_id` to `base_model_id` and `base_family_id` in `FeatureInfo`. Added new `family_id` and `model_id` functions that compute the actual model and family according to the spec by joining base and extended family/model. - Extend Hypervisor enum with more variants ([#50](https://github.com/gz/rust-cpuid/pull/50)) - Remove `has_rdseet` function (deprecated since 3.2), clients should use the correctly named `has_rdseed` function instead. Migration guide for `cpuid.get_feature_info()`: | <= v9 | >= v10 | | ----------- | ----------- | | `has_rdseet()` | `has_rdseed()` | - Removed `Default` traits for most structs. `default()` should not be used anymore. ### Changes - Updated Debug trait for SGX iterators. - Make CpuId derive Clone and Copy ([#53](https://github.com/gz/rust-cpuid/pull/53)) - Improved documentation in some places by adding leaf numbers. - Updated AMD leaf 0x8000_001f (Encrypted Memory) to latest manual. - `ProcessorBrandString.as_str()` now trims the returned string. - Fix `RdtAllocationInfo.memory_bandwidth_allocation()` which was using l2cat availability to determine if it exists. ### Added - Added AMD support for leaf 0x8000_0001 - Added AMD support for leaf 0x8000_0005 - Added AMD support for leaf 0x8000_0006 - Added AMD support for leaf 0x8000_0007 - Added AMD support for leaf 0x8000_0008 ### Deprecated - `VendorInfo.as_string()` is deprecated in favor of `VendorInfo.as_str()` - `SoCVendorBrand.as_string()` is deprecated in favor of `SoCVendorBrand.as_str()` ## [9.1.1] - 2021-07-06 ### Changed - Use more idiomatic rust code in readme/doc.rs example. - Use `str::from_utf8` instead of `str::from_utf8_unchecked` to avoid potential panics with the Deserialize trait ([#43](https://github.com/gz/rust-cpuid/issues/43)). - More extensive Debug trait implementation ([#49](https://github.com/gz/rust-cpuid/pull/49)) - Fix 2 clippy warnings ## [9.1.0] - 2021-07-03 ### Added - A `CpuId::with_cpuid_fn` that allows to override the default cpuid function. ### Changed - Fixed `RdtAllocationInfo.has_memory_bandwidth_allocation`: was using the wrong bit - Fixed `capacity_mask_length` in `L3CatInfo` and `L2CatInfo`: add +1 to returned value - Fixed `MemBwAllocationInfo.max_hba_throttling`: add +1 to returned value - Refactored tests into a module. - Started to add tests for Ryzen/AMD. raw-cpuid-11.6.0/Cargo.lock0000644000000527540000000000100110040ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "coolor" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95ce3e41909f18d5860fe1e6699651fcca2cb2576ee68c6984c93c2b26d059ea" dependencies = [ "crossterm", ] [[package]] name = "core_affinity" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622892f5635ce1fc38c8f16dfc938553ed64af482edb5e150bf4caedbfcb2304" dependencies = [ "libc", "num_cpus", "winapi", ] [[package]] name = "crossbeam" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", "crossbeam-queue", "crossbeam-utils", ] [[package]] name = "crossbeam-channel" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crossterm" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" dependencies = [ "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy-regex" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" dependencies = [ "lazy-regex-proc_macros", "once_cell", "regex", ] [[package]] name = "lazy-regex-proc_macros" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" dependencies = [ "proc-macro2", "quote", "regex", "syn", ] [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "minimad" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6c4610f430e49b882fcaad0186134150d4d74fc76080b0a61f7000460c2e268" dependencies = [ "once_cell", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", "windows-sys 0.48.0", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.52.5", ] [[package]] name = "phf" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", ] [[package]] name = "phf_generator" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", ] [[package]] name = "phf_macros" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", "syn", ] [[package]] name = "phf_shared" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "proc-macro2" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "raw-cpuid" version = "11.6.0" dependencies = [ "bitflags 2.5.0", "clap", "core_affinity", "libc", "phf", "rustversion", "serde", "serde_derive", "serde_json", "termimad", ] [[package]] name = "redox_syscall" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ "bitflags 2.5.0", ] [[package]] name = "regex" version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustversion" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", "mio", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termimad" version = "0.25.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1d090fe2d927c784b92ef54daddd9df070c856057715002d484bc7f49ae47d0" dependencies = [ "coolor", "crossbeam", "crossterm", "lazy-regex", "minimad", "serde", "thiserror", "unicode-width", ] [[package]] name = "thiserror" version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.5", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm 0.52.5", "windows_aarch64_msvc 0.52.5", "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", "windows_i686_msvc 0.52.5", "windows_x86_64_gnu 0.52.5", "windows_x86_64_gnullvm 0.52.5", "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] name = "windows_i686_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" raw-cpuid-11.6.0/Cargo.toml0000644000000047240000000000100110210ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "raw-cpuid" version = "11.6.0" authors = ["Gerd Zellweger "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A library to parse the x86 CPUID instruction, written in rust with no external dependencies. The implementation closely resembles the Intel CPUID manual description. The library does only depend on libcore." homepage = "https://github.com/gz/rust-cpuid" documentation = "https://docs.rs/raw-cpuid/" readme = "README.md" keywords = [ "cpuid", "x86", "amd64", "os", "libcore", ] categories = [ "no-std", "no-std::no-alloc", ] license = "MIT" repository = "https://github.com/gz/rust-cpuid" [features] cli = [ "display", "clap", ] display = [ "std", "termimad", "serde_json", "serialize", ] serialize = [ "serde", "serde_derive", ] std = [] [lib] name = "raw_cpuid" path = "src/lib.rs" [[bin]] name = "cpuid" path = "src/bin/cpuid.rs" required-features = ["cli"] [[example]] name = "cache" path = "examples/cache.rs" [[example]] name = "cpu" path = "examples/cpu.rs" [[example]] name = "serialize_deserialize" path = "examples/serialize_deserialize.rs" required-features = [ "serde_json", "serialize", ] [[example]] name = "topology" path = "examples/topology.rs" [[example]] name = "tsc_frequency" path = "examples/tsc_frequency.rs" [dependencies.bitflags] version = "2.0" [dependencies.clap] version = "4.2" features = ["derive"] optional = true [dependencies.serde] version = "1.0" optional = true default-features = false [dependencies.serde_derive] version = "1.0" optional = true [dependencies.serde_json] version = "1.0" optional = true [dependencies.termimad] version = "0.25" optional = true [dev-dependencies.core_affinity] version = "0.8.0" [dev-dependencies.libc] version = "0.2" default-features = false [dev-dependencies.phf] version = "0.11" features = ["macros"] [dev-dependencies.rustversion] version = "1.0" raw-cpuid-11.6.0/Cargo.toml.orig000064400000000000000000000030311046102023000144700ustar 00000000000000[package] authors = ["Gerd Zellweger "] edition = "2018" name = "raw-cpuid" version = "11.6.0" description = "A library to parse the x86 CPUID instruction, written in rust with no external dependencies. The implementation closely resembles the Intel CPUID manual description. The library does only depend on libcore." documentation = "https://docs.rs/raw-cpuid/" homepage = "https://github.com/gz/rust-cpuid" repository = "https://github.com/gz/rust-cpuid" keywords = ["cpuid", "x86", "amd64", "os", "libcore"] categories = ["no-std", "no-std::no-alloc"] license = "MIT" readme = "README.md" [[bin]] name = "cpuid" path = "src/bin/cpuid.rs" required-features = ["cli"] [[example]] name = "serialize_deserialize" path = "examples/serialize_deserialize.rs" required-features = ["serde_json", "serialize"] [features] std = [] display = ["std", "termimad", "serde_json", "serialize"] serialize = ["serde", "serde_derive"] # This is not a library feature and should only be used to install the cpuid binary: cli = ["display", "clap"] [dependencies] bitflags = { version = "2.0" } serde = { version = "1.0", default-features = false, optional = true } serde_derive = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true } termimad = { version = "0.25", optional = true } clap = { version = "4.2", features = ["derive"], optional = true } [dev-dependencies] core_affinity = "0.8.0" libc = { version = "0.2", default-features = false } phf = { version = "0.11", features = ["macros"] } rustversion = "1.0" raw-cpuid-11.6.0/LICENSE.md000064400000000000000000000020701046102023000132070ustar 00000000000000The MIT License (MIT) Copyright (c) 2015 Gerd Zellweger Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.raw-cpuid-11.6.0/README.md000064400000000000000000000037361046102023000130740ustar 00000000000000# cpuid [![Crates.io](https://img.shields.io/crates/v/raw_cpuid.svg)](https://crates.io/crates/raw-cpuid) [![Standard checks](https://github.com/gz/rust-cpuid/actions/workflows/standard.yml/badge.svg)](https://github.com/gz/rust-cpuid/actions/workflows/standard.yml) A library to parse the x86 CPUID instruction, written in rust with no external dependencies. The implementation closely resembles the Intel CPUID manual description. The library works in `no_std` environments. Some additional cargo features require `std` (e.g., pretty printing, serialization). - For Intel platforms: The code should be in sync with the March 2018 revision of the Intel Architectures SDM. - For AMD platforms it should be in sync with the [AMD64 systems manual no. 24594](https://www.amd.com/system/files/TechDocs/24594.pdf), Revision 3.32 (March 2021). ## Library usage ```rust use raw_cpuid::CpuId; let cpuid = CpuId::new(); if let Some(vf) = cpuid.get_vendor_info() { assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD"); } let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse()); if has_sse { println!("CPU supports SSE!"); } if let Some(cparams) = cpuid.get_cache_parameters() { for cache in cparams { let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets(); println!("L{}-Cache size is {}", cache.level(), size); } } else { println!("No cache parameter information available") } ``` ## `cpuid` binary `raw-cpuid` ships with a `cpuid` binary that can be installed to inspect the output of the CPUID instruction on a host system. To install, use: ```bash cargo install raw-cpuid --features cli ``` The `cli` feature is currently required to build the binary version due to [cargo limitations](https://github.com/rust-lang/cargo/issues/1982). ## Documentation * [API Documentation](https://docs.rs/raw-cpuid/) * [Examples](https://github.com/gz/rust-cpuid/tree/master/examples) raw-cpuid-11.6.0/examples/cache.rs000064400000000000000000000033701046102023000150360ustar 00000000000000//! Example that displays information about the caches. //! //! This example only compiles on x86 platforms. extern crate raw_cpuid; use raw_cpuid::{CacheType, CpuId}; fn main() { let cpuid = CpuId::new(); cpuid.get_cache_parameters().map_or_else( || println!("No cache parameter information available"), |cparams| { for cache in cparams { let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets(); let typ = match cache.cache_type() { CacheType::Data => "Instruction-Cache", CacheType::Instruction => "Data-Cache", CacheType::Unified => "Unified-Cache", _ => "Unknown cache type", }; let associativity = if cache.is_fully_associative() { "fully associative".to_string() } else { format!("{}-way associativity", cache.associativity()) }; let size_repr = if size > 1024 * 1024 { format!("{} MiB", size / (1024 * 1024)) } else { format!("{} KiB", size / 1024) }; let mapping = if cache.has_complex_indexing() { "hash-based-mapping" } else { "direct-mapped" }; println!( "L{} {}: ({}, {}, {})", cache.level(), typ, size_repr, associativity, mapping ); } }, ); } raw-cpuid-11.6.0/examples/cpu.rs000064400000000000000000000222131046102023000145570ustar 00000000000000//! An example that displays the type/features/configuration of the CPU. //! //! This example only compiles on x86 platforms. extern crate raw_cpuid; fn main() { let cpuid = raw_cpuid::CpuId::new(); println!( "Vendor is: {}", cpuid .get_vendor_info() .as_ref() .map_or_else(|| "unknown", |vf| vf.as_str(),) ); println!( "CPU Model is: {}", cpuid .get_processor_brand_string() .as_ref() .map_or_else(|| "n/a", |pbs| pbs.as_str()) ); println!( "APIC ID is: {}", cpuid.get_feature_info().as_ref().map_or_else( || String::from("n/a"), |finfo| format!("{}", finfo.initial_local_apic_id()), ) ); // 10.12.8.1 Consistency of APIC IDs and CPUID: "Initial APIC ID (CPUID.01H:EBX[31:24]) is always equal to CPUID.0BH:EDX[7:0]." println!( "x2APIC ID is: {}", cpuid.get_extended_topology_info().map_or_else( || String::from("n/a"), |mut topiter| format!("{}", topiter.next().as_ref().unwrap().x2apic_id()), ) ); cpuid.get_feature_info().as_ref().map_or_else( || println!("Family: n/a\nExtended Family: n/a\nModel: n/a\nExtended Model: n/a\nStepping: n/a\nBrand Index: n/a"), |finfo| { println!( "Base Family: {}\nExtended Family: {}\nFamily: {}\nBase Model: {}\nExtended Model: {}\nModel: {}\nStepping: {}\nBrand Index: {}", finfo.base_family_id(), finfo.extended_family_id(), finfo.family_id(), finfo.base_model_id(), finfo.extended_model_id(), finfo.model_id(), finfo.stepping_id(), finfo.brand_index(), ); }, ); println!( "Serial# is: {}", cpuid.get_processor_serial().as_ref().map_or_else( || String::from("n/a"), |serial_info| format!("{}", serial_info.serial()) ) ); let mut features = Vec::with_capacity(80); cpuid.get_feature_info().map(|finfo| { if finfo.has_sse3() { features.push("sse3") } if finfo.has_pclmulqdq() { features.push("pclmulqdq") } if finfo.has_ds_area() { features.push("ds_area") } if finfo.has_monitor_mwait() { features.push("monitor_mwait") } if finfo.has_cpl() { features.push("cpl") } if finfo.has_vmx() { features.push("vmx") } if finfo.has_smx() { features.push("smx") } if finfo.has_eist() { features.push("eist") } if finfo.has_tm2() { features.push("tm2") } if finfo.has_ssse3() { features.push("ssse3") } if finfo.has_cnxtid() { features.push("cnxtid") } if finfo.has_fma() { features.push("fma") } if finfo.has_cmpxchg16b() { features.push("cmpxchg16b") } if finfo.has_pdcm() { features.push("pdcm") } if finfo.has_pcid() { features.push("pcid") } if finfo.has_dca() { features.push("dca") } if finfo.has_sse41() { features.push("sse41") } if finfo.has_sse42() { features.push("sse42") } if finfo.has_x2apic() { features.push("x2apic") } if finfo.has_movbe() { features.push("movbe") } if finfo.has_popcnt() { features.push("popcnt") } if finfo.has_tsc_deadline() { features.push("tsc_deadline") } if finfo.has_aesni() { features.push("aesni") } if finfo.has_xsave() { features.push("xsave") } if finfo.has_oxsave() { features.push("oxsave") } if finfo.has_avx() { features.push("avx") } if finfo.has_f16c() { features.push("f16c") } if finfo.has_rdrand() { features.push("rdrand") } if finfo.has_fpu() { features.push("fpu") } if finfo.has_vme() { features.push("vme") } if finfo.has_de() { features.push("de") } if finfo.has_pse() { features.push("pse") } if finfo.has_tsc() { features.push("tsc") } if finfo.has_msr() { features.push("msr") } if finfo.has_pae() { features.push("pae") } if finfo.has_mce() { features.push("mce") } if finfo.has_cmpxchg8b() { features.push("cmpxchg8b") } if finfo.has_apic() { features.push("apic") } if finfo.has_sysenter_sysexit() { features.push("sysenter_sysexit") } if finfo.has_mtrr() { features.push("mtrr") } if finfo.has_pge() { features.push("pge") } if finfo.has_mca() { features.push("mca") } if finfo.has_cmov() { features.push("cmov") } if finfo.has_pat() { features.push("pat") } if finfo.has_pse36() { features.push("pse36") } if finfo.has_psn() { features.push("psn") } if finfo.has_clflush() { features.push("clflush") } if finfo.has_ds() { features.push("ds") } if finfo.has_acpi() { features.push("acpi") } if finfo.has_mmx() { features.push("mmx") } if finfo.has_fxsave_fxstor() { features.push("fxsave_fxstor") } if finfo.has_sse() { features.push("sse") } if finfo.has_sse2() { features.push("sse2") } if finfo.has_ss() { features.push("ss") } if finfo.has_htt() { features.push("htt") } if finfo.has_tm() { features.push("tm") } if finfo.has_pbe() { features.push("pbe") } }); cpuid.get_extended_feature_info().map(|finfo| { if finfo.has_bmi1() { features.push("bmi1") } if finfo.has_hle() { features.push("hle") } if finfo.has_avx2() { features.push("avx2") } if finfo.has_fdp() { features.push("fdp") } if finfo.has_smep() { features.push("smep") } if finfo.has_bmi2() { features.push("bmi2") } if finfo.has_rep_movsb_stosb() { features.push("rep_movsb_stosb") } if finfo.has_invpcid() { features.push("invpcid") } if finfo.has_rtm() { features.push("rtm") } if finfo.has_rdtm() { features.push("rdtm") } if finfo.has_fpu_cs_ds_deprecated() { features.push("fpu_cs_ds_deprecated") } if finfo.has_mpx() { features.push("mpx") } if finfo.has_rdta() { features.push("rdta") } if finfo.has_rdseed() { features.push("rdseed") } if finfo.has_adx() { features.push("adx") } if finfo.has_smap() { features.push("smap") } if finfo.has_clflushopt() { features.push("clflushopt") } if finfo.has_processor_trace() { features.push("processor_trace") } if finfo.has_sha() { features.push("sha") } if finfo.has_sgx() { features.push("sgx") } if finfo.has_avx512f() { features.push("avx512f") } if finfo.has_avx512dq() { features.push("avx512dq") } if finfo.has_avx512_ifma() { features.push("avx512_ifma") } if finfo.has_avx512pf() { features.push("avx512pf") } if finfo.has_avx512er() { features.push("avx512er") } if finfo.has_avx512cd() { features.push("avx512cd") } if finfo.has_avx512bw() { features.push("avx512bw") } if finfo.has_avx512vl() { features.push("avx512vl") } if finfo.has_clwb() { features.push("clwb") } if finfo.has_prefetchwt1() { features.push("prefetchwt1") } if finfo.has_umip() { features.push("umip") } if finfo.has_pku() { features.push("pku") } if finfo.has_ospke() { features.push("ospke") } if finfo.has_rdpid() { features.push("rdpid") } if finfo.has_sgx_lc() { features.push("sgx_lc") } }); println!("CPU Features: {}", features.join(" ")); } raw-cpuid-11.6.0/examples/serialize_deserialize.rs000064400000000000000000000026511046102023000203430ustar 00000000000000//! An example that serializes CpuId state, deserializes it back and passes it to a //! CpuId instance with a custom reader. //! //! Run using: //! `cargo run --features serialize --features serde_json --example serialize_deserialize` use raw_cpuid::{CpuId, CpuIdReader, CpuIdResult}; use std::collections::HashMap; #[derive(Clone)] struct HashMapCpuIdReader { ht: HashMap, } impl CpuIdReader for HashMapCpuIdReader { fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult { let key = (eax as u64) << u32::BITS | ecx as u64; self.ht .get(&key) .unwrap_or(&CpuIdResult { eax: 0, ebx: 0, ecx: 0, edx: 0, }) .clone() } } fn main() { let mut ht = HashMap::new(); ht.insert( 0x00000000_00000000u64, CpuIdResult { eax: 0x00000020, ebx: 0x756e6547, ecx: 0x6c65746e, edx: 0x49656e69, }, ); // Serialize to JSON and back let cpuid_as_json = serde_json::to_string(&ht).unwrap(); let deserialized_ht: HashMap = serde_json::from_str(&cpuid_as_json).unwrap(); // Create a CpuId instance with a custom reader let cpuid = CpuId::with_cpuid_reader(HashMapCpuIdReader { ht: deserialized_ht, }); assert!(cpuid.get_vendor_info().unwrap().as_str() == "GenuineIntel"); } raw-cpuid-11.6.0/examples/topology.rs000064400000000000000000000166341046102023000156560ustar 00000000000000//! An example that uses CPUID to determine the system topology. //! //! Intel Topology is a pretty complicated subject (unfortunately): //! https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ //! //! This example only compiles on x86 platforms. extern crate core_affinity; extern crate raw_cpuid; use raw_cpuid::{CpuId, ExtendedTopologyLevel, TopologyType}; use std::convert::TryInto; use std::thread; /// Runs CPU ID on every core in the system (to gather all APIC IDs). /// /// # Note /// This won't work on macOS, apparently there is no guarantee after setting the affinity /// that a thread will really execute on the pinned core. fn gather_all_xapic_ids() -> Vec { let core_ids = core_affinity::get_core_ids().unwrap(); // Create a thread for each active CPU core. core_ids .into_iter() .map(|id| { thread::spawn(move || { // Pin this thread to a single CPU core. core_affinity::set_for_current(id); // Do more work after this. let cpuid = CpuId::new(); cpuid .get_feature_info() .map_or_else(|| 0, |finfo| finfo.initial_local_apic_id()) }) .join() .unwrap_or(0) }) .collect::>() } /// Runs CPU ID on every core in the system (to gather all x2APIC IDs). /// /// # Note /// This won't work on macOS, apparently there is no guarantee after setting the affinity /// that a thread will really execute on the pinned core. fn gather_all_x2apic_ids() -> Vec { let core_ids = core_affinity::get_core_ids().unwrap(); // Create a thread for each active CPU core. core_ids .into_iter() .map(|id| { thread::spawn(move || { // Pin this thread to a single CPU core. core_affinity::set_for_current(id); // Do more work after this. let cpuid = CpuId::new(); cpuid.get_extended_topology_info().map_or_else( || 0, |mut topiter| topiter.next().as_ref().unwrap().x2apic_id(), ) }) .join() .unwrap_or(0) }) .collect::>() } fn enumerate_with_x2apic_ids() { let cpuid = CpuId::new(); let mut smt_x2apic_shift: u32 = 0; let mut core_x2apic_shift: u32 = 0; cpuid.get_extended_topology_info().map_or_else( || println!("No topology information available."), |topoiter| { let topology: Vec = topoiter.collect(); for topolevel in topology.iter() { match topolevel.level_type() { TopologyType::SMT => { smt_x2apic_shift = topolevel.shift_right_for_next_apic_id(); } TopologyType::Core => { core_x2apic_shift = topolevel.shift_right_for_next_apic_id(); } _ => panic!("Topology category not supported."), }; } }, ); println!("Enumeration of all cores in the system (with x2APIC IDs):"); let mut all_x2apic_ids: Vec = gather_all_x2apic_ids(); all_x2apic_ids.sort_unstable(); for x2apic_id in all_x2apic_ids { let smt_select_mask = !(u32::max_value() << smt_x2apic_shift); let core_select_mask = (!((u32::max_value()) << core_x2apic_shift)) ^ smt_select_mask; let pkg_select_mask = u32::max_value() << core_x2apic_shift; let smt_id = x2apic_id & smt_select_mask; let core_id = (x2apic_id & core_select_mask) >> smt_x2apic_shift; let pkg_id = (x2apic_id & pkg_select_mask) >> core_x2apic_shift; println!( "x2APIC#{} (pkg: {}, core: {}, smt: {})", x2apic_id, pkg_id, core_id, smt_id ); } } fn cpuid_bits_needed(count: u8) -> u8 { let mut mask: u8 = 0x80; let mut cnt: u8 = 8; while (cnt > 0) && ((mask & count) != mask) { mask >>= 1; cnt -= 1; } cnt } fn get_processor_limits() -> (u8, u8) { let cpuid = CpuId::new(); // This is for AMD processors: if let Some(info) = cpuid.get_processor_capacity_feature_info() { let max_logical_processor_ids = info.num_phys_threads(); let smt_max_cores_for_package = info.apic_id_size(); return ( max_logical_processor_ids.try_into().unwrap(), smt_max_cores_for_package.try_into().unwrap(), ); } // This is for Intel processors: else if let Some(cparams) = cpuid.get_cache_parameters() { let max_logical_processor_ids = cpuid .get_feature_info() .map_or_else(|| 1, |finfo| finfo.max_logical_processor_ids()); let mut smt_max_cores_for_package: u8 = 1; for (ecx, cache) in cparams.enumerate() { if ecx == 0 { smt_max_cores_for_package = cache.max_cores_for_package() as u8; } } return ( max_logical_processor_ids as u8, smt_max_cores_for_package as u8, ); } unreachable!("Example doesn't support this CPU") } fn enumerate_with_xapic_ids() { let (max_logical_processor_ids, smt_max_cores_for_package) = get_processor_limits(); let smt_mask_width: u8 = cpuid_bits_needed( (max_logical_processor_ids.next_power_of_two() / smt_max_cores_for_package) - 1, ); let smt_select_mask: u8 = !(u8::max_value() << smt_mask_width); let core_mask_width: u8 = cpuid_bits_needed(smt_max_cores_for_package - 1); let core_only_select_mask = (!(u8::max_value() << (core_mask_width + smt_mask_width))) ^ smt_select_mask; let pkg_select_mask = u8::max_value() << (core_mask_width + smt_mask_width); println!("Enumeration of all cores in the system (with APIC IDs):"); let mut all_xapic_ids: Vec = gather_all_xapic_ids(); all_xapic_ids.sort_unstable(); for xapic_id in all_xapic_ids { let smt_id = xapic_id & smt_select_mask; let core_id = (xapic_id & core_only_select_mask) >> smt_mask_width; let pkg_id = (xapic_id & pkg_select_mask) >> (core_mask_width + smt_mask_width); println!( "APIC#{} (pkg: {}, core: {}, smt: {})", xapic_id, pkg_id, core_id, smt_id ); } } fn main() { let cpuid = CpuId::new(); cpuid.get_processor_brand_string().map_or_else( || println!("CPU model identifier not available."), |pbs| println!("CPU Model is: {}", pbs.as_str()), ); cpuid.get_extended_topology_info().map_or_else( || println!("No topology information available."), |topoiter| { let mut topology: Vec = topoiter.collect(); topology.reverse(); for topolevel in topology.iter() { let typ = match topolevel.level_type() { TopologyType::SMT => "SMT-threads", TopologyType::Core => "cores", _ => panic!("Topology category not supported."), }; println!( "At level {} the CPU has: {} {}", topolevel.level_number(), topolevel.processors(), typ, ); } }, ); println!(); enumerate_with_xapic_ids(); println!(); enumerate_with_x2apic_ids(); } raw-cpuid-11.6.0/examples/tsc_frequency.rs000064400000000000000000000061321046102023000166440ustar 00000000000000//! An example that determines the time stamp counter frequency (RDTSC, RDTSCP). //! //! This example only compiles on x86 platforms. extern crate raw_cpuid; use std::time; const MHZ_TO_HZ: u64 = 1000000; const KHZ_TO_HZ: u64 = 1000; #[cfg(target_arch = "x86_64")] #[rustversion::nightly] use core::arch::x86_64::_rdtsc as rdtsc; #[cfg(target_arch = "x86")] #[rustversion::nightly] use core::arch::x86::_rdtsc as rdtsc; #[rustversion::not(nightly)] unsafe fn rdtsc() -> u64 { 0 } fn main() { let cpuid = raw_cpuid::CpuId::new(); let has_tsc = cpuid .get_feature_info() .map_or(false, |finfo| finfo.has_tsc()); let has_invariant_tsc = cpuid .get_advanced_power_mgmt_info() .map_or(false, |efinfo| efinfo.has_invariant_tsc()); let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| { if tinfo.nominal_frequency() != 0 { tinfo.tsc_frequency() } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 { // Skylake and Kabylake don't report the crystal clock, approximate with base frequency: cpuid .get_processor_frequency_info() .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ) .map(|cpu_base_freq_hz| { let crystal_hz = cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64; crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64 }) } else { None } }); if has_tsc { // Try to figure out TSC frequency with CPUID println!( "TSC Frequency is: {} ({})", match tsc_frequency_hz { Some(x) => format!("{} Hz", x.unwrap_or(0)), None => String::from("unknown"), }, if has_invariant_tsc { "invariant" } else { "TSC frequency varies with speed-stepping" } ); // Check if we run in a VM and the hypervisor can give us the TSC frequency cpuid.get_hypervisor_info().map(|hv| { hv.tsc_frequency().map(|tsc_khz| { let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ; println!( "Hypervisor reports TSC Frequency at: {} Hz", virtual_tsc_frequency_hz ); }) }); // Determine TSC frequency by measuring it (loop for a second, record ticks) let one_second = time::Duration::from_secs(1); let now = time::Instant::now(); let start = unsafe { rdtsc() }; if start > 0 { loop { if now.elapsed() >= one_second { break; } } let end = unsafe { rdtsc() }; println!( "Empirical measurement of TSC frequency was: {} Hz", (end - start) ); } else { // Don't have rdtsc on stable! } } else { println!("System does not have a TSC.") } } raw-cpuid-11.6.0/src/bin/cpuid.rs000064400000000000000000000023251046102023000146170ustar 00000000000000//! The cpuid binary accompanying the library. //! //! The cpuid binary only compiles/runs on x86 platforms. use std::str::FromStr; use clap::{Parser, ValueEnum}; use raw_cpuid::{CpuId, CpuIdReaderNative}; #[derive(ValueEnum, Clone)] enum OutputFormat { #[value(alias("raw"))] Raw, #[value(alias("cli"))] Cli, } impl FromStr for OutputFormat { type Err = &'static str; fn from_str(s: &str) -> Result { match s { "raw" => Ok(OutputFormat::Raw), "cli" => Ok(OutputFormat::Cli), _ => Err("no match"), } } } /// Prints information about the current x86 CPU to stdout using the cpuid instruction. #[derive(Parser)] #[clap(version = "10.2", author = "Gerd Zellweger ")] #[clap(disable_colored_help(true))] struct Opts { /// Configures the output format. #[clap(short, long, default_value = "cli")] format: OutputFormat, } fn main() { let opts: Opts = Opts::parse(); match opts.format { OutputFormat::Raw => raw_cpuid::display::raw(CpuIdReaderNative), OutputFormat::Cli => { let cpuid = CpuId::new(); raw_cpuid::display::markdown(cpuid); } }; } raw-cpuid-11.6.0/src/display.rs000064400000000000000000001775601046102023000144260ustar 00000000000000use std::fmt::Display; use crate::{ Associativity, CacheType, CpuIdResult, DatType, ExtendedRegisterStateLocation, SgxSectionInfo, SoCVendorBrand, TopologyType, }; use termimad::{minimad::TextTemplate, minimad::TextTemplateExpander, MadSkin}; pub fn raw(cpuid: R) { let _leafs_with_subleafs = &[0x04, 0x0d, 0x0f, 0x10, 0x12]; let max_leafs = cpuid.cpuid1(0x0).eax; for idx in 0..max_leafs { let res = cpuid.cpuid1(idx); println!("({:#x}, {:#x}) => {:?}", idx, 0x0, res); } let max_hypervisor_leafs = cpuid.cpuid1(0x4000_0000).eax; for idx in 0x4000_0000..max_hypervisor_leafs { println!("({:#x}, {:#x}) => {:?}", idx, 0x0, cpuid.cpuid1(idx)); } let max_extended_leafs = cpuid.cpuid1(0x8000_0000).eax; for idx in 0x8000_0000..max_extended_leafs { println!("({:#x}, {:#x}) => {:?}", idx, 0x0, cpuid.cpuid1(idx)); } } fn table2(skin: &MadSkin, attrs: &[(&str, String)]) { let table_template = TextTemplate::from( r#" |-:|-:| ${feature-rows |**${attr-name}**|${attr-avail}| } |-|-| "#, ); fn make_table_display<'a, 'b>( text_template: &'a TextTemplate<'b>, attrs: &'b [(&'b str, String)], ) -> TextTemplateExpander<'a, 'b> { let mut expander = text_template.expander(); for (attr, desc) in attrs { expander .sub("feature-rows") .set("attr-name", attr) .set("attr-avail", desc); } expander } let table = make_table_display(&table_template, &attrs); skin.print_expander(table); } fn table3(skin: &MadSkin, attrs: &[(&'static str, &'static str, String)]) { let table_template3 = TextTemplate::from( r#" |:-|-:|-:| ${feature-rows |**${category-name}**|**${attr-name}**|${attr-avail}| } |-|-| "#, ); fn make_table_display3<'a, 'b>( text_template: &'a TextTemplate<'b>, attrs: &'b [(&'b str, &'b str, String)], ) -> TextTemplateExpander<'a, 'b> { let mut expander = text_template.expander(); for (cat, attr, desc) in attrs { expander .sub("feature-rows") .set("category-name", cat) .set("attr-name", attr) .set("attr-avail", desc); } expander } let table = make_table_display3(&table_template3, &attrs); skin.print_expander(table); } fn print_title_line(skin: &MadSkin, title: &str, attr: Option<&str>) { if let Some(opt) = attr { skin.print_text(format!("## {} = \"{}\"\n", title, opt).as_str()); } else { skin.print_text(format!("## {}\n", title).as_str()); } } fn print_title_attr(skin: &MadSkin, title: &str, attr: &str) { print_title_line(skin, title, Some(attr)); } fn print_title(skin: &MadSkin, title: &str) { print_title_line(skin, title, None) } fn print_subtitle(skin: &MadSkin, title: &str) { skin.print_text(format!("### {}\n", title).as_str()); } fn print_attr(skin: &MadSkin, name: T, attr: A) { skin.print_text(format!("{} = {}", name, attr).as_str()); } fn print_cpuid_result(skin: &MadSkin, name: T, attr: CpuIdResult) { skin.print_text( format!( "{}: eax = {:#x} ebx = {:#x} ecx = {:#x} edx = {:#x}", name, attr.eax, attr.ebx, attr.ecx, attr.edx, ) .as_str(), ); } fn bool_repr(x: bool) -> String { if x { "āœ…".to_string() } else { "āŒ".to_string() } } trait RowGen { fn fmt(attr: &Self) -> String; fn tuple<'a>(t: &'a str, attr: Self) -> (&'a str, String) where Self: Sized, { (t, RowGen::fmt(&attr)) } fn triple<'a>(c: &'a str, t: &'a str, attr: Self) -> (&'a str, &'a str, String) where Self: Sized, { (c, t, RowGen::fmt(&attr)) } } impl RowGen for bool { fn fmt(attr: &Self) -> String { bool_repr(*attr) } } impl RowGen for u64 { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for usize { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for u32 { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for u16 { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for u8 { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for String { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for Associativity { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for CacheType { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for TopologyType { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for ExtendedRegisterStateLocation { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for DatType { fn fmt(attr: &Self) -> String { format!("{}", attr) } } impl RowGen for Option { fn fmt(attr: &Self) -> String { format!( "{}", attr.as_ref() .map(|v| v.as_str().to_string()) .unwrap_or(String::from("")) ) } } pub fn markdown(cpuid: crate::CpuId) { let skin = MadSkin::default(); skin.print_text("# CpuId\n"); if let Some(info) = cpuid.get_vendor_info() { print_title_attr(&skin, "vendor_id (0x00)", info.as_str()); } if let Some(info) = cpuid.get_feature_info() { print_title(&skin, "version information (1/eax):"); table2( &skin, &[ RowGen::tuple("base family", info.base_family_id()), RowGen::tuple("base model", info.base_model_id()), RowGen::tuple("stepping", info.stepping_id()), RowGen::tuple("extended family", info.extended_family_id()), RowGen::tuple("extended model", info.extended_model_id()), RowGen::tuple("family", info.family_id()), RowGen::tuple("model", info.model_id()), ], ); print_title(&skin, "miscellaneous (1/ebx):"); table2( &skin, &[ RowGen::tuple("processor APIC physical id", info.initial_local_apic_id()), RowGen::tuple("max. cpus", info.max_logical_processor_ids()), RowGen::tuple("CLFLUSH line size", info.cflush_cache_line_size()), RowGen::tuple("brand index", info.brand_index()), ], ); print_title(&skin, "feature information (1/edx):"); table2( &skin, &[ RowGen::tuple("fpu", info.has_fpu()), RowGen::tuple("vme", info.has_vme()), RowGen::tuple("de", info.has_de()), RowGen::tuple("pse", info.has_pse()), RowGen::tuple("tsc", info.has_tsc()), RowGen::tuple("msr", info.has_msr()), RowGen::tuple("pae", info.has_pae()), RowGen::tuple("mce", info.has_mce()), RowGen::tuple("cmpxchg8b", info.has_cmpxchg8b()), RowGen::tuple("apic", info.has_apic()), RowGen::tuple("sysenter_sysexit", info.has_sysenter_sysexit()), RowGen::tuple("mtrr", info.has_mtrr()), RowGen::tuple("pge", info.has_pge()), RowGen::tuple("mca", info.has_mca()), RowGen::tuple("cmov", info.has_cmov()), RowGen::tuple("pat", info.has_pat()), RowGen::tuple("pse36", info.has_pse36()), RowGen::tuple("psn", info.has_psn()), RowGen::tuple("clflush", info.has_clflush()), RowGen::tuple("ds", info.has_ds()), RowGen::tuple("acpi", info.has_acpi()), RowGen::tuple("mmx", info.has_mmx()), RowGen::tuple("fxsave_fxstor", info.has_fxsave_fxstor()), RowGen::tuple("sse", info.has_sse()), RowGen::tuple("sse2", info.has_sse2()), RowGen::tuple("ss", info.has_ss()), RowGen::tuple("htt", info.has_htt()), RowGen::tuple("tm", info.has_tm()), RowGen::tuple("pbe", info.has_pbe()), ], ); print_title(&skin, "feature information (1/ecx):"); table2( &skin, &[ RowGen::tuple("sse3", info.has_sse3()), RowGen::tuple("pclmulqdq", info.has_pclmulqdq()), RowGen::tuple("ds_area", info.has_ds_area()), RowGen::tuple("monitor_mwait", info.has_monitor_mwait()), RowGen::tuple("cpl", info.has_cpl()), RowGen::tuple("vmx", info.has_vmx()), RowGen::tuple("smx", info.has_smx()), RowGen::tuple("eist", info.has_eist()), RowGen::tuple("tm2", info.has_tm2()), RowGen::tuple("ssse3", info.has_ssse3()), RowGen::tuple("cnxtid", info.has_cnxtid()), RowGen::tuple("fma", info.has_fma()), RowGen::tuple("cmpxchg16b", info.has_cmpxchg16b()), RowGen::tuple("pdcm", info.has_pdcm()), RowGen::tuple("pcid", info.has_pcid()), RowGen::tuple("dca", info.has_dca()), RowGen::tuple("sse41", info.has_sse41()), RowGen::tuple("sse42", info.has_sse42()), RowGen::tuple("x2apic", info.has_x2apic()), RowGen::tuple("movbe", info.has_movbe()), RowGen::tuple("popcnt", info.has_popcnt()), RowGen::tuple("tsc_deadline", info.has_tsc_deadline()), RowGen::tuple("aesni", info.has_aesni()), RowGen::tuple("xsave", info.has_xsave()), RowGen::tuple("oxsave", info.has_oxsave()), RowGen::tuple("avx", info.has_avx()), RowGen::tuple("f16c", info.has_f16c()), RowGen::tuple("rdrand", info.has_rdrand()), RowGen::tuple("hypervisor", info.has_hypervisor()), ], ); } if let Some(info) = cpuid.get_cache_info() { print_title(&skin, "Cache and TLB information (0x02):"); let nums: Vec = info .clone() .map(|cache| format!("{:#x}", cache.num)) .collect(); let attrs: Vec<(&str, String)> = info .zip(nums.iter()) .map(|(cache, n)| RowGen::tuple(n, cache.desc().to_string())) .collect(); table2(&skin, &attrs); } if let Some(info) = cpuid.get_processor_serial() { print_title_attr( &skin, "processor serial number (0x03)", format!( "{:0>8x}-{:0>8x}-{:0>8x}", info.serial_upper(), info.serial_middle(), info.serial_lower() ) .as_str(), ); } if let Some(iter) = cpuid.get_cache_parameters() { print_title(&skin, "deterministic cache parameters (0x04):"); for cache in iter { print_subtitle(&skin, format!("L{} Cache:", cache.level()).as_str()); let size = (cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets()) as u64; table2( &skin, &[ RowGen::tuple("cache type", cache.cache_type()), RowGen::tuple("cache level", cache.level()), RowGen::tuple( "self-initializing cache level", cache.is_self_initializing(), ), RowGen::tuple("fully associative cache", cache.is_fully_associative()), RowGen::tuple("threads sharing this cache", cache.max_cores_for_cache()), RowGen::tuple("processor cores on this die", cache.max_cores_for_package()), RowGen::tuple("system coherency line size", cache.coherency_line_size()), RowGen::tuple("physical line partitions", cache.physical_line_partitions()), RowGen::tuple("ways of associativity", cache.associativity()), RowGen::tuple( "WBINVD/INVD acts on lower caches", cache.is_write_back_invalidate(), ), RowGen::tuple("inclusive to lower caches", cache.is_inclusive()), RowGen::tuple("complex cache indexing", cache.has_complex_indexing()), RowGen::tuple("number of sets", cache.sets()), RowGen::tuple("(size synth.)", size), ], ); } } if let Some(info) = cpuid.get_monitor_mwait_info() { print_title(&skin, "MONITOR/MWAIT (0x05):"); table2( &skin, &[ RowGen::tuple("smallest monitor-line size", info.smallest_monitor_line()), RowGen::tuple("largest monitor-line size", info.largest_monitor_line()), RowGen::tuple("MONITOR/MWAIT exts", info.extensions_supported()), RowGen::tuple( "Interrupts as break-event for MWAIT", info.interrupts_as_break_event(), ), ], ); skin.print_text("number of CX sub C-states using MWAIT:\n"); let cstate_table = TextTemplate::from( r#" | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | |**C0**|**C1**|**C2**|**C3**|**C4**|**C5**|**C6**|**C7**| | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | |${c0}|${c1}|${c2}|${c3}|${c4}|${c5}|${c6}|${c7}| | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | "#, ); let c0 = format!("{}", info.supported_c0_states()); let c1 = format!("{}", info.supported_c1_states()); let c2 = format!("{}", info.supported_c2_states()); let c3 = format!("{}", info.supported_c3_states()); let c4 = format!("{}", info.supported_c4_states()); let c5 = format!("{}", info.supported_c5_states()); let c6 = format!("{}", info.supported_c6_states()); let c7 = format!("{}", info.supported_c7_states()); let mut ctbl = cstate_table.expander(); ctbl.set("c0", c0.as_str()); ctbl.set("c1", c1.as_str()); ctbl.set("c2", c2.as_str()); ctbl.set("c3", c3.as_str()); ctbl.set("c4", c4.as_str()); ctbl.set("c5", c5.as_str()); ctbl.set("c6", c6.as_str()); ctbl.set("c7", c7.as_str()); skin.print_expander(ctbl); } if let Some(info) = cpuid.get_thermal_power_info() { print_title(&skin, "Thermal and Power Management Features (0x06):"); table2( &skin, &[ RowGen::tuple("digital thermometer", info.has_dts()), RowGen::tuple("Intel Turbo Boost Technology", info.has_turbo_boost()), RowGen::tuple("ARAT always running APIC timer", info.has_arat()), RowGen::tuple("PLN power limit notification", info.has_pln()), RowGen::tuple("ECMD extended clock modulation duty", info.has_ecmd()), RowGen::tuple("PTM package thermal management", info.has_ptm()), RowGen::tuple("HWP base registers", info.has_hwp()), RowGen::tuple("HWP notification", info.has_hwp_notification()), RowGen::tuple("HWP activity window", info.has_hwp_activity_window()), RowGen::tuple( "HWP energy performance preference", info.has_hwp_energy_performance_preference(), ), RowGen::tuple( "HWP package level request", info.has_hwp_package_level_request(), ), RowGen::tuple("HDC base registers", info.has_hdc()), RowGen::tuple( "Intel Turbo Boost Max Technology 3.0", info.has_turbo_boost3(), ), RowGen::tuple("HWP capabilities", info.has_hwp_capabilities()), RowGen::tuple("HWP PECI override", info.has_hwp_peci_override()), RowGen::tuple("flexible HWP", info.has_flexible_hwp()), RowGen::tuple( "IA32_HWP_REQUEST MSR fast access mode", info.has_hwp_fast_access_mode(), ), RowGen::tuple( "ignoring idle logical processor HWP req", info.has_ignore_idle_processor_hwp_request(), ), RowGen::tuple("digital thermometer threshold", info.dts_irq_threshold()), RowGen::tuple( "hardware coordination feedback", info.has_hw_coord_feedback(), ), RowGen::tuple( "performance-energy bias capability", info.has_energy_bias_pref(), ), ], ); } if let Some(info) = cpuid.get_extended_feature_info() { print_title(&skin, "Extended feature flags (0x07):"); table2( &skin, &[ RowGen::tuple("FSGSBASE", info.has_fsgsbase()), RowGen::tuple("IA32_TSC_ADJUST MSR", info.has_tsc_adjust_msr()), RowGen::tuple("SGX: Software Guard Extensions", info.has_sgx()), RowGen::tuple("BMI1", info.has_bmi1()), RowGen::tuple("HLE hardware lock elision", info.has_hle()), RowGen::tuple("AVX2: advanced vector extensions 2", info.has_avx2()), RowGen::tuple("FDP_EXCPTN_ONLY", info.has_fdp()), RowGen::tuple("SMEP supervisor mode exec protection", info.has_smep()), RowGen::tuple("BMI2 instructions", info.has_bmi2()), RowGen::tuple("enhanced REP MOVSB/STOSB", info.has_rep_movsb_stosb()), RowGen::tuple("INVPCID instruction", info.has_invpcid()), RowGen::tuple("RTM: restricted transactional memory", info.has_rtm()), RowGen::tuple("RDT-CMT/PQoS cache monitoring", info.has_rdtm()), RowGen::tuple("deprecated FPU CS/DS", info.has_fpu_cs_ds_deprecated()), RowGen::tuple("MPX: intel memory protection extensions", info.has_mpx()), RowGen::tuple("RDT-CAT/PQE cache allocation", info.has_rdta()), RowGen::tuple( "AVX512F: AVX-512 foundation instructions", info.has_avx512f(), ), RowGen::tuple("AVX512-4NNIW: 4NNIW instructions", info.has_avx512_4vnniw()), RowGen::tuple( "AVX512-4FMAPS: 4FMAPS instructions", info.has_avx512_4fmaps(), ), RowGen::tuple( "AVX512-VP2INTERSECT: VP2INTERSECT instructions", info.has_avx512_vp2intersect(), ), RowGen::tuple("AMX_BF16: AMX_BF16 instructions", info.has_amx_bf16()), RowGen::tuple( "AVX512_FP16: AVX512_FP16 instructions", info.has_avx512_fp16(), ), RowGen::tuple("AMX_TILE: Tile Architecture support", info.has_amx_tile()), RowGen::tuple( "AMX_INT8: Tile Computational Operation on 8-bit integers", info.has_amx_tile(), ), RowGen::tuple( "AVX512DQ: double & quadword instructions", info.has_avx512dq(), ), RowGen::tuple("RDSEED instruction", info.has_rdseed()), RowGen::tuple("ADX instructions", info.has_adx()), RowGen::tuple("SMAP: supervisor mode access prevention", info.has_smap()), RowGen::tuple("AVX512IFMA: fused multiply add", info.has_avx512_ifma()), RowGen::tuple("CLFLUSHOPT instruction", info.has_clflushopt()), RowGen::tuple("CLWB instruction", info.has_clwb()), RowGen::tuple("Intel processor trace", info.has_processor_trace()), RowGen::tuple("AVX512PF: prefetch instructions", info.has_avx512pf()), RowGen::tuple( "AVX512ER: exponent & reciprocal instrs", info.has_avx512er(), ), RowGen::tuple("AVX512CD: conflict detection instrs", info.has_avx512cd()), RowGen::tuple("SHA instructions", info.has_sha()), RowGen::tuple("AVX512BW: byte & word instructions", info.has_avx512bw()), RowGen::tuple("AVX512VL: vector length", info.has_avx512vl()), RowGen::tuple("PREFETCHWT1", info.has_prefetchwt1()), RowGen::tuple("UMIP: user-mode instruction prevention", info.has_umip()), RowGen::tuple("PKU protection keys for user-mode", info.has_pku()), RowGen::tuple("OSPKE CR4.PKE and RDPKRU/WRPKRU", info.has_ospke()), RowGen::tuple( "AVX512VNNI: vector neural network instructions", info.has_avx512vnni(), ), RowGen::tuple( "BNDLDX/BNDSTX MAWAU value in 64-bit mode", info.mawau_value(), ), RowGen::tuple("RDPID: read processor ID", info.has_rdpid()), RowGen::tuple("SGX_LC: SGX launch config", info.has_sgx_lc()), RowGen::tuple( "AVX_VNNI: AVX vector neural network instructions", info.has_avx_vnni(), ), RowGen::tuple( "AVX512_BF16: AVX512 BF16 instructions", info.has_avx512_bf16(), ), RowGen::tuple("FZRMK: fast zero-length REP MOVSB256", info.has_fzrm()), RowGen::tuple("FSRM: fast short REP STOSB", info.has_fsrs()), RowGen::tuple("FSRCRS: fast short REP CMPSB, REP SCASB", info.has_fsrcrs()), RowGen::tuple("HRESET: HRESET instruction", info.has_hreset()), RowGen::tuple("CET_SSS: CET_SSS support", info.has_cet_sss()), ], ); } if let Some(info) = cpuid.get_direct_cache_access_info() { print_title(&skin, "Direct Cache Access Parameters (0x09):"); print_attr(&skin, "PLATFORM_DCA_CAP MSR bits", info.get_dca_cap_value()); } if let Some(info) = cpuid.get_performance_monitoring_info() { print_title(&skin, "Architecture Performance Monitoring Features (0x0a)"); print_subtitle(&skin, "Monitoring Hardware Info (0x0a/{eax, edx}):"); table2( &skin, &[ RowGen::tuple("version ID", info.version_id()), RowGen::tuple( "number of counters per HW thread", info.number_of_counters(), ), RowGen::tuple("bit width of counter", info.counter_bit_width()), RowGen::tuple("length of EBX bit vector", info.ebx_length()), RowGen::tuple("number of fixed counters", info.fixed_function_counters()), RowGen::tuple( "bit width of fixed counters", info.fixed_function_counters_bit_width(), ), RowGen::tuple("anythread deprecation", info.has_any_thread_deprecation()), ], ); print_subtitle(&skin, "Monitoring Hardware Features (0x0a/ebx):"); table2( &skin, &[ RowGen::tuple( "core cycle event not available", info.is_core_cyc_ev_unavailable(), ), RowGen::tuple( "instruction retired event not available", info.is_inst_ret_ev_unavailable(), ), RowGen::tuple( "reference cycles event not available", info.is_ref_cycle_ev_unavailable(), ), RowGen::tuple( "last-level cache ref event not available", info.is_cache_ref_ev_unavailable(), ), RowGen::tuple( "last-level cache miss event not avail", info.is_ll_cache_miss_ev_unavailable(), ), RowGen::tuple( "branch inst retired event not available", info.is_branch_inst_ret_ev_unavailable(), ), RowGen::tuple( "branch mispred retired event not available", info.is_branch_midpred_ev_unavailable(), ), ], ); } if let Some(info) = cpuid.get_extended_topology_info() { print_title(&skin, "x2APIC features / processor topology (0x0b):"); for level in info { print_subtitle(&skin, format!("level {}:", level.level_number()).as_str()); table2( &skin, &[ RowGen::tuple("level type", level.level_type()), RowGen::tuple("bit width of level", level.shift_right_for_next_apic_id()), RowGen::tuple("number of logical processors at level", level.processors()), RowGen::tuple("x2apic id of current processor", level.x2apic_id()), ], ); } } if let Some(info) = cpuid.get_extended_state_info() { print_title(&skin, "Extended Register State (0x0d/0):"); print_subtitle(&skin, "XCR0/IA32_XSS supported states:"); table3( &skin, &[ RowGen::triple("XCR0", "x87", info.xcr0_supports_legacy_x87()), RowGen::triple("XCR0", "SSE state", info.xcr0_supports_sse_128()), RowGen::triple("XCR0", "AVX state", info.xcr0_supports_avx_256()), RowGen::triple("XCR0", "MPX BNDREGS", info.xcr0_supports_mpx_bndregs()), RowGen::triple("XCR0", "MPX BNDCSR", info.xcr0_supports_mpx_bndcsr()), RowGen::triple("XCR0", "AVX-512 opmask", info.xcr0_supports_avx512_opmask()), RowGen::triple( "XCR0", "AVX-512 ZMM_Hi256", info.xcr0_supports_avx512_zmm_hi256(), ), RowGen::triple( "XCR0", "AVX-512 Hi16_ZMM", info.xcr0_supports_avx512_zmm_hi16(), ), RowGen::triple("IA32_XSS", "PT", info.ia32_xss_supports_pt()), RowGen::triple("XCR0", "PKRU", info.xcr0_supports_pkru()), //("XCR0", "CET_U state", xxx), //("XCR0", "CET_S state", xxx), RowGen::triple("IA32_XSS", "HDC", info.ia32_xss_supports_hdc()), ], ); table2( &skin, &[ RowGen::tuple( "bytes required by fields in XCR0", info.xsave_area_size_enabled_features(), ), RowGen::tuple( "bytes required by XSAVE/XRSTOR area", info.xsave_area_size_supported_features(), ), ], ); print_subtitle(&skin, "XSAVE features (0x0d/1):"); table2( &skin, &[ RowGen::tuple("XSAVEOPT instruction", info.has_xsaveopt()), RowGen::tuple("XSAVEC instruction", info.has_xsavec()), RowGen::tuple("XGETBV instruction", info.has_xgetbv()), RowGen::tuple("XSAVES/XRSTORS instructions", info.has_xsaves_xrstors()), RowGen::tuple("SAVE area size [Bytes]", info.xsave_size()), ], ); for state in info.iter() { print_subtitle( &skin, format!("{} features (0x0d/{}):", state.register(), state.subleaf).as_str(), ); table2( &skin, &[ RowGen::tuple("save state size [Bytes]", state.size()), RowGen::tuple("save state byte offset", state.offset()), RowGen::tuple("supported in IA32_XSS or XCR0", state.location()), RowGen::tuple( "64-byte alignment in compacted XSAVE", state.is_compacted_format(), ), ], ); } } if let Some(info) = cpuid.get_rdt_monitoring_info() { print_title( &skin, "Quality of Service Monitoring Resource Type (0x0f/0):", ); table2( &skin, &[ RowGen::tuple("Maximum range of RMID", info.rmid_range()), RowGen::tuple("L3 cache QoS monitoring", info.has_l3_monitoring()), ], ); if let Some(rmid) = info.l3_monitoring() { print_subtitle(&skin, "L3 Cache Quality of Service Monitoring (0x0f/1):"); table2( &skin, &[ RowGen::tuple( "Conversion factor from IA32_QM_CTR to bytes", rmid.conversion_factor(), ), RowGen::tuple("Maximum range of RMID", rmid.maximum_rmid_range()), RowGen::tuple("L3 occupancy monitoring", rmid.has_occupancy_monitoring()), RowGen::tuple( "L3 total bandwidth monitoring", rmid.has_total_bandwidth_monitoring(), ), RowGen::tuple( "L3 local bandwidth monitoring", rmid.has_local_bandwidth_monitoring(), ), ], ); } } if let Some(info) = cpuid.get_rdt_allocation_info() { print_title(&skin, "Resource Director Technology Allocation (0x10/0)"); table2( &skin, &[ RowGen::tuple("L3 cache allocation technology", info.has_l3_cat()), RowGen::tuple("L2 cache allocation technology", info.has_l2_cat()), RowGen::tuple( "memory bandwidth allocation", info.has_memory_bandwidth_allocation(), ), ], ); if let Some(l3_cat) = info.l3_cat() { print_subtitle(&skin, "L3 Cache Allocation Technology (0x10/1):"); table2( &skin, &[ RowGen::tuple("length of capacity bit mask", l3_cat.capacity_mask_length()), RowGen::tuple( "Bit-granular map of isolation/contention", l3_cat.isolation_bitmap(), ), RowGen::tuple( "code and data prioritization", l3_cat.has_code_data_prioritization(), ), RowGen::tuple("highest COS number", l3_cat.highest_cos()), ], ); } if let Some(l2_cat) = info.l2_cat() { print_subtitle(&skin, "L2 Cache Allocation Technology (0x10/2):"); table2( &skin, &[ RowGen::tuple("length of capacity bit mask", l2_cat.capacity_mask_length()), RowGen::tuple( "Bit-granular map of isolation/contention", l2_cat.isolation_bitmap(), ), RowGen::tuple("highest COS number", l2_cat.highest_cos()), ], ); } if let Some(mem) = info.memory_bandwidth_allocation() { print_subtitle(&skin, "Memory Bandwidth Allocation (0x10/3):"); table2( &skin, &[ RowGen::tuple("maximum throttling value", mem.max_hba_throttling()), RowGen::tuple("delay values are linear", mem.has_linear_response_delay()), RowGen::tuple("highest COS number", mem.highest_cos()), ], ); } } if let Some(info) = cpuid.get_sgx_info() { print_title(&skin, "SGX - Software Guard Extensions (0x12/{0,1}):"); table2( &skin, &[ RowGen::tuple("SGX1", info.has_sgx1()), RowGen::tuple("SGX2", info.has_sgx2()), RowGen::tuple( "SGX ENCLV E*VIRTCHILD, ESETCONTEXT", info.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(), ), RowGen::tuple( "SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC", info.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(), ), RowGen::tuple("MISCSELECT", info.miscselect()), RowGen::tuple( "MaxEnclaveSize_Not64 (log2)", info.max_enclave_size_non_64bit(), ), RowGen::tuple("MaxEnclaveSize_64 (log2)", info.max_enclave_size_64bit()), ], ); for (idx, leaf) in info.iter().enumerate() { let SgxSectionInfo::Epc(section) = leaf; print_subtitle( &skin, format!("Enclave Page Cache (0x12/{})", idx + 2).as_str(), ); table2( &skin, &[ RowGen::tuple("physical base address", section.physical_base()), RowGen::tuple("size", section.size()), ], ); } } if let Some(info) = cpuid.get_processor_trace_info() { print_title(&skin, "Intel Processor Trace (0x14):"); table2( &skin, &[ RowGen::tuple( "IA32_RTIT_CR3_MATCH is accessible", info.has_rtit_cr3_match(), ), RowGen::tuple( "configurable PSB & cycle-accurate", info.has_configurable_psb_and_cycle_accurate_mode(), ), RowGen::tuple( "IP & TraceStop filtering; PT preserve", info.has_ip_tracestop_filtering(), ), RowGen::tuple( "MTC timing packet; suppress COFI-based", info.has_mtc_timing_packet_coefi_suppression(), ), RowGen::tuple("PTWRITE", info.has_ptwrite()), RowGen::tuple("power event trace", info.has_power_event_trace()), RowGen::tuple("ToPA output scheme", info.has_topa()), RowGen::tuple( "ToPA can hold many output entries", info.has_topa_maximum_entries(), ), RowGen::tuple( "single-range output scheme support", info.has_single_range_output_scheme(), ), RowGen::tuple( "output to trace transport", info.has_trace_transport_subsystem(), ), RowGen::tuple( "IP payloads have LIP values & CS", info.has_lip_with_cs_base(), ), RowGen::tuple( "configurable address ranges", info.configurable_address_ranges(), ), RowGen::tuple( "supported MTC periods bitmask", info.supported_mtc_period_encodings(), ), RowGen::tuple( "supported cycle threshold bitmask", info.supported_cycle_threshold_value_encodings(), ), RowGen::tuple( "supported config PSB freq bitmask", info.supported_psb_frequency_encodings(), ), ], ); } if let Some(info) = cpuid.get_tsc_info() { print_title( &skin, "Time Stamp Counter/Core Crystal Clock Information (0x15):", ); table2( &skin, &[ RowGen::tuple( "TSC/clock ratio", format!("{} / {}", info.numerator(), info.denominator()), ), RowGen::tuple("nominal core crystal clock", info.nominal_frequency()), ], ); } if let Some(info) = cpuid.get_processor_frequency_info() { print_title(&skin, "Processor Frequency Information (0x16):"); table2( &skin, &[ RowGen::tuple("Core Base Frequency (MHz)", info.processor_base_frequency()), RowGen::tuple( "Core Maximum Frequency (MHz)", info.processor_max_frequency(), ), RowGen::tuple("Bus (Reference) Frequency (MHz)", info.bus_frequency()), ], ); } if let Some(dat_iter) = cpuid.get_deterministic_address_translation_info() { for (idx, info) in dat_iter.enumerate() { print_title( &skin, format!( "Deterministic Address Translation Structure (0x18/{}):", idx ) .as_str(), ); table2( &skin, &[ RowGen::tuple("number of sets", info.sets()), RowGen::tuple("4 KiB page size entries", info.has_4k_entries()), RowGen::tuple("2 MiB page size entries", info.has_2mb_entries()), RowGen::tuple("4 MiB page size entries", info.has_4mb_entries()), RowGen::tuple("1 GiB page size entries", info.has_1gb_entries()), RowGen::tuple("partitioning", info.partitioning()), RowGen::tuple("ways of associativity", info.ways()), RowGen::tuple("translation cache type", info.cache_type()), RowGen::tuple("translation cache level", info.cache_level()), RowGen::tuple("fully associative", info.is_fully_associative()), RowGen::tuple( "maximum number of addressible IDs", info.max_addressable_ids(), ), RowGen::tuple( "maximum number of addressible IDs", info.max_addressable_ids(), ), ], ); } } if let Some(info) = cpuid.get_soc_vendor_info() { print_title(&skin, "System-on-Chip (SoC) Vendor Info (0x17):"); table2( &skin, &[ RowGen::tuple("Vendor ID", info.get_soc_vendor_id()), RowGen::tuple("Project ID", info.get_project_id()), RowGen::tuple("Stepping ID", info.get_stepping_id()), RowGen::tuple("Vendor Brand", info.get_vendor_brand()), ], ); if let Some(iter) = info.get_vendor_attributes() { for (idx, attr) in iter.enumerate() { print_cpuid_result(&skin, format!("0x17 {:#x}", idx + 4), attr); } } } if let Some(info) = cpuid.get_processor_brand_string() { print_attr( &skin, "Processor Brand String", format!("\"**{}**\"", info.as_str()), ); } if let Some(info) = cpuid.get_l1_cache_and_tlb_info() { print_title(&skin, "L1 TLB 2/4 MiB entries (0x8000_0005/eax):"); table2( &skin, &[ RowGen::tuple("iTLB #entries", info.itlb_2m_4m_size()), RowGen::tuple("iTLB associativity", info.itlb_2m_4m_associativity()), RowGen::tuple("dTLB #entries", info.dtlb_2m_4m_size()), RowGen::tuple("dTLB associativity", info.dtlb_2m_4m_associativity()), ], ); print_title(&skin, "L1 TLB 4 KiB entries (0x8000_0005/ebx):"); table2( &skin, &[ RowGen::tuple("iTLB #entries", info.itlb_4k_size()), RowGen::tuple("iTLB associativity", info.itlb_4k_associativity()), RowGen::tuple("dTLB #entries", info.dtlb_4k_size()), RowGen::tuple("dTLB associativity", info.dtlb_4k_associativity()), ], ); print_title(&skin, "L1 dCache (0x8000_0005/ecx):"); table2( &skin, &[ RowGen::tuple("line size [Bytes]", info.dcache_line_size()), RowGen::tuple("lines per tag", info.dcache_lines_per_tag()), RowGen::tuple("associativity", info.dcache_associativity()), RowGen::tuple("size [KiB]", info.dcache_size()), ], ); print_title(&skin, "L1 iCache (0x8000_0005/edx):"); table2( &skin, &[ RowGen::tuple("line size [Bytes]", info.icache_line_size()), RowGen::tuple("lines per tag", info.icache_lines_per_tag()), RowGen::tuple("associativity", info.icache_associativity()), RowGen::tuple("size [KiB]", info.icache_size()), ], ); } if let Some(info) = cpuid.get_l2_l3_cache_and_tlb_info() { print_title(&skin, "L2 TLB 2/4 MiB entries (0x8000_0006/eax):"); table2( &skin, &[ RowGen::tuple("iTLB #entries", info.itlb_2m_4m_size()), RowGen::tuple("iTLB associativity", info.itlb_2m_4m_associativity()), RowGen::tuple("dTLB #entries", info.dtlb_2m_4m_size()), RowGen::tuple("dTLB associativity", info.dtlb_2m_4m_associativity()), ], ); print_title(&skin, "L2 TLB 4 KiB entries (0x8000_0006/ebx):"); table2( &skin, &[ RowGen::tuple("iTLB #entries", info.itlb_4k_size()), RowGen::tuple("iTLB associativity", info.itlb_4k_associativity()), RowGen::tuple("dTLB #entries", info.dtlb_4k_size()), RowGen::tuple("dTLB associativity", info.dtlb_4k_associativity()), ], ); print_title(&skin, "L2 Cache (0x8000_0006/ecx):"); table2( &skin, &[ RowGen::tuple("line size [Bytes]", info.l2cache_line_size()), RowGen::tuple("lines per tag", info.l2cache_lines_per_tag()), RowGen::tuple("associativity", info.l2cache_associativity()), RowGen::tuple("size [KiB]", info.l2cache_size()), ], ); print_title(&skin, "L3 Cache (0x8000_0006/edx):"); table2( &skin, &[ RowGen::tuple("line size [Bytes]", info.l3cache_line_size()), RowGen::tuple("lines per tag", info.l3cache_lines_per_tag()), RowGen::tuple("associativity", info.l3cache_associativity()), RowGen::tuple("size [KiB]", info.l3cache_size() as usize * 512), ], ); } if let Some(info) = cpuid.get_advanced_power_mgmt_info() { print_title(&skin, "RAS Capability (0x8000_0007/ebx):"); table2( &skin, &[ RowGen::tuple("MCA overflow recovery", info.has_mca_overflow_recovery()), RowGen::tuple("SUCCOR", info.has_succor()), RowGen::tuple("HWA: hardware assert", info.has_hwa()), ], ); print_title(&skin, "Advanced Power Management (0x8000_0007/ecx):"); print_attr( &skin, "Ratio of Compute Unit Power Acc. sample period to TSC", info.cpu_pwr_sample_time_ratio(), ); print_title(&skin, "Advanced Power Management (0x8000_0007/edx):"); table2( &skin, &[ RowGen::tuple("TS: temperature sensing diode", info.has_ts()), RowGen::tuple("FID: frequency ID control", info.has_freq_id_ctrl()), RowGen::tuple("VID: voltage ID control", info.has_volt_id_ctrl()), RowGen::tuple("TTP: thermal trip", info.has_thermtrip()), RowGen::tuple("TM: thermal monitor", info.has_tm()), RowGen::tuple("100 MHz multiplier control", info.has_100mhz_steps()), RowGen::tuple("hardware P-State control", info.has_hw_pstate()), RowGen::tuple("Invariant TSC", info.has_invariant_tsc()), RowGen::tuple("CPB: core performance boost", info.has_cpb()), RowGen::tuple( "read-only effective frequency interface", info.has_ro_effective_freq_iface(), ), RowGen::tuple("processor feedback interface", info.has_feedback_iface()), RowGen::tuple("APM power reporting", info.has_power_reporting_iface()), ], ); } if let Some(info) = cpuid.get_processor_capacity_feature_info() { print_title( &skin, "Physical Address and Linear Address Size (0x8000_0008/eax):", ); table2( &skin, &[ RowGen::tuple( "maximum physical address [Bits]", info.physical_address_bits(), ), RowGen::tuple( "maximum linear (virtual) address [Bits]", info.linear_address_bits(), ), RowGen::tuple( "maximum guest physical address [Bits]", info.guest_physical_address_bits(), ), ], ); print_title(&skin, "Extended Feature Extensions ID (0x8000_0008/ebx):"); table2( &skin, &[ RowGen::tuple("CLZERO", info.has_cl_zero()), RowGen::tuple("instructions retired count", info.has_inst_ret_cntr_msr()), RowGen::tuple( "always save/restore error pointers", info.has_restore_fp_error_ptrs(), ), RowGen::tuple("RDPRU", info.has_rdpru()), RowGen::tuple("INVLPGB", info.has_invlpgb()), RowGen::tuple("MCOMMIT", info.has_mcommit()), RowGen::tuple("WBNOINVD", info.has_wbnoinvd()), RowGen::tuple("WBNOINVD/WBINVD interruptible", info.has_int_wbinvd()), RowGen::tuple("EFER.LMSLE unsupported", info.has_unsupported_efer_lmsle()), RowGen::tuple("INVLPGB with nested paging", info.has_invlpgb_nested()), ], ); print_title(&skin, "Size Identifiers (0x8000_0008/ecx):"); table2( &skin, &[ RowGen::tuple("Logical processors", info.num_phys_threads()), RowGen::tuple("APIC core ID size", info.apic_id_size()), RowGen::tuple("Max. logical processors", info.maximum_logical_processors()), RowGen::tuple("Perf. TSC size [Bits]", info.perf_tsc_size()), ], ); print_title(&skin, "Size Identifiers (0x8000_0008/edx):"); table2( &skin, &[ RowGen::tuple("RDPRU max. input value", info.max_rdpru_id()), RowGen::tuple("INVLPGB max. #pages", info.invlpgb_max_pages()), ], ); } if let Some(info) = cpuid.get_svm_info() { print_title(&skin, "SVM Secure Virtual Machine (0x8000_000a/eax):"); print_attr(&skin, "Revision", info.revision()); print_title(&skin, "SVM Secure Virtual Machine (0x8000_000a/edx):"); table2( &skin, &[ RowGen::tuple("nested paging", info.has_nested_paging()), RowGen::tuple("LBR virtualization", info.has_lbr_virtualization()), RowGen::tuple("SVM lock", info.has_svm_lock()), RowGen::tuple("NRIP", info.has_nrip()), RowGen::tuple("MSR based TSC rate control", info.has_tsc_rate_msr()), RowGen::tuple("VMCB clean bits support", info.has_vmcb_clean_bits()), RowGen::tuple("flush by ASID", info.has_flush_by_asid()), RowGen::tuple("decode assists", info.has_decode_assists()), RowGen::tuple("pause intercept filter", info.has_pause_filter()), RowGen::tuple("pause filter threshold", info.has_pause_filter_threshold()), RowGen::tuple("AVIC: virtual interrupt controller", info.has_avic()), RowGen::tuple( "virtualized VMLOAD/VMSAVE", info.has_vmsave_virtualization(), ), RowGen::tuple("GIF: virtual global interrupt flag", info.has_gif()), RowGen::tuple("GMET: guest mode execute trap", info.has_gmet()), RowGen::tuple("SPEC_CTRL virtualization", info.has_spec_ctrl()), RowGen::tuple("Supervisor shadow-stack restrictions", info.has_sss_check()), RowGen::tuple("#MC intercept", info.has_host_mce_override()), RowGen::tuple("INVLPGB/TLBSYNC virtualization", info.has_tlb_ctrl()), ], ); } if let Some(info) = cpuid.get_tlb_1gb_page_info() { print_title(&skin, "TLB 1-GiB Pages Info (0x8000_0019):"); table2( &skin, &[ RowGen::tuple("L1 iTLB #entries", info.itlb_l1_1gb_size()), RowGen::tuple("L1 iTLB associativity", info.itlb_l1_1gb_associativity()), RowGen::tuple("L1 dTLB #entries", info.dtlb_l1_1gb_size()), RowGen::tuple("L1 dTLB associativity", info.dtlb_l1_1gb_associativity()), RowGen::tuple("L2 iTLB #entries", info.itlb_l2_1gb_size()), RowGen::tuple("L2 iTLB associativity", info.itlb_l2_1gb_associativity()), RowGen::tuple("L2 dTLB #entries", info.dtlb_l2_1gb_size()), RowGen::tuple("L2 dTLB associativity", info.dtlb_l2_1gb_associativity()), ], ); } if let Some(info) = cpuid.get_performance_optimization_info() { print_title(&skin, "Performance Optimization Info (0x8000_001a):"); table2( &skin, &[ RowGen::tuple("128-bits width the internal FP/SIMD", info.has_fp128()), RowGen::tuple( "MOVU SSE are efficient more than MOVL/MOVH", info.has_movu(), ), RowGen::tuple("256-bits width the internal FP/SIMD", info.has_fp256()), ], ); } if let Some(info) = cpuid.get_instruction_based_sampling_capabilities() { print_title( &skin, "Instruction-Based Sampling Capabilities (0x8000_001b):", ); table2( &skin, &[ RowGen::tuple("IBS feature flags valid", info.has_feature_flags()), RowGen::tuple("IBS fetch sampling supporte", info.has_fetch_sampling()), RowGen::tuple( "IBS execution sampling supported", info.has_execution_sampling(), ), RowGen::tuple( "Read write of op counter supported", info.has_read_write_operation_counter(), ), RowGen::tuple("Op counting mode supported", info.has_operation_counter()), RowGen::tuple( "Branch target address reporting supported", info.has_branch_target_address_reporting(), ), RowGen::tuple( "IbsOpCurCnt and IbsOpMaxCnt extend by 7 bits", info.has_operation_counter_extended(), ), RowGen::tuple( "Invalid RIP indication supported", info.has_invalid_rip_indication(), ), RowGen::tuple( "Fused branch micro-op indication supported", info.has_fused_branch_micro_op_indication(), ), RowGen::tuple( "L3 Miss Filtering for IBS supported", info.has_l3_miss_filtering(), ), ], ); } if let Some(info) = cpuid.get_processor_topology_info() { print_title(&skin, "Processor Topology Info (0x8000_001e):"); table2( &skin, &[ RowGen::tuple("x2APIC ID", info.x2apic_id()), RowGen::tuple("Core ID", info.core_id()), RowGen::tuple("Threads per core", info.threads_per_core()), RowGen::tuple("Node ID", info.node_id()), RowGen::tuple("Nodes per processor", info.nodes_per_processor()), ], ); } if let Some(info) = cpuid.get_memory_encryption_info() { print_title(&skin, "Memory Encryption Support (0x8000_001f):"); table2( &skin, &[ RowGen::tuple("SME: Secure Memory Encryption", info.has_sme()), RowGen::tuple("SEV: Secure Encrypted Virtualization", info.has_sev()), RowGen::tuple("Page Flush MSR", info.has_page_flush_msr()), RowGen::tuple("SEV-ES: Encrypted State", info.has_sev_es()), RowGen::tuple("SEV Secure Nested Paging", info.has_sev_snp()), RowGen::tuple("VM Permission Levels", info.has_vmpl()), RowGen::tuple( "Hardware cache coherency across encryption domains", info.has_hw_enforced_cache_coh(), ), RowGen::tuple("SEV guests only with 64-bit host", info.has_64bit_mode()), RowGen::tuple("Restricted injection", info.has_restricted_injection()), RowGen::tuple("Alternate injection", info.has_alternate_injection()), RowGen::tuple( "Full debug state swap for SEV-ES guests", info.has_debug_swap(), ), RowGen::tuple( "Disallowing IBS use by the host supported", info.has_prevent_host_ibs(), ), RowGen::tuple("Virtual Transparent Encryption", info.has_vte()), RowGen::tuple("C-bit position in page-table", info.c_bit_position()), RowGen::tuple( "Physical address bit reduction", info.physical_address_reduction(), ), RowGen::tuple( "Max. simultaneouslys encrypted guests", info.max_encrypted_guests(), ), RowGen::tuple( "Minimum ASID value for SEV guest", info.min_sev_no_es_asid(), ), ], ); } if let Some(info) = cpuid.get_pqos_extended_feature_info() { print_title(&skin, "Platform Quality of Service (0x8000_0020/0):"); table2( &skin, &[ RowGen::tuple("Memory Bandwidth Enforcement", info.has_l3mbe()), RowGen::tuple("Slow Memory Bandwidth Enforcement", info.has_l3smbe()), RowGen::tuple("Bandwidth Monitoring Event Configuration", info.has_bmec()), RowGen::tuple("L3 Range Reservation", info.has_l3rr()), RowGen::tuple("Assignable Bandwidth Monitoring Counters", info.has_abmc()), RowGen::tuple( "Smart Data Cache Injection (SDCI) Allocation Enforcement", info.has_sdciae(), ), ], ); if let Some(info) = info.get_l3_memory_bandwidth_enforcement_info() { print_title( &skin, "L3 Memory Bandwidth Enforcement Information (0x8000_0020/1):", ); table2( &skin, &[ RowGen::tuple("Bandwidth Length", info.bandwidth_length()), RowGen::tuple("COS Number", info.cos_max()), ], ); } if let Some(info) = info.get_l3_slow_memory_bandwidth_enforcement_info() { print_title( &skin, "L3 Slow Memory Bandwidth Enforcement Information (0x8000_0020/2):", ); table2( &skin, &[ RowGen::tuple("Bandwidth Length", info.bandwidth_length()), RowGen::tuple("COS Number", info.cos_max()), ], ); } if let Some(info) = info.get_bandwidth_monitoring_event_counters_info() { print_title( &skin, "Bandwidth Monitoring Event Counters Information (0x8000_0020/3):", ); table2( &skin, &[ RowGen::tuple( "Number of configurable bandwidth events", info.number_events(), ), RowGen::tuple( "Reads to local DRAM memory", info.has_l3_cache_lcl_bw_fill_mon(), ), RowGen::tuple( "Reads to remote DRAM memory", info.has_l3_cache_rmt_bw_fill_mon(), ), RowGen::tuple( "Non-temporal writes to local memory", info.has_l3_cache_lcl_bw_nt_wr_mon(), ), RowGen::tuple( "Non-temporal writes to remote memory", info.has_l3_cache_rmt_bw_nt_wr_mon(), ), RowGen::tuple( "Reads to local memory identified as 'Slow Memory'", info.has_l3_cache_lcl_slow_bw_fill_mon(), ), RowGen::tuple( "Reads to remote memory identified as 'Slow Memory'", info.has_l3_cache_rmt_slow_bw_fill_mon(), ), RowGen::tuple( "Dirty victim writes to all types of memoryā€.", info.has_l3_cache_vic_mon(), ), ], ); } if let Some(info) = info.get_assignable_bandwidth_monitoring_counters_info() { print_title( &skin, "Assignable Bandwidth Monitoring Counters Information (0x8000_0020/5):", ); table2( &skin, &[ RowGen::tuple( "Indicates that QM_CTR bit 61 is an overflow bit", info.has_overflow_bit(), ), RowGen::tuple( "QM_CTR counter width, offset from 24 bits", info.counter_size(), ), RowGen::tuple("Maximum supported ABMC counter ID", info.max_abmc()), RowGen::tuple( "Bandwidth counters can be configured", info.has_select_cos(), ), ], ); } } if let Some(info) = cpuid.get_extended_feature_identification_2() { print_title(&skin, "Extended Feature Identification (0x8000_0021):"); table2( &skin, &[ RowGen::tuple("Processor ignores nested data breakpoints", info.has_no_nested_data_bp()), RowGen::tuple("LFENCE is always dispatch serializing", info.has_lfence_always_serializing()), RowGen::tuple("SMM paging configuration lock supported", info.has_smm_pg_cfg_lock()), RowGen::tuple("Null segment selector loads also clear the destination segment register base and limit", info.has_null_select_clears_base()), RowGen::tuple("Upper Address Ignore is supported", info.has_upper_address_ignore()), RowGen::tuple("Automatic IBRS", info.has_automatic_ibrs()), RowGen::tuple("SMM_CTL MSR (C001_0116h) is not supporte", info.has_no_smm_ctl_msr()), RowGen::tuple("Prefetch control MSR supporte", info.has_prefetch_ctl_msr()), RowGen::tuple("CPUID disable for non-privileged softwar", info.has_cpuid_user_dis()), RowGen::tuple("The size of the Microcode patch in 16-byte multiples", info.microcode_patch_size()), ], ); } if let Some(info) = cpuid.get_extended_performance_monitoring_and_debug() { print_title( &skin, "Extended Performance Monitoring and Debug (0x8000_0022):", ); table2( &skin, &[ RowGen::tuple( "Performance Monitoring Version 2 supported", info.has_perf_mon_v2(), ), RowGen::tuple("Last Branch Record Stack supported", info.has_lbr_stack()), RowGen::tuple("LbrAndPmcFreeze", info.has_lbr_and_pmc_freeze()), RowGen::tuple( "Number of Core Performance Counters", info.num_perf_ctr_core(), ), RowGen::tuple( "Number of Last Branch Record Stack entries", info.num_lbr_stack_size(), ), RowGen::tuple( "Number of Northbridge Performance Monitor Counters", info.num_perf_ctr_nb(), ), ], ); } if let Some(info) = cpuid.get_multi_key_encrypted_memory_capabilities() { print_title( &skin, "Multi-Key Encrypted Memory Capabilities (0x8000_0023):", ); table2( &skin, &[ RowGen::tuple( "Secure Host Multi-Key Memory (MEM-HMK) Encryption Mode Supported", info.has_mem_hmk(), ), RowGen::tuple("MaxMemHmkEncrKeyID", info.max_mem_hmk_encr_key_id()), ], ); } if let Some(info) = cpuid.get_extended_cpu_topology() { for (level, info) in info.enumerate() { print_title( &skin, &format!("Extended CPU Topology (0x8000_0026/{level}):"), ); table2( &skin, &[ RowGen::tuple("Mask Width", info.mask_width()), RowGen::tuple( "Efficiency Ranking Available", info.has_efficiency_ranking_available(), ), RowGen::tuple("Heterogeneous Cores", info.has_heterogeneous_cores()), RowGen::tuple("Asymmetric Topology", info.has_asymmetric_topology()), RowGen::tuple( "Number of logical processors at the current hierarchy level", info.num_logical_processors(), ), RowGen::tuple( "Static efficiency ranking between cores of a specific core type", info.pwr_efficiency_ranking(), ), RowGen::tuple("Native Mode Id", info.native_mode_id()), RowGen::tuple("Core Type", info.core_type()), RowGen::tuple("Level Type", info.level_type().to_string()), RowGen::tuple( "Extended APIC ID of the logical processo", info.extended_apic_id(), ), ], ); } } } raw-cpuid-11.6.0/src/extended.rs000064400000000000000000002273711046102023000145550ustar 00000000000000//! Data-structures / interpretation for extended leafs (>= 0x8000_0000) use bitflags::bitflags; use core::fmt::{self, Debug, Display, Formatter}; use core::mem::size_of; use core::slice; use core::str; use crate::{ get_bits, CpuIdReader, CpuIdResult, Vendor, EAX_EXTENDED_CPU_TOPOLOGY, EAX_PQOS_EXTENDED_FEATURES, }; /// Extended Processor and Processor Feature Identifiers (LEAF=0x8000_0001) /// /// # Platforms /// āœ… AMD 🟔 Intel pub struct ExtendedProcessorFeatureIdentifiers { vendor: Vendor, eax: u32, ebx: u32, ecx: ExtendedFunctionInfoEcx, edx: ExtendedFunctionInfoEdx, } impl ExtendedProcessorFeatureIdentifiers { pub(crate) fn new(vendor: Vendor, data: CpuIdResult) -> Self { Self { vendor, eax: data.eax, ebx: data.ebx, ecx: ExtendedFunctionInfoEcx::from_bits_truncate(data.ecx), edx: ExtendedFunctionInfoEdx::from_bits_truncate(data.edx), } } /// Extended Processor Signature. /// /// # AMD /// The value returned is the same as the value returned in EAX for LEAF=0x0000_0001 /// (use `CpuId.get_feature_info` instead) /// /// # Intel /// Vague mention of "Extended Processor Signature", not clear what it's supposed to /// represent. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn extended_signature(&self) -> u32 { self.eax } /// Returns package type on AMD. /// /// Package type. If `(Family[7:0] >= 10h)`, this field is valid. If /// `(Family[7:0]<10h)`, this field is reserved /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn pkg_type(&self) -> u32 { get_bits(self.ebx, 28, 31) } /// Returns brand ID on AMD. /// /// This field, in conjunction with CPUID `LEAF=0x0000_0001_EBX[8BitBrandId]`, and used /// by firmware to generate the processor name string. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn brand_id(&self) -> u32 { get_bits(self.ebx, 0, 15) } /// Is LAHF/SAHF available in 64-bit mode? /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_lahf_sahf(&self) -> bool { self.ecx.contains(ExtendedFunctionInfoEcx::LAHF_SAHF) } /// Check support legacy cmp. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_cmp_legacy(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::CMP_LEGACY) } /// Secure virtual machine supported. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_svm(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SVM) } /// Extended APIC space. /// /// This bit indicates the presence of extended APIC register space starting at offset /// 400h from the ā€œAPIC Base Address Register,ā€ as specified in the BKDG. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_ext_apic_space(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::EXT_APIC_SPACE) } /// LOCK MOV CR0 means MOV CR8. See ā€œMOV(CRn)ā€ in APM3. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_alt_mov_cr8(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::ALTMOVCR8) } /// Is LZCNT available? /// /// # AMD /// It's called ABM (Advanced bit manipulation) on AMD and also adds support for /// some other instructions. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_lzcnt(&self) -> bool { self.ecx.contains(ExtendedFunctionInfoEcx::LZCNT) } /// XTRQ, INSERTQ, MOVNTSS, and MOVNTSD instruction support. /// /// See ā€œEXTRQā€, ā€œINSERTQā€,ā€œMOVNTSSā€, and ā€œMOVNTSDā€ in APM4. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_sse4a(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SSE4A) } /// Misaligned SSE mode. See ā€œMisaligned Access Support Added for SSE Instructionsā€ in /// APM1. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_misaligned_sse_mode(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::MISALIGNSSE) } /// Is PREFETCHW available? /// /// # AMD /// PREFETCH and PREFETCHW instruction support. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_prefetchw(&self) -> bool { self.ecx.contains(ExtendedFunctionInfoEcx::PREFETCHW) } /// Indicates OS-visible workaround support /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_osvw(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::OSVW) } /// Instruction based sampling. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_ibs(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::IBS) } /// Extended operation support. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_xop(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::XOP) } /// SKINIT and STGI are supported. /// /// Indicates support for SKINIT and STGI, independent of the value of /// `MSRC000_0080[SVME]`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_skinit(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SKINIT) } /// Watchdog timer support. /// /// Indicates support for MSRC001_0074. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_wdt(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::WDT) } /// Lightweight profiling support /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_lwp(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::LWP) } /// Four-operand FMA instruction support. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_fma4(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::FMA4) } /// Trailing bit manipulation instruction support. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_tbm(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::TBM) } /// Topology extensions support. /// /// Indicates support for CPUID `Fn8000_001D_EAX_x[N:0]-CPUID Fn8000_001E_EDX`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_topology_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::TOPEXT) } /// Processor performance counter extensions support. /// /// Indicates support for `MSRC001_020[A,8,6,4,2,0]` and `MSRC001_020[B,9,7,5,3,1]`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_perf_cntr_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXT) } /// NB performance counter extensions support. /// /// Indicates support for `MSRC001_024[6,4,2,0]` and `MSRC001_024[7,5,3,1]`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_nb_perf_cntr_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXTNB) } /// Data access breakpoint extension. /// /// Indicates support for `MSRC001_1027` and `MSRC001_101[B:9]`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_data_access_bkpt_extension(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::DATABRKPEXT) } /// Performance time-stamp counter. /// /// Indicates support for `MSRC001_0280` `[Performance Time Stamp Counter]`. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_perf_tsc(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFTSC) } /// Support for L3 performance counter extension. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_perf_cntr_llc_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXTLLC) } /// Support for MWAITX and MONITORX instructions. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_monitorx_mwaitx(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::MONITORX) } /// Breakpoint Addressing masking extended to bit 31. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_addr_mask_extension(&self) -> bool { self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::ADDRMASKEXT) } /// Are fast system calls available. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_syscall_sysret(&self) -> bool { self.edx.contains(ExtendedFunctionInfoEdx::SYSCALL_SYSRET) } /// Is there support for execute disable bit. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_execute_disable(&self) -> bool { self.edx.contains(ExtendedFunctionInfoEdx::EXECUTE_DISABLE) } /// AMD extensions to MMX instructions. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_mmx_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::MMXEXT) } /// FXSAVE and FXRSTOR instruction optimizations. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_fast_fxsave_fxstor(&self) -> bool { self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::FFXSR) } /// Is there support for 1GiB pages. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_1gib_pages(&self) -> bool { self.edx.contains(ExtendedFunctionInfoEdx::GIB_PAGES) } /// Check support for rdtscp instruction. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_rdtscp(&self) -> bool { self.edx.contains(ExtendedFunctionInfoEdx::RDTSCP) } /// Check support for 64-bit mode. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_64bit_mode(&self) -> bool { self.edx.contains(ExtendedFunctionInfoEdx::I64BIT_MODE) } /// 3DNow AMD extensions. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_amd_3dnow_extensions(&self) -> bool { self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::THREEDNOWEXT) } /// 3DNow extensions. /// /// # Platform /// āœ… AMD āŒ Intel (will return false) pub fn has_3dnow(&self) -> bool { self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::THREEDNOW) } } impl Debug for ExtendedProcessorFeatureIdentifiers { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut ds = f.debug_struct("ExtendedProcessorFeatureIdentifiers"); ds.field("extended_signature", &self.extended_signature()); if self.vendor == Vendor::Amd { ds.field("pkg_type", &self.pkg_type()); ds.field("brand_id", &self.brand_id()); } ds.field("ecx_features", &self.ecx); ds.field("edx_features", &self.edx); ds.finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFunctionInfoEcx: u32 { const LAHF_SAHF = 1 << 0; const CMP_LEGACY = 1 << 1; const SVM = 1 << 2; const EXT_APIC_SPACE = 1 << 3; const ALTMOVCR8 = 1 << 4; const LZCNT = 1 << 5; const SSE4A = 1 << 6; const MISALIGNSSE = 1 << 7; const PREFETCHW = 1 << 8; const OSVW = 1 << 9; const IBS = 1 << 10; const XOP = 1 << 11; const SKINIT = 1 << 12; const WDT = 1 << 13; const LWP = 1 << 15; const FMA4 = 1 << 16; const TBM = 1 << 21; const TOPEXT = 1 << 22; const PERFCTREXT = 1 << 23; const PERFCTREXTNB = 1 << 24; const DATABRKPEXT = 1 << 26; const PERFTSC = 1 << 27; const PERFCTREXTLLC = 1 << 28; const MONITORX = 1 << 29; const ADDRMASKEXT = 1 << 30; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFunctionInfoEdx: u32 { const SYSCALL_SYSRET = 1 << 11; const EXECUTE_DISABLE = 1 << 20; const MMXEXT = 1 << 22; const FFXSR = 1 << 25; const GIB_PAGES = 1 << 26; const RDTSCP = 1 << 27; const I64BIT_MODE = 1 << 29; const THREEDNOWEXT = 1 << 30; const THREEDNOW = 1 << 31; } } /// Processor name (LEAF=0x8000_0002..=0x8000_0004). /// /// ASCII string up to 48 characters in length corresponding to the processor name. /// /// # Platforms /// āœ… AMD āœ… Intel pub struct ProcessorBrandString { data: [CpuIdResult; 3], } impl ProcessorBrandString { pub(crate) fn new(data: [CpuIdResult; 3]) -> Self { Self { data } } /// Return the processor brand string as a rust string. /// /// For example: /// "11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz". pub fn as_str(&self) -> &str { // Safety: CpuIdResult is laid out with repr(C), and the array // self.data contains 3 contiguous elements. let slice: &[u8] = unsafe { slice::from_raw_parts( self.data.as_ptr() as *const u8, self.data.len() * size_of::(), ) }; // Brand terminated at nul byte or end, whichever comes first. let slice = slice.split(|&x| x == 0).next().unwrap(); str::from_utf8(slice) .unwrap_or("Invalid Processor Brand String") .trim() } } impl Debug for ProcessorBrandString { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ProcessorBrandString") .field("as_str", &self.as_str()) .finish() } } /// L1 Cache and TLB Information (LEAF=0x8000_0005). /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) #[derive(PartialEq, Eq, Debug)] pub struct L1CacheTlbInfo { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl L1CacheTlbInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, ecx: data.ecx, edx: data.edx, } } /// Data TLB associativity for 2-MB and 4-MB pages. pub fn dtlb_2m_4m_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 24, 31) as u8; Associativity::for_l1(assoc_bits) } /// Data TLB number of entries for 2-MB and 4-MB pages. /// /// The value returned is for the number of entries available for the 2-MB page size; /// 4-MB pages require two 2-MB entries, so the number of entries available for the /// 4-MB page size is one-half the returned value. pub fn dtlb_2m_4m_size(&self) -> u8 { get_bits(self.eax, 16, 23) as u8 } /// Instruction TLB associativity for 2-MB and 4-MB pages. pub fn itlb_2m_4m_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 8, 15) as u8; Associativity::for_l1(assoc_bits) } /// Instruction TLB number of entries for 2-MB and 4-MB pages. /// /// The value returned is for the number of entries available for the 2-MB page size; /// 4-MB pages require two 2-MB entries, so the number of entries available for the /// 4-MB page size is one-half the returned value. pub fn itlb_2m_4m_size(&self) -> u8 { get_bits(self.eax, 0, 7) as u8 } /// Data TLB associativity for 4K pages. pub fn dtlb_4k_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 24, 31) as u8; Associativity::for_l1(assoc_bits) } /// Data TLB number of entries for 4K pages. pub fn dtlb_4k_size(&self) -> u8 { get_bits(self.ebx, 16, 23) as u8 } /// Instruction TLB associativity for 4K pages. pub fn itlb_4k_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 8, 15) as u8; Associativity::for_l1(assoc_bits) } /// Instruction TLB number of entries for 4K pages. pub fn itlb_4k_size(&self) -> u8 { get_bits(self.ebx, 0, 7) as u8 } /// L1 data cache size in KB pub fn dcache_size(&self) -> u8 { get_bits(self.ecx, 24, 31) as u8 } /// L1 data cache associativity. pub fn dcache_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ecx, 16, 23) as u8; Associativity::for_l1(assoc_bits) } /// L1 data cache lines per tag. pub fn dcache_lines_per_tag(&self) -> u8 { get_bits(self.ecx, 8, 15) as u8 } /// L1 data cache line size in bytes. pub fn dcache_line_size(&self) -> u8 { get_bits(self.ecx, 0, 7) as u8 } /// L1 instruction cache size in KB pub fn icache_size(&self) -> u8 { get_bits(self.edx, 24, 31) as u8 } /// L1 instruction cache associativity. pub fn icache_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.edx, 16, 23) as u8; Associativity::for_l1(assoc_bits) } /// L1 instruction cache lines per tag. pub fn icache_lines_per_tag(&self) -> u8 { get_bits(self.edx, 8, 15) as u8 } /// L1 instruction cache line size in bytes. pub fn icache_line_size(&self) -> u8 { get_bits(self.edx, 0, 7) as u8 } } /// L2/L3 Cache and TLB Information (LEAF=0x8000_0006). /// /// # Availability /// āœ… AMD 🟔 Intel #[derive(PartialEq, Eq, Debug)] pub struct L2And3CacheTlbInfo { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl L2And3CacheTlbInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, ecx: data.ecx, edx: data.edx, } } /// L2 Data TLB associativity for 2-MB and 4-MB pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn dtlb_2m_4m_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 28, 31) as u8; Associativity::for_l2(assoc_bits) } /// L2 Data TLB number of entries for 2-MB and 4-MB pages. /// /// The value returned is for the number of entries available for the 2-MB page size; /// 4-MB pages require two 2-MB entries, so the number of entries available for the /// 4-MB page size is one-half the returned value. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn dtlb_2m_4m_size(&self) -> u16 { get_bits(self.eax, 16, 27) as u16 } /// L2 Instruction TLB associativity for 2-MB and 4-MB pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn itlb_2m_4m_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 12, 15) as u8; Associativity::for_l2(assoc_bits) } /// L2 Instruction TLB number of entries for 2-MB and 4-MB pages. /// /// The value returned is for the number of entries available for the 2-MB page size; /// 4-MB pages require two 2-MB entries, so the number of entries available for the /// 4-MB page size is one-half the returned value. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn itlb_2m_4m_size(&self) -> u16 { get_bits(self.eax, 0, 11) as u16 } /// L2 Data TLB associativity for 4K pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn dtlb_4k_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 28, 31) as u8; Associativity::for_l2(assoc_bits) } /// L2 Data TLB number of entries for 4K pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn dtlb_4k_size(&self) -> u16 { get_bits(self.ebx, 16, 27) as u16 } /// L2 Instruction TLB associativity for 4K pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn itlb_4k_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 12, 15) as u8; Associativity::for_l2(assoc_bits) } /// L2 Instruction TLB number of entries for 4K pages. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn itlb_4k_size(&self) -> u16 { get_bits(self.ebx, 0, 11) as u16 } /// L2 Cache Line size in bytes /// /// # Platforms /// āœ… AMD āœ… Intel pub fn l2cache_line_size(&self) -> u8 { get_bits(self.ecx, 0, 7) as u8 } /// L2 cache lines per tag. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn l2cache_lines_per_tag(&self) -> u8 { get_bits(self.ecx, 8, 11) as u8 } /// L2 Associativity field /// /// # Availability /// āœ… AMD āœ… Intel pub fn l2cache_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ecx, 12, 15) as u8; Associativity::for_l2(assoc_bits) } /// Cache size in KB. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn l2cache_size(&self) -> u16 { get_bits(self.ecx, 16, 31) as u16 } /// L2 Cache Line size in bytes /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn l3cache_line_size(&self) -> u8 { get_bits(self.edx, 0, 7) as u8 } /// L2 cache lines per tag. /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn l3cache_lines_per_tag(&self) -> u8 { get_bits(self.edx, 8, 11) as u8 } /// L2 Associativity field /// /// # Availability /// āœ… AMD āŒ Intel (reserved=0) pub fn l3cache_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.edx, 12, 15) as u8; Associativity::for_l3(assoc_bits) } /// Specifies the L3 cache size range /// /// `(L3Size[31:18] * 512KB) <= L3 cache size < ((L3Size[31:18]+1) * 512KB)`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn l3cache_size(&self) -> u16 { get_bits(self.edx, 18, 31) as u16 } } /// Info about cache Associativity. #[derive(PartialEq, Eq, Debug)] pub enum Associativity { Disabled, DirectMapped, NWay(u8), FullyAssociative, Unknown, } impl Display for Associativity { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let s = match self { Associativity::Disabled => "Disabled", Associativity::DirectMapped => "Direct mapped", Associativity::NWay(n) => { return write!(f, "NWay({})", n); } Associativity::FullyAssociative => "Fully associative", Associativity::Unknown => "Unknown (check leaf 0x8000_001d)", }; f.write_str(s) } } impl Associativity { /// Constructor for L1 Cache and TLB Associativity Field Encodings fn for_l1(n: u8) -> Associativity { match n { 0x0 => Associativity::Disabled, // Intel only, AMD is reserved 0x1 => Associativity::DirectMapped, 0x2..=0xfe => Associativity::NWay(n), 0xff => Associativity::FullyAssociative, } } /// Constructor for L2 Cache and TLB Associativity Field Encodings fn for_l2(n: u8) -> Associativity { match n { 0x0 => Associativity::Disabled, 0x1 => Associativity::DirectMapped, 0x2 => Associativity::NWay(2), 0x4 => Associativity::NWay(4), 0x5 => Associativity::NWay(6), // Reserved on Intel 0x6 => Associativity::NWay(8), // 0x7 => SDM states: "See CPUID leaf 04H, sub-leaf 2" 0x8 => Associativity::NWay(16), 0x9 => Associativity::Unknown, // Intel: Reserved, AMD: Value for all fields should be determined from Fn8000_001D 0xa => Associativity::NWay(32), 0xb => Associativity::NWay(48), 0xc => Associativity::NWay(64), 0xd => Associativity::NWay(96), 0xe => Associativity::NWay(128), 0xF => Associativity::FullyAssociative, _ => Associativity::Unknown, } } /// Constructor for L2 Cache and TLB Associativity Field Encodings fn for_l3(n: u8) -> Associativity { Associativity::for_l2(n) } } /// Processor Power Management and RAS Capabilities (LEAF=0x8000_0007). /// /// # Platforms /// āœ… AMD 🟔 Intel #[derive(Debug, PartialEq, Eq)] pub struct ApmInfo { /// Reserved on AMD and Intel. _eax: u32, ebx: RasCapabilities, ecx: u32, edx: ApmInfoEdx, } impl ApmInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { _eax: data.eax, ebx: RasCapabilities::from_bits_truncate(data.ebx), ecx: data.ecx, edx: ApmInfoEdx::from_bits_truncate(data.edx), } } /// Is MCA overflow recovery available? /// /// If set, indicates that MCA overflow conditions (`MCi_STATUS[Overflow]=1`) /// are not fatal; software may safely ignore such conditions. If clear, MCA /// overflow conditions require software to shut down the system. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_mca_overflow_recovery(&self) -> bool { self.ebx.contains(RasCapabilities::MCAOVFLRECOV) } /// Has Software uncorrectable error containment and recovery capability? /// /// The processor supports software containment of uncorrectable errors /// through context synchronizing data poisoning and deferred error /// interrupts. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_succor(&self) -> bool { self.ebx.contains(RasCapabilities::SUCCOR) } /// Has Hardware assert supported? /// /// Indicates support for `MSRC001_10[DF:C0]`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_hwa(&self) -> bool { self.ebx.contains(RasCapabilities::HWA) } /// Specifies the ratio of the compute unit power accumulator sample period /// to the TSC counter period. /// /// Returns a value of 0 if not applicable for the system. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn cpu_pwr_sample_time_ratio(&self) -> u32 { self.ecx } /// Is Temperature Sensor available? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_ts(&self) -> bool { self.edx.contains(ApmInfoEdx::TS) } /// Frequency ID control. /// /// # Note /// Function replaced by `has_hw_pstate`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_freq_id_ctrl(&self) -> bool { self.edx.contains(ApmInfoEdx::FID) } /// Voltage ID control. /// /// # Note /// Function replaced by `has_hw_pstate`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_volt_id_ctrl(&self) -> bool { self.edx.contains(ApmInfoEdx::VID) } /// Has THERMTRIP? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_thermtrip(&self) -> bool { self.edx.contains(ApmInfoEdx::TTP) } /// Hardware thermal control (HTC)? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_tm(&self) -> bool { self.edx.contains(ApmInfoEdx::TM) } /// Has 100 MHz multiplier Control? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_100mhz_steps(&self) -> bool { self.edx.contains(ApmInfoEdx::MHZSTEPS100) } /// Has Hardware P-state control? /// /// MSRC001_0061 [P-state Current Limit], MSRC001_0062 [P-state Control] and /// MSRC001_0063 [P-state Status] exist /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_hw_pstate(&self) -> bool { self.edx.contains(ApmInfoEdx::HWPSTATE) } /// Is Invariant TSC available? /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_invariant_tsc(&self) -> bool { self.edx.contains(ApmInfoEdx::INVTSC) } /// Has Core performance boost? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_cpb(&self) -> bool { self.edx.contains(ApmInfoEdx::CPB) } /// Has Read-only effective frequency interface? /// /// Indicates presence of MSRC000_00E7 [Read-Only Max Performance Frequency /// Clock Count (MPerfReadOnly)] and MSRC000_00E8 [Read-Only Actual /// Performance Frequency Clock Count (APerfReadOnly)]. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_ro_effective_freq_iface(&self) -> bool { self.edx.contains(ApmInfoEdx::EFFFREQRO) } /// Indicates support for processor feedback interface. /// /// # Note /// This feature is deprecated. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_feedback_iface(&self) -> bool { self.edx.contains(ApmInfoEdx::PROCFEEDBACKIF) } /// Has Processor power reporting interface? /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_power_reporting_iface(&self) -> bool { self.edx.contains(ApmInfoEdx::PROCPWRREPORT) } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ApmInfoEdx: u32 { const TS = 1 << 0; const FID = 1 << 1; const VID = 1 << 2; const TTP = 1 << 3; const TM = 1 << 4; const MHZSTEPS100 = 1 << 6; const HWPSTATE = 1 << 7; const INVTSC = 1 << 8; const CPB = 1 << 9; const EFFFREQRO = 1 << 10; const PROCFEEDBACKIF = 1 << 11; const PROCPWRREPORT = 1 << 12; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct RasCapabilities: u32 { const MCAOVFLRECOV = 1 << 0; const SUCCOR = 1 << 1; const HWA = 1 << 2; } } /// Processor Capacity Parameters and Extended Feature Identification /// (LEAF=0x8000_0008). /// /// This function provides the size or capacity of various architectural /// parameters that vary by implementation, as well as an extension to the /// 0x8000_0001 feature identifiers. /// /// # Platforms /// āœ… AMD 🟔 Intel #[derive(PartialEq, Eq)] pub struct ProcessorCapacityAndFeatureInfo { eax: u32, ebx: ProcessorCapacityAndFeatureEbx, ecx: u32, edx: u32, } impl ProcessorCapacityAndFeatureInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: ProcessorCapacityAndFeatureEbx::from_bits_truncate(data.ebx), ecx: data.ecx, edx: data.edx, } } /// Physical Address Bits /// /// # Platforms /// āœ… AMD āœ… Intel pub fn physical_address_bits(&self) -> u8 { get_bits(self.eax, 0, 7) as u8 } /// Linear Address Bits /// /// # Platforms /// āœ… AMD āœ… Intel pub fn linear_address_bits(&self) -> u8 { get_bits(self.eax, 8, 15) as u8 } /// Guest Physical Address Bits /// /// This number applies only to guests using nested paging. When this field /// is zero, refer to the PhysAddrSize field for the maximum guest physical /// address size. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn guest_physical_address_bits(&self) -> u8 { get_bits(self.eax, 16, 23) as u8 } /// CLZERO instruction supported if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_cl_zero(&self) -> bool { self.ebx.contains(ProcessorCapacityAndFeatureEbx::CLZERO) } /// Instruction Retired Counter MSR available if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_inst_ret_cntr_msr(&self) -> bool { self.ebx .contains(ProcessorCapacityAndFeatureEbx::INST_RETCNT_MSR) } /// FP Error Pointers Restored by XRSTOR if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_restore_fp_error_ptrs(&self) -> bool { self.ebx .contains(ProcessorCapacityAndFeatureEbx::RSTR_FP_ERR_PTRS) } /// INVLPGB and TLBSYNC instruction supported if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_invlpgb(&self) -> bool { self.ebx.contains(ProcessorCapacityAndFeatureEbx::INVLPGB) } /// RDPRU instruction supported if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_rdpru(&self) -> bool { self.ebx.contains(ProcessorCapacityAndFeatureEbx::RDPRU) } /// MCOMMIT instruction supported if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_mcommit(&self) -> bool { self.ebx.contains(ProcessorCapacityAndFeatureEbx::MCOMMIT) } /// WBNOINVD instruction supported if set. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_wbnoinvd(&self) -> bool { self.ebx.contains(ProcessorCapacityAndFeatureEbx::WBNOINVD) } /// WBINVD/WBNOINVD are interruptible if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_int_wbinvd(&self) -> bool { self.ebx .contains(ProcessorCapacityAndFeatureEbx::INT_WBINVD) } /// EFER.LMSLE is unsupported if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_unsupported_efer_lmsle(&self) -> bool { self.ebx .contains(ProcessorCapacityAndFeatureEbx::EFER_LMSLE_UNSUPP) } /// INVLPGB support for invalidating guest nested translations if set. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn has_invlpgb_nested(&self) -> bool { self.ebx .contains(ProcessorCapacityAndFeatureEbx::INVLPGB_NESTED) } /// Performance time-stamp counter size (in bits). /// /// Indicates the size of `MSRC001_0280[PTSC]`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=false) pub fn perf_tsc_size(&self) -> usize { let s = get_bits(self.ecx, 16, 17) as u8; match s & 0b11 { 0b00 => 40, 0b01 => 48, 0b10 => 56, 0b11 => 64, _ => unreachable!("AND with 0b11 in match"), } } /// APIC ID size. /// /// A value of zero indicates that legacy methods must be used to determine /// the maximum number of logical processors, as indicated by CPUID /// `Fn8000_0008_ECX[NC]`. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn apic_id_size(&self) -> u8 { get_bits(self.ecx, 12, 15) as u8 } /// The size of the `apic_id_size` field determines the maximum number of /// logical processors (MNLP) that the package could theoretically support, /// and not the actual number of logical processors that are implemented or /// enabled in the package, as indicated by CPUID `Fn8000_0008_ECX[NC]`. /// /// `MNLP = (2 raised to the power of ApicIdSize[3:0])` (if not 0) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn maximum_logical_processors(&self) -> usize { usize::pow(2, self.apic_id_size() as u32) } /// Number of physical threads in the processor. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn num_phys_threads(&self) -> usize { get_bits(self.ecx, 0, 7) as usize + 1 } /// Maximum page count for INVLPGB instruction. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn invlpgb_max_pages(&self) -> u16 { get_bits(self.edx, 0, 15) as u16 } /// The maximum ECX value recognized by RDPRU. /// /// # Platforms /// āœ… AMD āŒ Intel (reserved=0) pub fn max_rdpru_id(&self) -> u16 { get_bits(self.edx, 16, 31) as u16 } } impl Debug for ProcessorCapacityAndFeatureInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("ProcessorCapacityAndFeatureInfo") .field("physical_address_bits", &self.physical_address_bits()) .field("linear_address_bits", &self.linear_address_bits()) .field( "guest_physical_address_bits", &self.guest_physical_address_bits(), ) .field("has_cl_zero", &self.has_cl_zero()) .field("has_inst_ret_cntr_msr", &self.has_inst_ret_cntr_msr()) .field( "has_restore_fp_error_ptrs", &self.has_restore_fp_error_ptrs(), ) .field("has_invlpgb", &self.has_invlpgb()) .field("has_rdpru", &self.has_rdpru()) .field("has_mcommit", &self.has_mcommit()) .field("has_wbnoinvd", &self.has_wbnoinvd()) .field("has_int_wbinvd", &self.has_int_wbinvd()) .field( "has_unsupported_efer_lmsle", &self.has_unsupported_efer_lmsle(), ) .field("has_invlpgb_nested", &self.has_invlpgb_nested()) .field("perf_tsc_size", &self.perf_tsc_size()) .field("apic_id_size", &self.apic_id_size()) .field( "maximum_logical_processors", &self.maximum_logical_processors(), ) .field("num_phys_threads", &self.num_phys_threads()) .field("invlpgb_max_pages", &self.invlpgb_max_pages()) .field("max_rdpru_id", &self.max_rdpru_id()) .finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ProcessorCapacityAndFeatureEbx: u32 { const CLZERO = 1 << 0; const INST_RETCNT_MSR = 1 << 1; const RSTR_FP_ERR_PTRS = 1 << 2; const INVLPGB = 1 << 3; const RDPRU = 1 << 4; const MCOMMIT = 1 << 8; const WBNOINVD = 1 << 9; const INT_WBINVD = 1 << 13; const EFER_LMSLE_UNSUPP = 1 << 20; const INVLPGB_NESTED = 1 << 21; } } /// Information about the SVM features that the processory supports (LEAF=0x8000_000A). /// /// # Note /// If SVM is not supported ([ExtendedProcessorFeatureIdentifiers::has_svm] is false), /// this leaf is reserved ([crate::CpuId] will return None in this case). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct SvmFeatures { eax: u32, ebx: u32, /// Reserved _ecx: u32, edx: SvmFeaturesEdx, } impl SvmFeatures { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, _ecx: data.ecx, edx: SvmFeaturesEdx::from_bits_truncate(data.edx), } } /// SVM revision number. pub fn revision(&self) -> u8 { get_bits(self.eax, 0, 7) as u8 } /// Number of available address space identifiers (ASID). pub fn supported_asids(&self) -> u32 { self.ebx } /// Nested paging supported if set. pub fn has_nested_paging(&self) -> bool { self.edx.contains(SvmFeaturesEdx::NP) } /// Indicates support for LBR Virtualization. pub fn has_lbr_virtualization(&self) -> bool { self.edx.contains(SvmFeaturesEdx::LBR_VIRT) } /// Indicates support for SVM-Lock if set. pub fn has_svm_lock(&self) -> bool { self.edx.contains(SvmFeaturesEdx::SVML) } /// Indicates support for NRIP save on #VMEXIT if set. pub fn has_nrip(&self) -> bool { self.edx.contains(SvmFeaturesEdx::NRIPS) } /// Indicates support for MSR TSC ratio (MSR `0xC000_0104`) if set. pub fn has_tsc_rate_msr(&self) -> bool { self.edx.contains(SvmFeaturesEdx::TSC_RATE_MSR) } /// Indicates support for VMCB clean bits if set. pub fn has_vmcb_clean_bits(&self) -> bool { self.edx.contains(SvmFeaturesEdx::VMCB_CLEAN) } /// Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush /// only the current ASID's TLB entries. /// /// Also indicates support for the extended VMCB TLB_Control. pub fn has_flush_by_asid(&self) -> bool { self.edx.contains(SvmFeaturesEdx::FLUSH_BY_ASID) } /// Indicates support for the decode assists if set. pub fn has_decode_assists(&self) -> bool { self.edx.contains(SvmFeaturesEdx::DECODE_ASSISTS) } /// Indicates support for the pause intercept filter if set. pub fn has_pause_filter(&self) -> bool { self.edx.contains(SvmFeaturesEdx::PAUSE_FILTER) } /// Indicates support for the PAUSE filter cycle count threshold if set. pub fn has_pause_filter_threshold(&self) -> bool { self.edx.contains(SvmFeaturesEdx::PAUSE_FILTER_THRESHOLD) } /// Support for the AMD advanced virtual interrupt controller if set. pub fn has_avic(&self) -> bool { self.edx.contains(SvmFeaturesEdx::AVIC) } /// VMSAVE and VMLOAD virtualization supported if set. pub fn has_vmsave_virtualization(&self) -> bool { self.edx.contains(SvmFeaturesEdx::VMSAVE_VIRT) } /// GIF -- virtualized global interrupt flag if set. pub fn has_gif(&self) -> bool { self.edx.contains(SvmFeaturesEdx::VGIF) } /// Guest Mode Execution Trap supported if set. pub fn has_gmet(&self) -> bool { self.edx.contains(SvmFeaturesEdx::GMET) } /// SVM supervisor shadow stack restrictions if set. pub fn has_sss_check(&self) -> bool { self.edx.contains(SvmFeaturesEdx::SSS_CHECK) } /// SPEC_CTRL virtualization supported if set. pub fn has_spec_ctrl(&self) -> bool { self.edx.contains(SvmFeaturesEdx::SPEC_CTRL) } /// When host `CR4.MCE=1` and guest `CR4.MCE=0`, machine check exceptions (`#MC`) in a /// guest do not cause shutdown and are always intercepted if set. pub fn has_host_mce_override(&self) -> bool { self.edx.contains(SvmFeaturesEdx::HOST_MCE_OVERRIDE) } /// Support for INVLPGB/TLBSYNC hypervisor enable in VMCB and TLBSYNC intercept if /// set. pub fn has_tlb_ctrl(&self) -> bool { self.edx.contains(SvmFeaturesEdx::TLB_CTL) } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct SvmFeaturesEdx: u32 { const NP = 1 << 0; const LBR_VIRT = 1 << 1; const SVML = 1 << 2; const NRIPS = 1 << 3; const TSC_RATE_MSR = 1 << 4; const VMCB_CLEAN = 1 << 5; const FLUSH_BY_ASID = 1 << 6; const DECODE_ASSISTS = 1 << 7; const PAUSE_FILTER = 1 << 10; const PAUSE_FILTER_THRESHOLD = 1 << 12; const AVIC = 1 << 13; const VMSAVE_VIRT = 1 << 15; const VGIF = 1 << 16; const GMET = 1 << 17; const SSS_CHECK = 1 << 19; const SPEC_CTRL = 1 << 20; const HOST_MCE_OVERRIDE = 1 << 23; const TLB_CTL = 1 << 24; } } /// TLB 1-GiB Pages Information (LEAF=0x8000_0019). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct Tlb1gbPageInfo { eax: u32, ebx: u32, /// Reserved _ecx: u32, /// Reserved _edx: u32, } impl Tlb1gbPageInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// L1 Data TLB associativity for 1-GB pages. pub fn dtlb_l1_1gb_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 28, 31) as u8; Associativity::for_l2(assoc_bits) } /// L1 Data TLB number of entries for 1-GB pages. pub fn dtlb_l1_1gb_size(&self) -> u8 { get_bits(self.eax, 16, 27) as u8 } /// L1 Instruction TLB associativity for 1-GB pages. pub fn itlb_l1_1gb_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.eax, 12, 15) as u8; Associativity::for_l2(assoc_bits) } /// L1 Instruction TLB number of entries for 1-GB pages. pub fn itlb_l1_1gb_size(&self) -> u8 { get_bits(self.eax, 0, 11) as u8 } /// L2 Data TLB associativity for 1-GB pages. pub fn dtlb_l2_1gb_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 28, 31) as u8; Associativity::for_l2(assoc_bits) } /// L2 Data TLB number of entries for 1-GB pages. pub fn dtlb_l2_1gb_size(&self) -> u8 { get_bits(self.ebx, 16, 27) as u8 } /// L2 Instruction TLB associativity for 1-GB pages. pub fn itlb_l2_1gb_associativity(&self) -> Associativity { let assoc_bits = get_bits(self.ebx, 12, 15) as u8; Associativity::for_l2(assoc_bits) } /// L2 Instruction TLB number of entries for 1-GB pages. pub fn itlb_l2_1gb_size(&self) -> u8 { get_bits(self.ebx, 0, 11) as u8 } } /// Performance Optimization Identifier (LEAF=0x8000_001A). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct PerformanceOptimizationInfo { eax: PerformanceOptimizationInfoEax, /// Reserved _ebx: u32, /// Reserved _ecx: u32, /// Reserved _edx: u32, } impl PerformanceOptimizationInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: PerformanceOptimizationInfoEax::from_bits_truncate(data.eax), _ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// The internal FP/SIMD execution datapath is 128 bits wide if set. pub fn has_fp128(&self) -> bool { self.eax.contains(PerformanceOptimizationInfoEax::FP128) } /// MOVU (Move Unaligned) SSE instructions are efficient more than /// MOVL/MOVH SSE if set. pub fn has_movu(&self) -> bool { self.eax.contains(PerformanceOptimizationInfoEax::MOVU) } /// The internal FP/SIMD execution datapath is 256 bits wide if set. pub fn has_fp256(&self) -> bool { self.eax.contains(PerformanceOptimizationInfoEax::FP256) } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct PerformanceOptimizationInfoEax: u32 { const FP128 = 1 << 0; const MOVU = 1 << 1; const FP256 = 1 << 2; } } /// Performance Optimization Identifier (LEAF=0x8000_001A). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct InstructionBasedSamplingCapabilities { eax: InstructionBasedSamplingCapabilitiesEax, /// Reserved _ebx: u32, /// Reserved _ecx: u32, /// Reserved _edx: u32, } impl InstructionBasedSamplingCapabilities { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: InstructionBasedSamplingCapabilitiesEax::from_bits_truncate(data.eax), _ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// IBS feature flags valid if set. pub fn has_feature_flags(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::IBSFFV) } /// IBS fetch sampling supported if set. pub fn has_fetch_sampling(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::FETCH_SAM) } /// IBS execution sampling supported if set. pub fn has_execution_sampling(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::OP_SAM) } /// Read write of op counter supported if set. pub fn has_read_write_operation_counter(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::RD_WR_OP_CNT) } /// Op counting mode supported if set. pub fn has_operation_counter(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::OP_CNT) } /// Branch target address reporting supported if set. pub fn has_branch_target_address_reporting(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::BRN_TRGT) } /// IbsOpCurCnt and IbsOpMaxCnt extend by 7 bits if set. pub fn has_operation_counter_extended(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::OP_CNT_EXT) } /// Invalid RIP indication supported if set. pub fn has_invalid_rip_indication(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::RIP_INVALID_CHK) } /// Fused branch micro-op indication supported if set. pub fn has_fused_branch_micro_op_indication(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::OP_BRN_FUSE) } /// L3 Miss Filtering for IBS supported if set. pub fn has_l3_miss_filtering(&self) -> bool { self.eax .contains(InstructionBasedSamplingCapabilitiesEax::IBS_L3_MISS_FILTERING) } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct InstructionBasedSamplingCapabilitiesEax: u32 { const IBSFFV = 1 << 0; const FETCH_SAM = 1 << 1; const OP_SAM = 1 << 2; const RD_WR_OP_CNT = 1 << 3; const OP_CNT = 1 << 4; const BRN_TRGT = 1 << 5; const OP_CNT_EXT = 1 << 6; const RIP_INVALID_CHK = 1 << 7; const OP_BRN_FUSE = 1 << 8; const IBS_L3_MISS_FILTERING = 1 << 11; } } /// Processor Topology Information (LEAF=0x8000_001E). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq)] pub struct ProcessorTopologyInfo { eax: u32, ebx: u32, ecx: u32, /// Reserved _edx: u32, } impl ProcessorTopologyInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, ecx: data.ecx, _edx: data.edx, } } /// x2APIC ID pub fn x2apic_id(&self) -> u32 { self.eax } /// Core ID /// /// # Note /// `Core ID` means `Compute Unit ID` if AMD Family 15h-16h Processors. pub fn core_id(&self) -> u8 { get_bits(self.ebx, 0, 7) as u8 } /// Threads per core /// /// # Note /// `Threads per Core` means `Cores per Compute Unit` if AMD Family 15h-16h Processors. pub fn threads_per_core(&self) -> u8 { get_bits(self.ebx, 8, 15) as u8 + 1 } /// Node ID pub fn node_id(&self) -> u8 { get_bits(self.ecx, 0, 7) as u8 } /// Nodes per processor pub fn nodes_per_processor(&self) -> u8 { get_bits(self.ecx, 8, 10) as u8 + 1 } } impl Debug for ProcessorTopologyInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("ProcessorTopologyInfo") .field("x2apic_id", &self.x2apic_id()) .field("core_id", &self.core_id()) .field("threads_per_core", &self.threads_per_core()) .field("node_id", &self.node_id()) .field("nodes_per_processor", &self.nodes_per_processor()) .finish() } } /// Encrypted Memory Capabilities (LEAF=0x8000_001F). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(Debug, PartialEq, Eq)] pub struct MemoryEncryptionInfo { eax: MemoryEncryptionInfoEax, ebx: u32, ecx: u32, edx: u32, } impl MemoryEncryptionInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: MemoryEncryptionInfoEax::from_bits_truncate(data.eax), ebx: data.ebx, ecx: data.ecx, edx: data.edx, } } /// Secure Memory Encryption is supported if set. pub fn has_sme(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::SME) } /// Secure Encrypted Virtualization is supported if set. pub fn has_sev(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::SEV) } /// The Page Flush MSR is available if set. pub fn has_page_flush_msr(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::PAGE_FLUSH_MSR) } /// SEV Encrypted State is supported if set. pub fn has_sev_es(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::SEV_ES) } /// SEV Secure Nested Paging supported if set. pub fn has_sev_snp(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::SEV_SNP) } /// VM Permission Levels supported if set. pub fn has_vmpl(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::VMPL) } /// Hardware cache coherency across encryption domains enforced if set. pub fn has_hw_enforced_cache_coh(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::HWENFCACHECOH) } /// SEV guest execution only allowed from a 64-bit host if set. pub fn has_64bit_mode(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::HOST64) } /// Restricted Injection supported if set. pub fn has_restricted_injection(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::RESTINJECT) } /// Alternate Injection supported if set. pub fn has_alternate_injection(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::ALTINJECT) } /// Full debug state swap supported for SEV-ES guests. pub fn has_debug_swap(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::DBGSWP) } /// Disallowing IBS use by the host supported if set. pub fn has_prevent_host_ibs(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::PREVHOSTIBS) } /// Virtual Transparent Encryption supported if set. pub fn has_vte(&self) -> bool { self.eax.contains(MemoryEncryptionInfoEax::VTE) } /// C-bit location in page table entry pub fn c_bit_position(&self) -> u8 { get_bits(self.ebx, 0, 5) as u8 } /// Physical Address bit reduction pub fn physical_address_reduction(&self) -> u8 { get_bits(self.ebx, 6, 11) as u8 } /// Number of encrypted guests supported simultaneouslys pub fn max_encrypted_guests(&self) -> u32 { self.ecx } /// Minimum ASID value for an SEV enabled, SEV-ES disabled guest pub fn min_sev_no_es_asid(&self) -> u32 { self.edx } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct MemoryEncryptionInfoEax: u32 { const SME = 1 << 0; const SEV = 1 << 1; const PAGE_FLUSH_MSR = 1 << 2; const SEV_ES = 1 << 3; const SEV_SNP = 1 << 4; const VMPL = 1 << 5; const HWENFCACHECOH = 1 << 10; const HOST64 = 1 << 11; const RESTINJECT = 1 << 12; const ALTINJECT = 1 << 13; const DBGSWP = 1 << 14; const PREVHOSTIBS = 1 << 15; const VTE = 1 << 16; } } /// Platform Quality of Service Information (LEAF=0x8000_0020). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq)] pub struct PqosExtendedFeatureInfo { read: R, _eax: u32, ebx: PqosExtendedFeatureInfoEbx, _ecx: u32, _edx: u32, } impl PqosExtendedFeatureInfo { pub(crate) fn new(read: R) -> Self { let data = read.cpuid2(EAX_PQOS_EXTENDED_FEATURES, 0); Self { read, _eax: data.eax, ebx: PqosExtendedFeatureInfoEbx::from_bits_truncate(data.ebx), _ecx: data.ecx, _edx: data.edx, } } /// Memory Bandwidth Enforcement is supported if set. pub fn has_l3mbe(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::L3MBE) } /// Slow Memory Bandwidth Enforcement is supported if set. pub fn has_l3smbe(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::L3SMBE) } /// Bandwidth Monitoring Event Configuration is supported if set. pub fn has_bmec(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::BMEC) } /// L3 Range Reservations. See ā€œL3 Range Reservationā€ in APM /// Volume 2 is supported if set. pub fn has_l3rr(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::L3RR) } /// Assignable Bandwidth Monitoring Counters is supported if set. pub fn has_abmc(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::ABMC) } /// Smart Data Cache Injection (SDCI) Allocation Enforcement is supported if set. pub fn has_sdciae(&self) -> bool { self.ebx.contains(PqosExtendedFeatureInfoEbx::SDCIAE) } /// Get L3 Memory Bandwidth Enforcement Information pub fn get_l3_memory_bandwidth_enforcement_info( &self, ) -> Option { if self.has_l3mbe() { Some(L3MemoryBandwidthEnforcementInformation::new( self.read.cpuid2(EAX_PQOS_EXTENDED_FEATURES, 1), )) } else { None } } /// Get L3 Slow Memory Bandwidth Enforcement Information pub fn get_l3_slow_memory_bandwidth_enforcement_info( &self, ) -> Option { if self.has_l3smbe() { Some(L3MemoryBandwidthEnforcementInformation::new( self.read.cpuid2(EAX_PQOS_EXTENDED_FEATURES, 2), )) } else { None } } /// Get Bandwidth Monitoring Event Counters Information pub fn get_bandwidth_monitoring_event_counters_info( &self, ) -> Option { if self.has_bmec() { Some(BandwidthMonitoringEventCounters::new( self.read.cpuid2(EAX_PQOS_EXTENDED_FEATURES, 3), )) } else { None } } /// Get Bandwidth Monitoring Event Counters Information pub fn get_assignable_bandwidth_monitoring_counters_info( &self, ) -> Option { if self.has_abmc() { Some(AssignableBandwidthMonitoringCounterInfo::new( self.read.cpuid2(EAX_PQOS_EXTENDED_FEATURES, 5), )) } else { None } } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct PqosExtendedFeatureInfoEbx: u32 { const L3MBE = 1 << 1; const L3SMBE = 1 << 2; const BMEC = 1 << 3; const L3RR = 1 << 4; const ABMC = 1 << 5; const SDCIAE = 1 << 6; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct PqosExtendedFeatureInfoEbx5: u32 { const SELECT_COS = 1 << 0; } } impl Debug for PqosExtendedFeatureInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("PqosExtendedFeatureInfo") .field("has_l3mbe", &self.has_l3mbe()) .field("has_l3smbe", &self.has_l3smbe()) .field("has_bmec", &self.has_bmec()) .field("has_l3rr", &self.has_l3rr()) .field("has_abmc", &self.has_abmc()) .field("has_sdciae", &self.has_sdciae()) .finish() } } /// L3 Memory Bandwidth Enforcement Information (LEAF=0x8000_0020_x1 and x2). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct L3MemoryBandwidthEnforcementInformation { eax: u32, _ebx: u32, _ecx: u32, edx: u32, } impl L3MemoryBandwidthEnforcementInformation { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, _ebx: data.ebx, _ecx: data.ecx, edx: data.edx, } } /// Identifies the size of the bandwidth specifier field in the /// L3QOS_BW_Control_n MSRs pub fn bandwidth_length(&self) -> u32 { self.eax } /// Maximum COS number supported by the L3MBE feature pub fn cos_max(&self) -> u32 { self.edx } } /// Bandwidth Monitoring Event Counters Information (LEAF=0x8000_0020_x3). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct BandwidthMonitoringEventCounters { _eax: u32, ebx: u32, ecx: BandwidthMonitoringEventCountersEcx, _edx: u32, } impl BandwidthMonitoringEventCounters { pub(crate) fn new(data: CpuIdResult) -> Self { Self { _eax: data.eax, ebx: data.ebx, ecx: BandwidthMonitoringEventCountersEcx::from_bits_truncate(data.ecx), _edx: data.edx, } } /// Get Number of configurable bandwidth events pub fn number_events(&self) -> u32 { get_bits(self.ebx, 0, 7) } /// Reads to local DRAM memory is supported if set. pub fn has_l3_cache_lcl_bw_fill_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_LCL_BW_FILL_MON) } /// Reads to remote DRAM memory is supported if set. pub fn has_l3_cache_rmt_bw_fill_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_RMT_BW_FILL_MON) } /// Non-temporal writes to local memory is supported if set. pub fn has_l3_cache_lcl_bw_nt_wr_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_LCL_BW_NT_WR_MON) } /// Non-temporal writes to remote memory is supported if set. pub fn has_l3_cache_rmt_bw_nt_wr_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_RMT_BW_NT_WR_MON) } /// Reads to local memory identified as ā€œSlow Memoryā€ is supported if set. pub fn has_l3_cache_lcl_slow_bw_fill_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_LCL_SLOW_BW_FILL_MON) } /// Reads to remote memory identified as ā€œSlow Memoryā€ is supported if set. pub fn has_l3_cache_rmt_slow_bw_fill_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_RMT_SLOW_BW_FILL_MON) } /// Dirty victim writes to all types of memory is supported if set. pub fn has_l3_cache_vic_mon(&self) -> bool { self.ecx .contains(BandwidthMonitoringEventCountersEcx::L3_CACHE_VIC_MON) } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct BandwidthMonitoringEventCountersEcx: u32 { const L3_CACHE_LCL_BW_FILL_MON = 1 << 0; const L3_CACHE_RMT_BW_FILL_MON = 1 << 1; const L3_CACHE_LCL_BW_NT_WR_MON = 1 << 2; const L3_CACHE_RMT_BW_NT_WR_MON = 1 << 3; const L3_CACHE_LCL_SLOW_BW_FILL_MON = 1 << 4; const L3_CACHE_RMT_SLOW_BW_FILL_MON = 1 << 5; const L3_CACHE_VIC_MON = 1 << 6; } } /// L3 Memory Bandwidth Enforcement Information (LEAF=0x8000_0020_x5). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct AssignableBandwidthMonitoringCounterInfo { eax: u32, ebx: u32, ecx: u32, _edx: u32, } impl AssignableBandwidthMonitoringCounterInfo { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, ecx: data.ecx, _edx: data.edx, } } /// Get QM_CTR counter width, offset from 24 bits pub fn counter_size(&self) -> u8 { get_bits(self.eax, 0, 7) as u8 } /// Indicates that QM_CTR bit 61 is an overflow bit if set pub fn has_overflow_bit(&self) -> bool { (self.eax & (1 << 8)) > 0 } /// Get Maximum supported ABMC counter ID pub fn max_abmc(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } /// Bandwidth counters can be configured to measure /// bandwidth consumed by a COS instead of an RMID if set pub fn has_select_cos(&self) -> bool { (self.ecx & 1) > 0 } } /// Extended Feature Identification 2 (LEAF=0x8000_0021). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct ExtendedFeatureIdentification2 { eax: ExtendedFeatureIdentification2Eax, ebx: u32, _ecx: u32, _edx: u32, } impl ExtendedFeatureIdentification2 { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: ExtendedFeatureIdentification2Eax::from_bits_truncate(data.eax), ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// Processor ignores nested data breakpoints if set pub fn has_no_nested_data_bp(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::NO_NESTED_DATA_BP) } /// LFENCE is always dispatch serializing if set pub fn has_lfence_always_serializing(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::LFENCE_ALWAYS_SERIALIZING) } /// SMM paging configuration lock supported if set pub fn has_smm_pg_cfg_lock(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::SMM_PG_CFG_LOCK) } /// Null segment selector loads also clear the destination segment register /// base and limit supported if set pub fn has_null_select_clears_base(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::NULL_SELECT_CLEARS_BASE) } /// Upper Address Ignore is supported if set pub fn has_upper_address_ignore(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::UPPER_ADDRESS_IGNORE) } /// Automatic IBRS if set pub fn has_automatic_ibrs(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::AUTOMATIC_IBRS) } /// SMM_CTL MSR (C001_0116h) is not supported if set pub fn has_no_smm_ctl_msr(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::NO_SMM_CTL_MSR) } /// Prefetch control MSR supported if set pub fn has_prefetch_ctl_msr(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::PREFETCH_CTL_MSR) } /// CPUID disable for non-privileged software if set pub fn has_cpuid_user_dis(&self) -> bool { self.eax .contains(ExtendedFeatureIdentification2Eax::CPUID_USER_DIS) } /// The size of the Microcode patch in 16-byte multiples. If 0, the size of the /// patch is at most 5568 (15C0h) bytes. pub fn microcode_patch_size(&self) -> u16 { get_bits(self.ebx, 0, 11) as u16 } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeatureIdentification2Eax: u32 { const NO_NESTED_DATA_BP = 1 << 0; const LFENCE_ALWAYS_SERIALIZING = 1 << 2; const SMM_PG_CFG_LOCK = 1 << 3; const NULL_SELECT_CLEARS_BASE = 1 << 6; const UPPER_ADDRESS_IGNORE = 1 << 7; const AUTOMATIC_IBRS = 1 << 8; const NO_SMM_CTL_MSR = 1 << 9; const PREFETCH_CTL_MSR = 1 << 13; const CPUID_USER_DIS = 1 << 17; } } /// Extended Performance Monitoring and Debug (LEAF=0x8000_0022). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct ExtendedPerformanceMonitoringDebug { eax: ExtendedPerformanceMonitoringDebugEax, ebx: u32, _ecx: u32, _edx: u32, } impl ExtendedPerformanceMonitoringDebug { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: ExtendedPerformanceMonitoringDebugEax::from_bits_truncate(data.eax), ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// Performance Monitoring Version 2 supported if set pub fn has_perf_mon_v2(&self) -> bool { self.eax .contains(ExtendedPerformanceMonitoringDebugEax::PERF_MON_V2) } /// Last Branch Record Stack supported if set pub fn has_lbr_stack(&self) -> bool { self.eax .contains(ExtendedPerformanceMonitoringDebugEax::LBR_STACK) } /// Freezing Core Performance Counters and LBR Stack on Core /// Performance Counter overflow supported if set pub fn has_lbr_and_pmc_freeze(&self) -> bool { self.eax .contains(ExtendedPerformanceMonitoringDebugEax::LBR_AND_PMC_FREEZE) } /// Number of Core Performance Counters pub fn num_perf_ctr_core(&self) -> u8 { get_bits(self.ebx, 0, 3) as u8 } /// Number of Last Branch Record Stack entries pub fn num_lbr_stack_size(&self) -> u8 { get_bits(self.ebx, 4, 9) as u8 } /// Number of Northbridge Performance Monitor Counters pub fn num_perf_ctr_nb(&self) -> u8 { get_bits(self.ebx, 10, 15) as u8 } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedPerformanceMonitoringDebugEax: u32 { const PERF_MON_V2 = 1 << 0; const LBR_STACK = 1 << 1; const LBR_AND_PMC_FREEZE = 1 << 2; } } /// Multi-Key Encrypted Memory Capabilities (LEAF=0x8000_0023). /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(PartialEq, Eq, Debug)] pub struct MultiKeyEncryptedMemoryCapabilities { eax: MultiKeyEncryptedMemoryCapabilitiesEax, ebx: u32, _ecx: u32, _edx: u32, } impl MultiKeyEncryptedMemoryCapabilities { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: MultiKeyEncryptedMemoryCapabilitiesEax::from_bits_truncate(data.eax), ebx: data.ebx, _ecx: data.ecx, _edx: data.edx, } } /// Secure Host Multi-Key Memory (MEM-HMK) Encryption Mode Supported if set pub fn has_mem_hmk(&self) -> bool { self.eax .contains(MultiKeyEncryptedMemoryCapabilitiesEax::MEM_HMK) } /// Number of simultaneously available host encryption key IDs in MEM-HMK /// encryption mode. pub fn max_mem_hmk_encr_key_id(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct MultiKeyEncryptedMemoryCapabilitiesEax: u32 { const MEM_HMK = 1 << 0; } } /// Extended CPU Topology (LEAF=0x8000_0026). /// /// Iterates over the extended cpu topology in order to retrieve more information for logical /// processors, including asymmetric and heterogenous topology descriptions. Individual /// logical processors may report different values in systems with asynchronous and /// heterogeneous topologies /// /// # Platforms /// āœ… AMD āŒ Intel #[derive(Clone)] pub struct ExtendedCpuTopologyIter { read: R, level: u32, } impl ExtendedCpuTopologyIter { pub fn new(read: R) -> Self { Self { read, level: 0 } } } /// Gives information about the current level in the cpu topology. #[derive(PartialEq, Eq, Debug)] pub struct ExtendedCpuTopologyLevel { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl ExtendedCpuTopologyLevel { pub(crate) fn new(data: CpuIdResult) -> Self { Self { eax: data.eax, ebx: data.ebx, ecx: data.ecx, edx: data.edx, } } /// Number of bits to shift Extended APIC ID right to get a unique topology ID /// of the current hierarchy level. pub fn mask_width(&self) -> u8 { get_bits(self.eax, 0, 4) as u8 } /// Set to 1 if processor power efficiency ranking (PwrEfficiencyRanking) is /// available and varies between cores. Only valid for LevelType = 1h (Core). pub fn has_efficiency_ranking_available(&self) -> bool { self.eax & (1 << 29) > 0 } /// Set to 1 if all components at the current hierarchy level do not consist of /// the cores that report the same core type (CoreType). pub fn has_heterogeneous_cores(&self) -> bool { self.eax & (1 << 30) > 0 } /// Set to 1 if all components at the current hierarchy level do not report the /// same number of logical processors (NumLogProc). pub fn has_asymmetric_topology(&self) -> bool { self.eax & (1 << 31) > 0 } /// Number of logical processors at the current hierarchy level pub fn num_logical_processors(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } /// Reports a static efficiency ranking between cores of a specific core type, /// where a lower value indicates comparatively lower power consumption /// and lower performance. Only valid for LevelType = 1h (Core) pub fn pwr_efficiency_ranking(&self) -> u8 { get_bits(self.ebx, 16, 23) as u8 } /// Reports a value that may be used to further differentiate implementation /// specific features. Native mode ID is used in conjunction with the family, /// model, and stepping identifiers. Refer to the Processor Programming /// Reference Manual applicable to your product for a list of Native Mode /// IDs. Only valid for LevelType = 1h (Core) pub fn native_mode_id(&self) -> u8 { get_bits(self.ebx, 24, 27) as u8 } /// Reports a value that may be used to distinguish between cores with /// different architectural and microarchitectural properties (for example, /// cores with different performance or power characteristics). Refer to the /// Processor Programming Reference Manual applicable to your product for /// a list of the available core types. Only valid for LevelType = 1h (Core) pub fn core_type(&self) -> u8 { get_bits(self.ebx, 28, 31) as u8 } /// Input ECX pub fn input_ecx(&self) -> u8 { get_bits(self.ecx, 0, 7) as u8 } /// Encoded hierarchy level type pub fn level_type(&self) -> HierarchyLevelType { HierarchyLevelType::from(get_bits(self.ecx, 8, 15) as u8) } /// Extended APIC ID of the logical processor pub fn extended_apic_id(&self) -> u32 { self.edx } } impl Iterator for ExtendedCpuTopologyIter { type Item = ExtendedCpuTopologyLevel; fn next(&mut self) -> Option { let res = self.read.cpuid2(EAX_EXTENDED_CPU_TOPOLOGY, self.level); self.level += 1; let ect = ExtendedCpuTopologyLevel::new(res); if ect.level_type() == HierarchyLevelType::Reserved { None } else { Some(ect) } } } #[repr(u8)] #[derive(PartialEq, Eq)] pub enum HierarchyLevelType { Reserved = 0, Core = 1, Complex = 2, Die = 3, Socket = 4, Unknown(u8), } impl From for HierarchyLevelType { fn from(value: u8) -> Self { match value { 0 => Self::Reserved, 1 => Self::Core, 2 => Self::Complex, 3 => Self::Die, 4 => Self::Socket, x => Self::Unknown(x), } } } impl Display for HierarchyLevelType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { HierarchyLevelType::Reserved => write!(f, "Reserved (0)"), HierarchyLevelType::Core => write!(f, "Core (1)"), HierarchyLevelType::Complex => write!(f, "Complex (2)"), HierarchyLevelType::Die => write!(f, "DIE (3)"), HierarchyLevelType::Socket => write!(f, "Socket (4)"), HierarchyLevelType::Unknown(x) => write!(f, "Unknown ({x})"), } } } impl Debug for HierarchyLevelType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Reserved => write!(f, "Reserved"), Self::Core => write!(f, "Core"), Self::Complex => write!(f, "Complex"), Self::Die => write!(f, "Die"), Self::Socket => write!(f, "Socket"), Self::Unknown(arg0) => f.debug_tuple("Unknown").field(arg0).finish(), } } } raw-cpuid-11.6.0/src/lib.rs000064400000000000000000006006641046102023000135230ustar 00000000000000//! A library to parse the x86 CPUID instruction, written in rust with no //! external dependencies. The implementation closely resembles the Intel CPUID //! manual description. The library works with no_std. //! //! ## Example //! ```rust //! use raw_cpuid::CpuId; //! let cpuid = CpuId::new(); //! //! if let Some(vf) = cpuid.get_vendor_info() { //! assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD"); //! } //! //! let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse()); //! if has_sse { //! println!("CPU supports SSE!"); //! } //! //! if let Some(cparams) = cpuid.get_cache_parameters() { //! for cache in cparams { //! let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets(); //! println!("L{}-Cache size is {}", cache.level(), size); //! } //! } else { //! println!("No cache parameter information available") //! } //! ``` //! //! # Platform support //! //! CPU vendors may choose to not support certain functions/leafs in cpuid or //! only support them partially. We highlight this with the following emojis //! throughout the documentation: //! //! - āœ…: This struct/function is fully supported by the vendor. //! - 🟔: This struct is partially supported by the vendor, refer to individual //! functions for more information. //! - āŒ: This struct/function is not supported by the vendor. When queried on //! this platform, we will return None/false/0 (or some other sane default). //! - ā“: This struct/function is not supported by the vendor according to the //! manual, but the in practice it still may return valid information. //! //! Note that the presence of a āœ… does not guarantee that a specific feature //! will exist for your CPU -- just that it is potentially supported by the //! vendor on some of its chips. You will still have to query it at runtime. #![cfg_attr(not(feature = "std"), no_std)] #![crate_name = "raw_cpuid"] #![crate_type = "lib"] #[cfg(test)] #[macro_use] extern crate std; #[cfg(feature = "display")] pub mod display; mod extended; #[cfg(test)] mod tests; use bitflags::bitflags; use core::fmt::{self, Debug, Formatter}; use core::mem::size_of; use core::slice; use core::str; #[cfg(feature = "serialize")] use serde_derive::{Deserialize, Serialize}; pub use extended::*; /// Uses Rust's `cpuid` function from the `arch` module. #[cfg(any( all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), all(target_arch = "x86_64", not(target_env = "sgx")) ))] pub mod native_cpuid { use crate::CpuIdResult; #[cfg(all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"))] use core::arch::x86 as arch; #[cfg(all(target_arch = "x86_64", not(target_env = "sgx")))] use core::arch::x86_64 as arch; pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult { // Safety: CPUID is supported on all x86_64 CPUs and all x86 CPUs with // SSE, but not by SGX. let result = unsafe { self::arch::__cpuid_count(a, c) }; CpuIdResult { eax: result.eax, ebx: result.ebx, ecx: result.ecx, edx: result.edx, } } /// The native reader uses the cpuid instruction to read the cpuid data from the /// CPU we're currently running on directly. #[derive(Clone, Copy)] pub struct CpuIdReaderNative; impl super::CpuIdReader for CpuIdReaderNative { fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult { cpuid_count(eax, ecx) } } } #[cfg(any( all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), all(target_arch = "x86_64", not(target_env = "sgx")) ))] pub use native_cpuid::CpuIdReaderNative; /// Macro which queries cpuid directly. /// /// First parameter is cpuid leaf (EAX register value), /// second optional parameter is the subleaf (ECX register value). #[cfg(any( all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), all(target_arch = "x86_64", not(target_env = "sgx")) ))] #[macro_export] macro_rules! cpuid { ($eax:expr) => { $crate::native_cpuid::cpuid_count($eax as u32, 0) }; ($eax:expr, $ecx:expr) => { $crate::native_cpuid::cpuid_count($eax as u32, $ecx as u32) }; } fn get_bits(r: u32, from: u32, to: u32) -> u32 { assert!(from <= 31); assert!(to <= 31); assert!(from <= to); let mask = match to { 31 => 0xffffffff, _ => (1 << (to + 1)) - 1, }; (r & mask) >> from } macro_rules! check_flag { ($doc:meta, $fun:ident, $flags:ident, $flag:expr) => { #[$doc] pub fn $fun(&self) -> bool { self.$flags.contains($flag) } }; } macro_rules! is_bit_set { ($field:expr, $bit:expr) => { $field & (1 << $bit) > 0 }; } macro_rules! check_bit_fn { ($doc:meta, $fun:ident, $field:ident, $bit:expr) => { #[$doc] pub fn $fun(&self) -> bool { is_bit_set!(self.$field, $bit) } }; } /// Implements function to read/write cpuid. /// This allows to conveniently swap out the underlying cpuid implementation /// with one that returns data that is deterministic (for unit-testing). pub trait CpuIdReader: Clone { fn cpuid1(&self, eax: u32) -> CpuIdResult { self.cpuid2(eax, 0) } fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult; } impl CpuIdReader for F where F: Fn(u32, u32) -> CpuIdResult + Clone, { fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult { self(eax, ecx) } } #[derive(Debug, Eq, PartialEq, Clone, Copy)] enum Vendor { Intel, Amd, Unknown(u32, u32, u32), } impl Vendor { fn from_vendor_leaf(res: CpuIdResult) -> Self { let vi = VendorInfo { ebx: res.ebx, ecx: res.ecx, edx: res.edx, }; match vi.as_str() { "GenuineIntel" => Vendor::Intel, "AuthenticAMD" | "HygonGenuine" => Vendor::Amd, _ => Vendor::Unknown(res.ebx, res.ecx, res.edx), } } } /// The main type used to query information about the CPU we're running on. /// /// Other structs can be accessed by going through this type. #[derive(Clone, Copy)] pub struct CpuId { /// A generic reader to abstract the cpuid interface. read: R, /// CPU vendor to differentiate cases where logic needs to differ in code . vendor: Vendor, /// How many basic leafs are supported (EAX < EAX_HYPERVISOR_INFO) supported_leafs: u32, /// How many extended leafs are supported (e.g., leafs with EAX > EAX_EXTENDED_FUNCTION_INFO) supported_extended_leafs: u32, } #[cfg(any( all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), all(target_arch = "x86_64", not(target_env = "sgx")) ))] impl Default for CpuId { /// Create a new `CpuId` instance. fn default() -> Self { CpuId::with_cpuid_fn(CpuIdReaderNative) } } #[cfg(any( all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), all(target_arch = "x86_64", not(target_env = "sgx")) ))] impl CpuId { /// Create a new `CpuId` instance. pub fn new() -> Self { CpuId::default() } } /// Low-level data-structure to store result of cpuid instruction. #[derive(Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[repr(C)] pub struct CpuIdResult { /// Return value EAX register pub eax: u32, /// Return value EBX register pub ebx: u32, /// Return value ECX register pub ecx: u32, /// Return value EDX register pub edx: u32, } impl CpuIdResult { pub fn all_zero(&self) -> bool { self.eax == 0 && self.ebx == 0 && self.ecx == 0 && self.edx == 0 } } impl Debug for CpuIdResult { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("CpuIdResult") .field("eax", &(self.eax as *const u32)) .field("ebx", &(self.ebx as *const u32)) .field("ecx", &(self.ecx as *const u32)) .field("edx", &(self.edx as *const u32)) .finish() } } // // Normal leafs: // const EAX_VENDOR_INFO: u32 = 0x0; const EAX_FEATURE_INFO: u32 = 0x1; const EAX_CACHE_INFO: u32 = 0x2; const EAX_PROCESSOR_SERIAL: u32 = 0x3; const EAX_CACHE_PARAMETERS: u32 = 0x4; const EAX_MONITOR_MWAIT_INFO: u32 = 0x5; const EAX_THERMAL_POWER_INFO: u32 = 0x6; const EAX_STRUCTURED_EXTENDED_FEATURE_INFO: u32 = 0x7; const EAX_DIRECT_CACHE_ACCESS_INFO: u32 = 0x9; const EAX_PERFORMANCE_MONITOR_INFO: u32 = 0xA; const EAX_EXTENDED_TOPOLOGY_INFO: u32 = 0xB; const EAX_EXTENDED_STATE_INFO: u32 = 0xD; const EAX_RDT_MONITORING: u32 = 0xF; const EAX_RDT_ALLOCATION: u32 = 0x10; const EAX_SGX: u32 = 0x12; const EAX_TRACE_INFO: u32 = 0x14; const EAX_TIME_STAMP_COUNTER_INFO: u32 = 0x15; const EAX_FREQUENCY_INFO: u32 = 0x16; const EAX_SOC_VENDOR_INFO: u32 = 0x17; const EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO: u32 = 0x18; const EAX_EXTENDED_TOPOLOGY_INFO_V2: u32 = 0x1F; /// Hypervisor leaf const EAX_HYPERVISOR_INFO: u32 = 0x4000_0000; // // Extended leafs: // const EAX_EXTENDED_FUNCTION_INFO: u32 = 0x8000_0000; const EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS: u32 = 0x8000_0001; const EAX_EXTENDED_BRAND_STRING: u32 = 0x8000_0002; const EAX_L1_CACHE_INFO: u32 = 0x8000_0005; const EAX_L2_L3_CACHE_INFO: u32 = 0x8000_0006; const EAX_ADVANCED_POWER_MGMT_INFO: u32 = 0x8000_0007; const EAX_PROCESSOR_CAPACITY_INFO: u32 = 0x8000_0008; const EAX_TLB_1GB_PAGE_INFO: u32 = 0x8000_0019; const EAX_PERFORMANCE_OPTIMIZATION_INFO: u32 = 0x8000_001A; const EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES: u32 = 0x8000_001B; const EAX_CACHE_PARAMETERS_AMD: u32 = 0x8000_001D; const EAX_PROCESSOR_TOPOLOGY_INFO: u32 = 0x8000_001E; const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F; const EAX_SVM_FEATURES: u32 = 0x8000_000A; const EAX_PQOS_EXTENDED_FEATURES: u32 = 0x8000_0020; const EAX_EXTENDED_FEATURE_IDENTIFICATION_2: u32 = 0x8000_0021; const EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG: u32 = 0x8000_0022; const EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES: u32 = 0x8000_0023; const EAX_EXTENDED_CPU_TOPOLOGY: u32 = 0x8000_0026; impl CpuId { /// Return new CpuId struct with custom reader function. /// /// This is useful for example when testing code or if we want to interpose /// on the CPUID calls this library makes. pub fn with_cpuid_reader(cpuid_fn: R) -> Self { let vendor_leaf = cpuid_fn.cpuid1(EAX_VENDOR_INFO); let extended_leaf = cpuid_fn.cpuid1(EAX_EXTENDED_FUNCTION_INFO); CpuId { supported_leafs: vendor_leaf.eax, supported_extended_leafs: extended_leaf.eax, vendor: Vendor::from_vendor_leaf(vendor_leaf), read: cpuid_fn, } } /// See [`CpuId::with_cpuid_reader`]. /// /// # Note /// This function will likely be deprecated in the future. Use the identical /// `with_cpuid_reader` function instead. pub fn with_cpuid_fn(cpuid_fn: R) -> Self { CpuId::with_cpuid_reader(cpuid_fn) } /// Check if a non extended leaf (`val`) is supported. fn leaf_is_supported(&self, val: u32) -> bool { // Exclude reserved functions/leafs on AMD if self.vendor == Vendor::Amd && ((0x2..=0x4).contains(&val) || (0x8..=0xa).contains(&val)) { return false; } if val < EAX_EXTENDED_FUNCTION_INFO { val <= self.supported_leafs } else { val <= self.supported_extended_leafs } } /// Return information about the vendor (LEAF=0x00). /// /// This leaf will contain a ASCII readable string such as "GenuineIntel" /// for Intel CPUs or "AuthenticAMD" for AMD CPUs. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn get_vendor_info(&self) -> Option { if self.leaf_is_supported(EAX_VENDOR_INFO) { let res = self.read.cpuid1(EAX_VENDOR_INFO); Some(VendorInfo { ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } /// Query a set of features that are available on this CPU (LEAF=0x01). /// /// # Platforms /// āœ… AMD āœ… Intel pub fn get_feature_info(&self) -> Option { if self.leaf_is_supported(EAX_FEATURE_INFO) { let res = self.read.cpuid1(EAX_FEATURE_INFO); Some(FeatureInfo { vendor: self.vendor, eax: res.eax, ebx: res.ebx, edx_ecx: FeatureInfoFlags::from_bits_truncate( ((res.edx as u64) << 32) | (res.ecx as u64), ), }) } else { None } } /// Query basic information about caches (LEAF=0x02). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_cache_info(&self) -> Option { if self.leaf_is_supported(EAX_CACHE_INFO) { let res = self.read.cpuid1(EAX_CACHE_INFO); Some(CacheInfoIter { current: 1, eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } /// Retrieve serial number of processor (LEAF=0x03). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_processor_serial(&self) -> Option { if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) { // upper 64-96 bits are in res1.eax: let res1 = self.read.cpuid1(EAX_FEATURE_INFO); let res = self.read.cpuid1(EAX_PROCESSOR_SERIAL); Some(ProcessorSerial { ecx: res.ecx, edx: res.edx, eax: res1.eax, }) } else { None } } /// Retrieve more elaborate information about caches (LEAF=0x04 or 0x8000_001D). /// /// As opposed to [get_cache_info](CpuId::get_cache_info), this will tell us /// about associativity, set size, line size of each level in the cache /// hierarchy. /// /// # Platforms /// 🟔 AMD āœ… Intel pub fn get_cache_parameters(&self) -> Option> { if self.leaf_is_supported(EAX_CACHE_PARAMETERS) || (self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_CACHE_PARAMETERS_AMD)) { Some(CacheParametersIter { read: self.read.clone(), leaf: if self.vendor == Vendor::Amd { EAX_CACHE_PARAMETERS_AMD } else { EAX_CACHE_PARAMETERS }, current: 0, }) } else { None } } /// Information about how monitor/mwait works on this CPU (LEAF=0x05). /// /// # Platforms /// 🟔 AMD āœ… Intel pub fn get_monitor_mwait_info(&self) -> Option { if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) { let res = self.read.cpuid1(EAX_MONITOR_MWAIT_INFO); Some(MonitorMwaitInfo { eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } /// Query information about thermal and power management features of the CPU (LEAF=0x06). /// /// # Platforms /// 🟔 AMD āœ… Intel pub fn get_thermal_power_info(&self) -> Option { if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) { let res = self.read.cpuid1(EAX_THERMAL_POWER_INFO); Some(ThermalPowerInfo { eax: ThermalPowerFeaturesEax::from_bits_truncate(res.eax), ebx: res.ebx, ecx: ThermalPowerFeaturesEcx::from_bits_truncate(res.ecx), _edx: res.edx, }) } else { None } } /// Find out about more features supported by this CPU (LEAF=0x07). /// /// # Platforms /// 🟔 AMD āœ… Intel pub fn get_extended_feature_info(&self) -> Option { if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) { let res = self.read.cpuid1(EAX_STRUCTURED_EXTENDED_FEATURE_INFO); let res1 = self.read.cpuid2(EAX_STRUCTURED_EXTENDED_FEATURE_INFO, 1); Some(ExtendedFeatures { _eax: res.eax, ebx: ExtendedFeaturesEbx::from_bits_truncate(res.ebx), ecx: ExtendedFeaturesEcx::from_bits_truncate(res.ecx), edx: ExtendedFeaturesEdx::from_bits_truncate(res.edx), eax1: ExtendedFeaturesEax1::from_bits_truncate(res1.eax), _ebx1: res1.ebx, _ecx1: res1.ecx, edx1: ExtendedFeaturesEdx1::from_bits_truncate(res1.edx), }) } else { None } } /// Direct cache access info (LEAF=0x09). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_direct_cache_access_info(&self) -> Option { if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) { let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO); Some(DirectCacheAccessInfo { eax: res.eax }) } else { None } } /// Info about performance monitoring (LEAF=0x0A). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_performance_monitoring_info(&self) -> Option { if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) { let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO); Some(PerformanceMonitoringInfo { eax: res.eax, ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(res.ebx), _ecx: res.ecx, edx: res.edx, }) } else { None } } /// Information about topology (LEAF=0x0B). /// /// Intel SDM suggests software should check support for leaf 0x1F /// ([`CpuId::get_extended_topology_info_v2`]), and if supported, enumerate /// that leaf instead. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn get_extended_topology_info(&self) -> Option> { if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) { Some(ExtendedTopologyIter { read: self.read.clone(), level: 0, is_v2: false, }) } else { None } } /// Extended information about topology (LEAF=0x1F). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_extended_topology_info_v2(&self) -> Option> { if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) { Some(ExtendedTopologyIter { read: self.read.clone(), level: 0, is_v2: true, }) } else { None } } /// Information for saving/restoring extended register state (LEAF=0x0D). /// /// # Platforms /// āœ… AMD āœ… Intel pub fn get_extended_state_info(&self) -> Option> { if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) { let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0); let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1); Some(ExtendedStateInfo { read: self.read.clone(), eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(res.eax), ebx: res.ebx, ecx: res.ecx, _edx: res.edx, eax1: res1.eax, ebx1: res1.ebx, ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(res1.ecx), _edx1: res1.edx, }) } else { None } } /// Quality of service monitoring information (LEAF=0x0F). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_rdt_monitoring_info(&self) -> Option> { let res = self.read.cpuid1(EAX_RDT_MONITORING); if self.leaf_is_supported(EAX_RDT_MONITORING) { Some(RdtMonitoringInfo { read: self.read.clone(), ebx: res.ebx, edx: res.edx, }) } else { None } } /// Quality of service enforcement information (LEAF=0x10). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_rdt_allocation_info(&self) -> Option> { let res = self.read.cpuid1(EAX_RDT_ALLOCATION); if self.leaf_is_supported(EAX_RDT_ALLOCATION) { Some(RdtAllocationInfo { read: self.read.clone(), ebx: res.ebx, }) } else { None } } /// Information about secure enclave support (LEAF=0x12). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_sgx_info(&self) -> Option> { // Leaf 12H sub-leaf 0 (ECX = 0) is supported if CPUID.(EAX=07H, ECX=0H):EBX[SGX] = 1. self.get_extended_feature_info().and_then(|info| { if self.leaf_is_supported(EAX_SGX) && info.has_sgx() { let res = self.read.cpuid2(EAX_SGX, 0); let res1 = self.read.cpuid2(EAX_SGX, 1); Some(SgxInfo { read: self.read.clone(), eax: res.eax, ebx: res.ebx, _ecx: res.ecx, edx: res.edx, eax1: res1.eax, ebx1: res1.ebx, ecx1: res1.ecx, edx1: res1.edx, }) } else { None } }) } /// Intel Processor Trace Enumeration Information (LEAF=0x14). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_processor_trace_info(&self) -> Option { if self.leaf_is_supported(EAX_TRACE_INFO) { let res = self.read.cpuid2(EAX_TRACE_INFO, 0); let res1 = if res.eax >= 1 { Some(self.read.cpuid2(EAX_TRACE_INFO, 1)) } else { None }; Some(ProcessorTraceInfo { _eax: res.eax, ebx: res.ebx, ecx: res.ecx, _edx: res.edx, leaf1: res1, }) } else { None } } /// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_tsc_info(&self) -> Option { if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) { let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0); Some(TscInfo { eax: res.eax, ebx: res.ebx, ecx: res.ecx, }) } else { None } } /// Processor Frequency Information (LEAF=0x16). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_processor_frequency_info(&self) -> Option { if self.leaf_is_supported(EAX_FREQUENCY_INFO) { let res = self.read.cpuid1(EAX_FREQUENCY_INFO); Some(ProcessorFrequencyInfo { eax: res.eax, ebx: res.ebx, ecx: res.ecx, }) } else { None } } /// Contains SoC vendor specific information (LEAF=0x17). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_soc_vendor_info(&self) -> Option> { if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) { let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO); Some(SoCVendorInfo { read: self.read.clone(), eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } /// Query deterministic address translation feature (LEAF=0x18). /// /// # Platforms /// āŒ AMD āœ… Intel pub fn get_deterministic_address_translation_info(&self) -> Option> { if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) { let res = self .read .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0); Some(DatIter { read: self.read.clone(), current: 0, count: res.eax, }) } else { None } } /// Returns information provided by the hypervisor, if running /// in a virtual environment (LEAF=0x4000_00xx). /// /// # Platform /// Needs to be a virtual CPU to be supported. pub fn get_hypervisor_info(&self) -> Option> { // We only fetch HypervisorInfo, if the Hypervisor-Flag is set. // See https://github.com/gz/rust-cpuid/issues/52 self.get_feature_info() .filter(|fi| fi.has_hypervisor()) .and_then(|_| { let res = self.read.cpuid1(EAX_HYPERVISOR_INFO); if res.eax > 0 { Some(HypervisorInfo { read: self.read.clone(), res, }) } else { None } }) } /// Extended Processor and Processor Feature Identifiers (LEAF=0x8000_0001). /// /// # Platforms /// āœ… AMD 🟔 Intel pub fn get_extended_processor_and_feature_identifiers( &self, ) -> Option { if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) { Some(ExtendedProcessorFeatureIdentifiers::new( self.vendor, self.read .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS), )) } else { None } } /// Retrieve processor brand string (LEAF=0x8000_000{2..4}). /// /// # Platforms /// āœ… AMD āœ… Intel pub fn get_processor_brand_string(&self) -> Option { if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1) && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2) { Some(ProcessorBrandString::new([ self.read.cpuid1(EAX_EXTENDED_BRAND_STRING), self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1), self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2), ])) } else { None } } /// L1 Instruction Cache Information (LEAF=0x8000_0005) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_l1_cache_and_tlb_info(&self) -> Option { if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) { Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO))) } else { None } } /// L2/L3 Cache and TLB Information (LEAF=0x8000_0006). /// /// # Platforms /// āœ… AMD 🟔 Intel pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option { if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) { Some(L2And3CacheTlbInfo::new( self.read.cpuid1(EAX_L2_L3_CACHE_INFO), )) } else { None } } /// Advanced Power Management Information (LEAF=0x8000_0007). /// /// # Platforms /// āœ… AMD 🟔 Intel pub fn get_advanced_power_mgmt_info(&self) -> Option { if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) { Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO))) } else { None } } /// Processor Capacity Parameters and Extended Feature Identification (LEAF=0x8000_0008). /// /// # Platforms /// āœ… AMD 🟔 Intel pub fn get_processor_capacity_feature_info(&self) -> Option { if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) { Some(ProcessorCapacityAndFeatureInfo::new( self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO), )) } else { None } } /// This function provides information about the SVM features that the processor /// supports. (LEAF=0x8000_000A) /// /// If SVM is not supported if [ExtendedProcessorFeatureIdentifiers::has_svm] is /// false, this function is reserved then. /// /// # Platforms /// āœ… AMD āŒ Intel pub fn get_svm_info(&self) -> Option { let has_svm = self .get_extended_processor_and_feature_identifiers() .map_or(false, |f| f.has_svm()); if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) { Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES))) } else { None } } /// TLB 1-GiB Pages Information (LEAF=0x8000_0019) /// /// # Platforms /// āœ… AMD āŒ Intel pub fn get_tlb_1gb_page_info(&self) -> Option { if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) { Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO))) } else { None } } /// Informations about performance optimization (LEAF=0x8000_001A) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_performance_optimization_info(&self) -> Option { if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) { Some(PerformanceOptimizationInfo::new( self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO), )) } else { None } } /// Instruction-Based Sampling Capabilities (LEAF=0x8000_001B) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_instruction_based_sampling_capabilities( &self, ) -> Option { if self.leaf_is_supported(EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES) { Some(InstructionBasedSamplingCapabilities::new( self.read .cpuid1(EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES), )) } else { None } } /// Informations about processor topology (LEAF=0x8000_001E) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_processor_topology_info(&self) -> Option { if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) { Some(ProcessorTopologyInfo::new( self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO), )) } else { None } } /// Informations about memory encryption support (LEAF=0x8000_001F) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_memory_encryption_info(&self) -> Option { if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) { Some(MemoryEncryptionInfo::new( self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO), )) } else { None } } /// Informations about Platform Quality of Service (LEAF=0x8000_0020) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_pqos_extended_feature_info(&self) -> Option> { if self.leaf_is_supported(EAX_PQOS_EXTENDED_FEATURES) { Some(PqosExtendedFeatureInfo::new(self.read.clone())) } else { None } } /// Extended Feature Identification 2 (LEAF=0x8000_0021) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_extended_feature_identification_2(&self) -> Option { if self.leaf_is_supported(EAX_EXTENDED_FEATURE_IDENTIFICATION_2) { Some(ExtendedFeatureIdentification2::new( self.read.cpuid1(EAX_EXTENDED_FEATURE_IDENTIFICATION_2), )) } else { None } } /// Extended Performance Monitoring and Debug (LEAF=0x8000_0022) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_extended_performance_monitoring_and_debug( &self, ) -> Option { if self.leaf_is_supported(EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG) { Some(ExtendedPerformanceMonitoringDebug::new( self.read .cpuid1(EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG), )) } else { None } } /// Multi-Key Encrypted Memory Capabilities (LEAF=0x8000_0023) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_multi_key_encrypted_memory_capabilities( &self, ) -> Option { if self.leaf_is_supported(EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES) { Some(MultiKeyEncryptedMemoryCapabilities::new( self.read .cpuid1(EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES), )) } else { None } } /// Extended CPU Topology (LEAF=0x8000_0026) /// /// # Platforms /// āœ… AMD āŒ Intel (reserved) pub fn get_extended_cpu_topology(&self) -> Option> { if self.leaf_is_supported(EAX_EXTENDED_CPU_TOPOLOGY) { Some(ExtendedCpuTopologyIter::new(self.read.clone())) } else { None } } } impl Debug for CpuId { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("CpuId") .field("vendor", &self.vendor) // .field("supported_leafs", &(self.supported_leafs as *const u32)) // .field("supported_extended_leafs", &(self.supported_extended_leafs as *const u32)) .field("vendor_info", &self.get_vendor_info()) .field("feature_info", &self.get_feature_info()) .field("cache_info", &self.get_cache_info()) .field("processor_serial", &self.get_processor_serial()) .field("cache_parameters", &self.get_cache_parameters()) .field("monitor_mwait_info", &self.get_monitor_mwait_info()) .field("thermal_power_info", &self.get_thermal_power_info()) .field("extended_feature_info", &self.get_extended_feature_info()) .field( "direct_cache_access_info", &self.get_direct_cache_access_info(), ) .field( "performance_monitoring_info", &self.get_performance_monitoring_info(), ) .field("extended_topology_info", &self.get_extended_topology_info()) .field("extended_state_info", &self.get_extended_state_info()) .field("rdt_monitoring_info", &self.get_rdt_monitoring_info()) .field("rdt_allocation_info", &self.get_rdt_allocation_info()) .field("sgx_info", &self.get_sgx_info()) .field("processor_trace_info", &self.get_processor_trace_info()) .field("tsc_info", &self.get_tsc_info()) .field( "processor_frequency_info", &self.get_processor_frequency_info(), ) .field( "deterministic_address_translation_info", &self.get_deterministic_address_translation_info(), ) .field("soc_vendor_info", &self.get_soc_vendor_info()) .field("hypervisor_info", &self.get_hypervisor_info()) .field( "extended_processor_and_feature_identifiers", &self.get_extended_processor_and_feature_identifiers(), ) .field("processor_brand_string", &self.get_processor_brand_string()) .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info()) .field( "l2_l3_cache_and_tlb_info", &self.get_l2_l3_cache_and_tlb_info(), ) .field( "advanced_power_mgmt_info", &self.get_advanced_power_mgmt_info(), ) .field( "processor_capacity_feature_info", &self.get_processor_capacity_feature_info(), ) .field("svm_info", &self.get_svm_info()) .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info()) .field( "performance_optimization_info", &self.get_performance_optimization_info(), ) .field( "processor_topology_info", &self.get_processor_topology_info(), ) .field("memory_encryption_info", &self.get_memory_encryption_info()) .finish() } } /// Vendor Info String (LEAF=0x0) /// /// A string that can be for example "AuthenticAMD" or "GenuineIntel". /// /// # Technical Background /// /// The vendor info is a 12-byte (96 bit) long string stored in `ebx`, `edx` and /// `ecx` by the corresponding `cpuid` instruction. /// /// # Platforms /// āœ… AMD āœ… Intel #[derive(PartialEq, Eq)] #[repr(C)] pub struct VendorInfo { ebx: u32, edx: u32, ecx: u32, } impl VendorInfo { /// Return vendor identification as human readable string. pub fn as_str(&self) -> &str { let brand_string_start = self as *const VendorInfo as *const u8; let slice = unsafe { // Safety: VendorInfo is laid out with repr(C) and exactly // 12 byte long without any padding. slice::from_raw_parts(brand_string_start, size_of::()) }; str::from_utf8(slice).unwrap_or("InvalidVendorString") } #[deprecated( since = "10.0.0", note = "Use idiomatic function name `as_str` instead" )] pub fn as_string(&self) -> &str { self.as_str() } } impl Debug for VendorInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("VendorInfo") .field("brand_string", &self.as_str()) .finish() } } impl fmt::Display for VendorInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.as_str()) } } /// Iterates over cache information (LEAF=0x02). /// /// This will just return an index into a static table of cache descriptions /// (see [CACHE_INFO_TABLE](crate::CACHE_INFO_TABLE)). /// /// # Platforms /// āŒ AMD āœ… Intel #[derive(PartialEq, Eq, Clone)] pub struct CacheInfoIter { current: u32, eax: u32, ebx: u32, ecx: u32, edx: u32, } impl Iterator for CacheInfoIter { type Item = CacheInfo; /// Iterate over all cache information. fn next(&mut self) -> Option { // Every byte of the 4 register values returned by cpuid // can contain information about a cache (except the // very first one). if self.current >= 4 * 4 { return None; } let reg_index = self.current % 4; let byte_index = self.current / 4; let reg = match reg_index { 0 => self.eax, 1 => self.ebx, 2 => self.ecx, 3 => self.edx, _ => unreachable!(), }; let byte = match byte_index { 0 => reg, 1 => reg >> 8, 2 => reg >> 16, 3 => reg >> 24, _ => unreachable!(), } as u8; if byte == 0 { self.current += 1; return self.next(); } for cache_info in CACHE_INFO_TABLE.iter() { if cache_info.num == byte { self.current += 1; return Some(*cache_info); } } None } } impl Debug for CacheInfoIter { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } /// What type of cache are we dealing with? #[derive(Copy, Clone, Debug)] pub enum CacheInfoType { General, Cache, TLB, STLB, DTLB, Prefetch, } /// Describes any kind of cache (TLB, Data and Instruction caches plus prefetchers). #[derive(Copy, Clone)] pub struct CacheInfo { /// Number as retrieved from cpuid pub num: u8, /// Cache type pub typ: CacheInfoType, } impl CacheInfo { /// Description of the cache (from Intel Manual) pub fn desc(&self) -> &'static str { match self.num { 0x00 => "Null descriptor, this byte contains no information", 0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries", 0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries", 0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries", 0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries", 0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries", 0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size", 0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size", 0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size", 0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size", 0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries", 0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size", 0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size", 0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size", 0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size", 0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size", 0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector", 0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", 0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size", 0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", 0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", 0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size", 0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size", 0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache", 0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size", 0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size", 0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size", 0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size", 0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size", 0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size", 0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size", 0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size", 0x49 => "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set ssociative, 64 byte line size", 0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size", 0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size", 0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size", 0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size", 0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size", 0x4F => "Instruction TLB: 4 KByte pages, 32 entries", 0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries", 0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries", 0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries", 0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries", 0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries", 0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries", 0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries", 0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries", 0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries", 0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries", 0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries", 0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size", 0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries", 0x63 => "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries", 0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries", 0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size", 0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size", 0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size", 0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries", 0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries", 0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries", 0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries", 0x70 => "Trace cache: 12 K-μop, 8-way set associative", 0x71 => "Trace cache: 16 K-μop, 8-way set associative", 0x72 => "Trace cache: 32 K-μop, 8-way set associative", 0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries", 0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size", 0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", 0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", 0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", 0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector", 0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size", 0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size", 0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size", 0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size", 0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size", 0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size", 0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size", 0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size", 0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size", 0xA0 => "DTLB: 4k pages, fully associative, 32 entries", 0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries", 0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries", 0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries", 0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries", 0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries", 0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries", 0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries", 0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries", 0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries", 0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries", 0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries", 0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.", 0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries", 0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries", 0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size", 0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size", 0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size", 0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size", 0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size", 0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size", 0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size", 0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size", 0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size", 0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size", 0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size", 0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size", 0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size", 0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size", 0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size", 0xF0 => "64-Byte prefetching", 0xF1 => "128-Byte prefetching", 0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.", 0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters", _ => "Unknown cache type!" } } } impl Debug for CacheInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("CacheInfo") .field("typ", &self.typ) .field("desc", &self.desc()) .finish() } } impl fmt::Display for CacheInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let typ = match self.typ { CacheInfoType::General => "N/A", CacheInfoType::Cache => "Cache", CacheInfoType::TLB => "TLB", CacheInfoType::STLB => "STLB", CacheInfoType::DTLB => "DTLB", CacheInfoType::Prefetch => "Prefetcher", }; write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc()) } } /// This table is taken from Intel manual (Section CPUID instruction). pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [ CacheInfo { num: 0x00, typ: CacheInfoType::General, }, CacheInfo { num: 0x01, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x02, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x03, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x04, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x05, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x06, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x08, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x09, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x0A, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x0B, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x0C, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x0D, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x0E, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x21, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x22, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x23, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x24, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x25, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x29, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x2C, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x30, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x40, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x41, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x42, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x43, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x44, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x45, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x46, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x47, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x48, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x49, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4A, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4B, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4C, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4D, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4E, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x4F, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x50, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x51, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x52, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x55, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x56, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x57, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x59, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x5A, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x5B, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x5C, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x5D, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x60, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x61, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x63, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x66, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x67, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x68, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x6A, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x6B, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x6C, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x6D, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x70, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x71, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x72, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x76, typ: CacheInfoType::TLB, }, CacheInfo { num: 0x78, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x79, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x7A, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x7B, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x7C, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x7D, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x7F, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x80, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x82, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x83, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x84, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x85, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x86, typ: CacheInfoType::Cache, }, CacheInfo { num: 0x87, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xB0, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB1, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB2, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB3, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB4, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB5, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xB6, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xBA, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xC0, typ: CacheInfoType::TLB, }, CacheInfo { num: 0xC1, typ: CacheInfoType::STLB, }, CacheInfo { num: 0xC2, typ: CacheInfoType::DTLB, }, CacheInfo { num: 0xCA, typ: CacheInfoType::STLB, }, CacheInfo { num: 0xD0, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xD1, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xD2, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xD6, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xD7, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xD8, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xDC, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xDD, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xDE, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xE2, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xE3, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xE4, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xEA, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xEB, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xEC, typ: CacheInfoType::Cache, }, CacheInfo { num: 0xF0, typ: CacheInfoType::Prefetch, }, CacheInfo { num: 0xF1, typ: CacheInfoType::Prefetch, }, CacheInfo { num: 0xFE, typ: CacheInfoType::General, }, CacheInfo { num: 0xFF, typ: CacheInfoType::General, }, ]; /// Processor Serial Number (LEAF=0x3). /// /// # Deprecated /// /// Processor serial number (PSN) is not supported in the Pentium 4 processor or /// later. On all models, use the PSN flag (returned using CPUID) to check for /// PSN support before accessing the feature. /// /// # Platforms /// āŒ AMD āœ… Intel #[derive(PartialEq, Eq)] pub struct ProcessorSerial { /// Lower bits ecx: u32, /// Middle bits edx: u32, /// Upper bits (come from leaf 0x1) eax: u32, } impl ProcessorSerial { /// Bits 00-31 of 96 bit processor serial number. /// /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.) pub fn serial_lower(&self) -> u32 { self.ecx } /// Bits 32-63 of 96 bit processor serial number. /// /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.) pub fn serial_middle(&self) -> u32 { self.edx } /// Bits 64-96 of 96 bit processor serial number. pub fn serial_upper(&self) -> u32 { self.eax } /// Combination of bits 00-31 and 32-63 of 96 bit processor serial number. pub fn serial(&self) -> u64 { (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32 } /// 96 bit processor serial number. pub fn serial_all(&self) -> u128 { (self.serial_lower() as u128) | ((self.serial_middle() as u128) << 32) | ((self.serial_upper() as u128) << 64) } } impl Debug for ProcessorSerial { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ProcessorSerial") .field("serial_lower", &self.serial_lower()) .field("serial_middle", &self.serial_middle()) .finish() } } /// Processor and Processor Feature Identifiers (LEAF=0x01). /// /// # Platforms /// āœ… AMD āœ… Intel pub struct FeatureInfo { vendor: Vendor, eax: u32, ebx: u32, edx_ecx: FeatureInfoFlags, } impl FeatureInfo { /// Version Information: Extended Family pub fn extended_family_id(&self) -> u8 { get_bits(self.eax, 20, 27) as u8 } /// Version Information: Extended Model pub fn extended_model_id(&self) -> u8 { get_bits(self.eax, 16, 19) as u8 } /// Version Information: Family pub fn base_family_id(&self) -> u8 { get_bits(self.eax, 8, 11) as u8 } /// Version Information: Model pub fn base_model_id(&self) -> u8 { get_bits(self.eax, 4, 7) as u8 } pub fn family_id(&self) -> u8 { let base_family_id = self.base_family_id(); let extended_family_id = self.extended_family_id(); let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf) || (self.vendor == Vendor::Intel && base_family_id != 0xf); if just_use_base { base_family_id } else { base_family_id + extended_family_id } } pub fn model_id(&self) -> u8 { let base_family_id = self.base_family_id(); let base_model_id = self.base_model_id(); let extended_model_id = self.extended_model_id(); let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf) || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6); if just_use_base { base_model_id } else { (extended_model_id << 4) | base_model_id } } /// Version Information: Stepping ID pub fn stepping_id(&self) -> u8 { get_bits(self.eax, 0, 3) as u8 } /// Brand Index pub fn brand_index(&self) -> u8 { get_bits(self.ebx, 0, 7) as u8 } /// CLFLUSH line size (Value āˆ— 8 = cache line size in bytes) pub fn cflush_cache_line_size(&self) -> u8 { get_bits(self.ebx, 8, 15) as u8 } /// Initial APIC ID pub fn initial_local_apic_id(&self) -> u8 { get_bits(self.ebx, 24, 31) as u8 } /// Maximum number of addressable IDs for logical processors in this physical package. pub fn max_logical_processor_ids(&self) -> u8 { get_bits(self.ebx, 16, 23) as u8 } check_flag!( doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \ supports this technology.", has_sse3, edx_ecx, FeatureInfoFlags::SSE3 ); check_flag!( doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \ instruction", has_pclmulqdq, edx_ecx, FeatureInfoFlags::PCLMULQDQ ); check_flag!( doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \ using 64-bit layout", has_ds_area, edx_ecx, FeatureInfoFlags::DTES64 ); check_flag!( doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.", has_monitor_mwait, edx_ecx, FeatureInfoFlags::MONITOR ); check_flag!( doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \ the extensions to the Debug Store feature to allow for branch message \ storage qualified by CPL.", has_cpl, edx_ecx, FeatureInfoFlags::DSCPL ); check_flag!( doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \ supports this technology.", has_vmx, edx_ecx, FeatureInfoFlags::VMX ); check_flag!( doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \ this technology. See Chapter 5, Safer Mode Extensions Reference.", has_smx, edx_ecx, FeatureInfoFlags::SMX ); check_flag!( doc = "Enhanced Intel SpeedStepĀ® technology. A value of 1 indicates that the \ processor supports this technology.", has_eist, edx_ecx, FeatureInfoFlags::EIST ); check_flag!( doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \ this technology.", has_tm2, edx_ecx, FeatureInfoFlags::TM2 ); check_flag!( doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \ Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \ are not present in the processor", has_ssse3, edx_ecx, FeatureInfoFlags::SSSE3 ); check_flag!( doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \ to either adaptive mode or shared mode. A value of 0 indicates this \ feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \ 24 (L1 Data Cache Context Mode) for details.", has_cnxtid, edx_ecx, FeatureInfoFlags::CNXTID ); check_flag!( doc = "A value of 1 indicates the processor supports FMA extensions using YMM \ state.", has_fma, edx_ecx, FeatureInfoFlags::FMA ); check_flag!( doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \ available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \ section. 14", has_cmpxchg16b, edx_ecx, FeatureInfoFlags::CMPXCHG16B ); check_flag!( doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \ supports the performance and debug feature indication MSR \ IA32_PERF_CAPABILITIES.", has_pdcm, edx_ecx, FeatureInfoFlags::PDCM ); check_flag!( doc = "Process-context identifiers. A value of 1 indicates that the processor \ supports PCIDs and the software may set CR4.PCIDE to 1.", has_pcid, edx_ecx, FeatureInfoFlags::PCID ); check_flag!( doc = "A value of 1 indicates the processor supports the ability to prefetch \ data from a memory mapped device.", has_dca, edx_ecx, FeatureInfoFlags::DCA ); check_flag!( doc = "A value of 1 indicates that the processor supports SSE4.1.", has_sse41, edx_ecx, FeatureInfoFlags::SSE41 ); check_flag!( doc = "A value of 1 indicates that the processor supports SSE4.2.", has_sse42, edx_ecx, FeatureInfoFlags::SSE42 ); check_flag!( doc = "A value of 1 indicates that the processor supports x2APIC feature.", has_x2apic, edx_ecx, FeatureInfoFlags::X2APIC ); check_flag!( doc = "A value of 1 indicates that the processor supports MOVBE instruction.", has_movbe, edx_ecx, FeatureInfoFlags::MOVBE ); check_flag!( doc = "A value of 1 indicates that the processor supports the POPCNT instruction.", has_popcnt, edx_ecx, FeatureInfoFlags::POPCNT ); check_flag!( doc = "A value of 1 indicates that the processors local APIC timer supports \ one-shot operation using a TSC deadline value.", has_tsc_deadline, edx_ecx, FeatureInfoFlags::TSC_DEADLINE ); check_flag!( doc = "A value of 1 indicates that the processor supports the AESNI instruction \ extensions.", has_aesni, edx_ecx, FeatureInfoFlags::AESNI ); check_flag!( doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \ processor extended states feature, the XSETBV/XGETBV instructions, and \ XCR0.", has_xsave, edx_ecx, FeatureInfoFlags::XSAVE ); check_flag!( doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \ to access XCR0, and support for processor extended state management using \ XSAVE/XRSTOR.", has_oxsave, edx_ecx, FeatureInfoFlags::OSXSAVE ); check_flag!( doc = "A value of 1 indicates the processor supports the AVX instruction \ extensions.", has_avx, edx_ecx, FeatureInfoFlags::AVX ); check_flag!( doc = "A value of 1 indicates that processor supports 16-bit floating-point \ conversion instructions.", has_f16c, edx_ecx, FeatureInfoFlags::F16C ); check_flag!( doc = "A value of 1 indicates that processor supports RDRAND instruction.", has_rdrand, edx_ecx, FeatureInfoFlags::RDRAND ); check_flag!( doc = "A value of 1 indicates the indicates the presence of a hypervisor.", has_hypervisor, edx_ecx, FeatureInfoFlags::HYPERVISOR ); check_flag!( doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.", has_fpu, edx_ecx, FeatureInfoFlags::FPU ); check_flag!( doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \ CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \ interrupts, software interrupt indirection, expansion of the TSS with the \ software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.", has_vme, edx_ecx, FeatureInfoFlags::VME ); check_flag!( doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \ controlling the feature, and optional trapping of accesses to DR4 and DR5.", has_de, edx_ecx, FeatureInfoFlags::DE ); check_flag!( doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \ CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \ Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.", has_pse, edx_ecx, FeatureInfoFlags::PSE ); check_flag!( doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \ for controlling privilege.", has_tsc, edx_ecx, FeatureInfoFlags::TSC ); check_flag!( doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \ WRMSR instructions are supported. Some of the MSRs are implementation \ dependent.", has_msr, edx_ecx, FeatureInfoFlags::MSR ); check_flag!( doc = "Physical Address Extension. Physical addresses greater than 32 bits are \ supported: extended page table entry formats, an extra level in the page \ translation tables is defined, 2-MByte pages are supported instead of 4 \ Mbyte pages if PAE bit is 1.", has_pae, edx_ecx, FeatureInfoFlags::PAE ); check_flag!( doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \ including CR4.MCE for controlling the feature. This feature does not \ define the model-specific implementations of machine-check error logging, \ reporting, and processor shutdowns. Machine Check exception handlers may \ have to depend on processor version to do model specific processing of \ the exception, or test for the presence of the Machine Check feature.", has_mce, edx_ecx, FeatureInfoFlags::MCE ); check_flag!( doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \ instruction is supported (implicitly locked and atomic).", has_cmpxchg8b, edx_ecx, FeatureInfoFlags::CX8 ); check_flag!( doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \ Controller (APIC), responding to memory mapped commands in the physical \ address range FFFE0000H to FFFE0FFFH (by default - some processors permit \ the APIC to be relocated).", has_apic, edx_ecx, FeatureInfoFlags::APIC ); check_flag!( doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \ associated MSRs are supported.", has_sysenter_sysexit, edx_ecx, FeatureInfoFlags::SEP ); check_flag!( doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \ contains feature bits that describe what memory types are supported, how \ many variable MTRRs are supported, and whether fixed MTRRs are supported.", has_mtrr, edx_ecx, FeatureInfoFlags::MTRR ); check_flag!( doc = "Page Global Bit. The global bit is supported in paging-structure entries \ that map a page, indicating TLB entries that are common to different \ processes and need not be flushed. The CR4.PGE bit controls this feature.", has_pge, edx_ecx, FeatureInfoFlags::PGE ); check_flag!( doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \ Architecture of reporting machine errors is supported. The MCG_CAP MSR \ contains feature bits describing how many banks of error reporting MSRs \ are supported.", has_mca, edx_ecx, FeatureInfoFlags::MCA ); check_flag!( doc = "Conditional Move Instructions. The conditional move instruction CMOV is \ supported. In addition, if x87 FPU is present as indicated by the \ CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported", has_cmov, edx_ecx, FeatureInfoFlags::CMOV ); check_flag!( doc = "Page Attribute Table. Page Attribute Table is supported. This feature \ augments the Memory Type Range Registers (MTRRs), allowing an operating \ system to specify attributes of memory accessed through a linear address \ on a 4KB granularity.", has_pat, edx_ecx, FeatureInfoFlags::PAT ); check_flag!( doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \ beyond 4 GBytes are supported with 32-bit paging. This feature indicates \ that upper bits of the physical address of a 4-MByte page are encoded in \ bits 20:13 of the page-directory entry. Such physical addresses are \ limited by MAXPHYADDR and may be up to 40 bits in size.", has_pse36, edx_ecx, FeatureInfoFlags::PSE36 ); check_flag!( doc = "Processor Serial Number. The processor supports the 96-bit processor \ identification number feature and the feature is enabled.", has_psn, edx_ecx, FeatureInfoFlags::PSN ); check_flag!( doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.", has_clflush, edx_ecx, FeatureInfoFlags::CLFSH ); check_flag!( doc = "Debug Store. The processor supports the ability to write debug \ information into a memory resident buffer. This feature is used by the \ branch trace store (BTS) and processor event-based sampling (PEBS) \ facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \ in the IntelĀ® 64 and IA-32 Architectures Software Developers Manual, \ Volume 3C).", has_ds, edx_ecx, FeatureInfoFlags::DS ); check_flag!( doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \ implements internal MSRs that allow processor temperature to be monitored \ and processor performance to be modulated in predefined duty cycles under \ software control.", has_acpi, edx_ecx, FeatureInfoFlags::ACPI ); check_flag!( doc = "Intel MMX Technology. The processor supports the Intel MMX technology.", has_mmx, edx_ecx, FeatureInfoFlags::MMX ); check_flag!( doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \ supported for fast save and restore of the floating point context. \ Presence of this bit also indicates that CR4.OSFXSR is available for an \ operating system to indicate that it supports the FXSAVE and FXRSTOR \ instructions.", has_fxsave_fxstor, edx_ecx, FeatureInfoFlags::FXSR ); check_flag!( doc = "SSE. The processor supports the SSE extensions.", has_sse, edx_ecx, FeatureInfoFlags::SSE ); check_flag!( doc = "SSE2. The processor supports the SSE2 extensions.", has_sse2, edx_ecx, FeatureInfoFlags::SSE2 ); check_flag!( doc = "Self Snoop. The processor supports the management of conflicting memory \ types by performing a snoop of its own cache structure for transactions \ issued to the bus.", has_ss, edx_ecx, FeatureInfoFlags::SS ); check_flag!( doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \ there is only a single logical processor in the package and software \ should assume only a single APIC ID is reserved. A value of 1 for HTT \ indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \ addressable IDs for logical processors in this package) is valid for the \ package.", has_htt, edx_ecx, FeatureInfoFlags::HTT ); check_flag!( doc = "Thermal Monitor. The processor implements the thermal monitor automatic \ thermal control circuitry (TCC).", has_tm, edx_ecx, FeatureInfoFlags::TM ); check_flag!( doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \ pin when the processor is in the stop-clock state (STPCLK# is asserted) \ to signal the processor that an interrupt is pending and that the \ processor should return to normal operation to handle the interrupt. Bit \ 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.", has_pbe, edx_ecx, FeatureInfoFlags::PBE ); } impl Debug for FeatureInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("FeatureInfo") .field("extended_family_id", &self.extended_family_id()) .field("extended_model_id", &self.extended_model_id()) .field("family_id", &self.family_id()) .field("model_id", &self.model_id()) .field("stepping_id", &self.stepping_id()) .field("brand_index", &self.brand_index()) .field("cflush_cache_line_size", &self.cflush_cache_line_size()) .field("initial_local_apic_id", &self.initial_local_apic_id()) .field( "max_logical_processor_ids", &self.max_logical_processor_ids(), ) .field("edx_ecx", &self.edx_ecx) .finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct FeatureInfoFlags: u64 { // ECX flags /// Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor supports this technology. const SSE3 = 1 << 0; /// PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ instruction const PCLMULQDQ = 1 << 1; /// 64-bit DS Area. A value of 1 indicates the processor supports DS area using 64-bit layout const DTES64 = 1 << 2; /// MONITOR/MWAIT. A value of 1 indicates the processor supports this feature. const MONITOR = 1 << 3; /// CPL Qualified Debug Store. A value of 1 indicates the processor supports the extensions to the Debug Store feature to allow for branch message storage qualified by CPL. const DSCPL = 1 << 4; /// Virtual Machine Extensions. A value of 1 indicates that the processor supports this technology. const VMX = 1 << 5; /// Safer Mode Extensions. A value of 1 indicates that the processor supports this technology. See Chapter 5, Safer Mode Extensions Reference. const SMX = 1 << 6; /// Enhanced Intel SpeedStepĀ® technology. A value of 1 indicates that the processor supports this technology. const EIST = 1 << 7; /// Thermal Monitor 2. A value of 1 indicates whether the processor supports this technology. const TM2 = 1 << 8; /// A value of 1 indicates the presence of the Supplemental Streaming SIMD Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions are not present in the processor const SSSE3 = 1 << 9; /// L1 Context ID. A value of 1 indicates the L1 data cache mode can be set to either adaptive mode or shared mode. A value of 0 indicates this feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit 24 (L1 Data Cache Context Mode) for details. const CNXTID = 1 << 10; /// A value of 1 indicates the processor supports FMA extensions using YMM state. const FMA = 1 << 12; /// CMPXCHG16B Available. A value of 1 indicates that the feature is available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes section. 14 const CMPXCHG16B = 1 << 13; /// Perfmon and Debug Capability: A value of 1 indicates the processor supports the performance and debug feature indication MSR IA32_PERF_CAPABILITIES. const PDCM = 1 << 15; /// Process-context identifiers. A value of 1 indicates that the processor supports PCIDs and the software may set CR4.PCIDE to 1. const PCID = 1 << 17; /// A value of 1 indicates the processor supports the ability to prefetch data from a memory mapped device. const DCA = 1 << 18; /// A value of 1 indicates that the processor supports SSE4.1. const SSE41 = 1 << 19; /// A value of 1 indicates that the processor supports SSE4.2. const SSE42 = 1 << 20; /// A value of 1 indicates that the processor supports x2APIC feature. const X2APIC = 1 << 21; /// A value of 1 indicates that the processor supports MOVBE instruction. const MOVBE = 1 << 22; /// A value of 1 indicates that the processor supports the POPCNT instruction. const POPCNT = 1 << 23; /// A value of 1 indicates that the processors local APIC timer supports one-shot operation using a TSC deadline value. const TSC_DEADLINE = 1 << 24; /// A value of 1 indicates that the processor supports the AESNI instruction extensions. const AESNI = 1 << 25; /// A value of 1 indicates that the processor supports the XSAVE/XRSTOR processor extended states feature, the XSETBV/XGETBV instructions, and XCR0. const XSAVE = 1 << 26; /// A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions to access XCR0, and support for processor extended state management using XSAVE/XRSTOR. const OSXSAVE = 1 << 27; /// A value of 1 indicates the processor supports the AVX instruction extensions. const AVX = 1 << 28; /// A value of 1 indicates that processor supports 16-bit floating-point conversion instructions. const F16C = 1 << 29; /// A value of 1 indicates that processor supports RDRAND instruction. const RDRAND = 1 << 30; /// A value of 1 indicates the indicates the presence of a hypervisor. const HYPERVISOR = 1 << 31; // EDX flags /// Floating Point Unit On-Chip. The processor contains an x87 FPU. const FPU = 1 << 32; /// Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including CR4.VME for controlling the feature, CR4.PVI for protected mode virtual interrupts, software interrupt indirection, expansion of the TSS with the software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags. const VME = 1 << (32 + 1); /// Debugging Extensions. Support for I/O breakpoints, including CR4.DE for controlling the feature, and optional trapping of accesses to DR4 and DR5. const DE = 1 << (32 + 2); /// Page Size Extension. Large pages of size 4 MByte are supported, including CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs. const PSE = 1 << (32 + 3); /// Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD for controlling privilege. const TSC = 1 << (32 + 4); /// Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and WRMSR instructions are supported. Some of the MSRs are implementation dependent. const MSR = 1 << (32 + 5); /// Physical Address Extension. Physical addresses greater than 32 bits are supported: extended page table entry formats, an extra level in the page translation tables is defined, 2-MByte pages are supported instead of 4 Mbyte pages if PAE bit is 1. const PAE = 1 << (32 + 6); /// Machine Check Exception. Exception 18 is defined for Machine Checks, including CR4.MCE for controlling the feature. This feature does not define the model-specific implementations of machine-check error logging, reporting, and processor shutdowns. Machine Check exception handlers may have to depend on processor version to do model specific processing of the exception, or test for the presence of the Machine Check feature. const MCE = 1 << (32 + 7); /// CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) instruction is supported (implicitly locked and atomic). const CX8 = 1 << (32 + 8); /// APIC On-Chip. The processor contains an Advanced Programmable Interrupt Controller (APIC), responding to memory mapped commands in the physical address range FFFE0000H to FFFE0FFFH (by default - some processors permit the APIC to be relocated). const APIC = 1 << (32 + 9); /// SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and associated MSRs are supported. const SEP = 1 << (32 + 11); /// Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR contains feature bits that describe what memory types are supported, how many variable MTRRs are supported, and whether fixed MTRRs are supported. const MTRR = 1 << (32 + 12); /// Page Global Bit. The global bit is supported in paging-structure entries that map a page, indicating TLB entries that are common to different processes and need not be flushed. The CR4.PGE bit controls this feature. const PGE = 1 << (32 + 13); /// Machine Check Architecture. The Machine Check exArchitecture, which provides a compatible mechanism for error reporting in P6 family, Pentium 4, Intel Xeon processors, and future processors, is supported. The MCG_CAP MSR contains feature bits describing how many banks of error reporting MSRs are supported. const MCA = 1 << (32 + 14); /// Conditional Move Instructions. The conditional move instruction CMOV is supported. In addition, if x87 FPU is present as indicated by the CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported const CMOV = 1 << (32 + 15); /// Page Attribute Table. Page Attribute Table is supported. This feature augments the Memory Type Range Registers (MTRRs), allowing an operating system to specify attributes of memory accessed through a linear address on a 4KB granularity. const PAT = 1 << (32 + 16); /// 36-Bit Page Size Extension. 4-MByte pages addressing physical memory beyond 4 GBytes are supported with 32-bit paging. This feature indicates that upper bits of the physical address of a 4-MByte page are encoded in bits 20:13 of the page-directory entry. Such physical addresses are limited by MAXPHYADDR and may be up to 40 bits in size. const PSE36 = 1 << (32 + 17); /// Processor Serial Number. The processor supports the 96-bit processor identification number feature and the feature is enabled. const PSN = 1 << (32 + 18); /// CLFLUSH Instruction. CLFLUSH Instruction is supported. const CLFSH = 1 << (32 + 19); /// Debug Store. The processor supports the ability to write debug information into a memory resident buffer. This feature is used by the branch trace store (BTS) and precise event-based sampling (PEBS) facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, in the IntelĀ® 64 and IA-32 Architectures Software Developers Manual, Volume 3C). const DS = 1 << (32 + 21); /// Thermal Monitor and Software Controlled Clock Facilities. The processor implements internal MSRs that allow processor temperature to be monitored and processor performance to be modulated in predefined duty cycles under software control. const ACPI = 1 << (32 + 22); /// Intel MMX Technology. The processor supports the Intel MMX technology. const MMX = 1 << (32 + 23); /// FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are supported for fast save and restore of the floating point context. Presence of this bit also indicates that CR4.OSFXSR is available for an operating system to indicate that it supports the FXSAVE and FXRSTOR instructions. const FXSR = 1 << (32 + 24); /// SSE. The processor supports the SSE extensions. const SSE = 1 << (32 + 25); /// SSE2. The processor supports the SSE2 extensions. const SSE2 = 1 << (32 + 26); /// Self Snoop. The processor supports the management of conflicting memory types by performing a snoop of its own cache structure for transactions issued to the bus. const SS = 1 << (32 + 27); /// Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates there is only a single logical processor in the package and software should assume only a single APIC ID is reserved. A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] (the Maximum number of addressable IDs for logical processors in this package) is valid for the package. const HTT = 1 << (32 + 28); /// Thermal Monitor. The processor implements the thermal monitor automatic thermal control circuitry (TCC). const TM = 1 << (32 + 29); /// Pending Break Enable. The processor supports the use of the FERR#/PBE# pin when the processor is in the stop-clock state (STPCLK# is asserted) to signal the processor that an interrupt is pending and that the processor should return to normal operation to handle the interrupt. Bit 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability. const PBE = 1 << (32 + 31); } } /// Iterator over caches (LEAF=0x04). /// /// Yields a [CacheParameter] for each cache. /// /// # Platforms /// 🟔 AMD āœ… Intel #[derive(Clone, Copy)] pub struct CacheParametersIter { read: R, leaf: u32, current: u32, } impl Iterator for CacheParametersIter { type Item = CacheParameter; /// Iterate over all cache info subleafs for this CPU. /// /// # Note /// cpuid is called every-time we advance the iterator to get information /// about the next cache. fn next(&mut self) -> Option { let res = self.read.cpuid2(self.leaf, self.current); let cp = CacheParameter { eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }; match cp.cache_type() { CacheType::Null => None, CacheType::Reserved => None, _ => { self.current += 1; Some(cp) } } } } impl Debug for CacheParametersIter { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } /// Information about an individual cache in the hierarchy. /// /// # Platforms /// 🟔 AMD āœ… Intel #[derive(Copy, Clone, Eq, PartialEq)] pub struct CacheParameter { eax: u32, ebx: u32, ecx: u32, edx: u32, } /// Info about a what a given cache caches (instructions, data, etc.) #[derive(PartialEq, Eq, Debug)] pub enum CacheType { /// Null - No more caches Null = 0, /// Data cache Data, /// Instruction cache Instruction, /// Data and Instruction cache Unified, /// 4-31 = Reserved Reserved, } impl fmt::Display for CacheType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let typ = match self { CacheType::Null => "Null", CacheType::Data => "Data", CacheType::Instruction => "Instruction", CacheType::Unified => "Unified", CacheType::Reserved => "Reserved", }; f.write_str(typ) } } impl CacheParameter { /// Cache Type /// /// # Platforms /// āœ… AMD āœ… Intel pub fn cache_type(&self) -> CacheType { let typ = get_bits(self.eax, 0, 4) as u8; match typ { 0 => CacheType::Null, 1 => CacheType::Data, 2 => CacheType::Instruction, 3 => CacheType::Unified, _ => CacheType::Reserved, } } /// Cache Level (starts at 1) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn level(&self) -> u8 { get_bits(self.eax, 5, 7) as u8 } /// Self Initializing cache level (does not need SW initialization). /// /// # Platforms /// āœ… AMD āœ… Intel pub fn is_self_initializing(&self) -> bool { get_bits(self.eax, 8, 8) == 1 } /// Fully Associative cache /// /// # Platforms /// āœ… AMD āœ… Intel pub fn is_fully_associative(&self) -> bool { get_bits(self.eax, 9, 9) == 1 } /// Maximum number of addressable IDs for logical processors sharing this cache /// /// # Platforms /// āœ… AMD āœ… Intel pub fn max_cores_for_cache(&self) -> usize { (get_bits(self.eax, 14, 25) + 1) as usize } /// Maximum number of addressable IDs for processor cores in the physical package /// /// # Platforms /// āŒ AMD āœ… Intel pub fn max_cores_for_package(&self) -> usize { (get_bits(self.eax, 26, 31) + 1) as usize } /// System Coherency Line Size (Bits 11-00) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn coherency_line_size(&self) -> usize { (get_bits(self.ebx, 0, 11) + 1) as usize } /// Physical Line partitions (Bits 21-12) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn physical_line_partitions(&self) -> usize { (get_bits(self.ebx, 12, 21) + 1) as usize } /// Ways of associativity (Bits 31-22) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn associativity(&self) -> usize { (get_bits(self.ebx, 22, 31) + 1) as usize } /// Number of Sets (Bits 31-00) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn sets(&self) -> usize { (self.ecx + 1) as usize } /// Write-Back Invalidate/Invalidate (Bit 0) /// False: WBINVD/INVD from threads sharing this cache acts upon lower level caches for threads sharing this cache. /// True: WBINVD/INVD is not guaranteed to act upon lower level caches of non-originating threads sharing this cache. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn is_write_back_invalidate(&self) -> bool { get_bits(self.edx, 0, 0) == 1 } /// Cache Inclusiveness (Bit 1) /// False: Cache is not inclusive of lower cache levels. /// True: Cache is inclusive of lower cache levels. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn is_inclusive(&self) -> bool { get_bits(self.edx, 1, 1) == 1 } /// Complex Cache Indexing (Bit 2) /// False: Direct mapped cache. /// True: A complex function is used to index the cache, potentially using all address bits. /// /// # Platforms /// āŒ AMD āœ… Intel pub fn has_complex_indexing(&self) -> bool { get_bits(self.edx, 2, 2) == 1 } } impl Debug for CacheParameter { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("CacheParameter") .field("cache_type", &self.cache_type()) .field("level", &self.level()) .field("is_self_initializing", &self.is_self_initializing()) .field("is_fully_associative", &self.is_fully_associative()) .field("max_cores_for_cache", &self.max_cores_for_cache()) .field("max_cores_for_package", &self.max_cores_for_package()) .field("coherency_line_size", &self.coherency_line_size()) .field("physical_line_partitions", &self.physical_line_partitions()) .field("associativity", &self.associativity()) .field("sets", &self.sets()) .field("is_write_back_invalidate", &self.is_write_back_invalidate()) .field("is_inclusive", &self.is_inclusive()) .field("has_complex_indexing", &self.has_complex_indexing()) .finish() } } /// Information about how monitor/mwait works on this CPU (LEAF=0x05). /// /// # Platforms /// 🟔 AMD āœ… Intel #[derive(Eq, PartialEq)] pub struct MonitorMwaitInfo { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl MonitorMwaitInfo { /// Smallest monitor-line size in bytes (default is processor's monitor granularity) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn smallest_monitor_line(&self) -> u16 { get_bits(self.eax, 0, 15) as u16 } /// Largest monitor-line size in bytes (default is processor's monitor granularity) /// /// # Platforms /// āœ… AMD āœ… Intel pub fn largest_monitor_line(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } /// Enumeration of Monitor-Mwait extensions (beyond EAX and EBX registers) supported /// /// # Platforms /// āœ… AMD āœ… Intel pub fn extensions_supported(&self) -> bool { get_bits(self.ecx, 0, 0) == 1 } /// Supports treating interrupts as break-event for MWAIT, even when interrupts disabled /// /// # Platforms /// āœ… AMD āœ… Intel pub fn interrupts_as_break_event(&self) -> bool { get_bits(self.ecx, 1, 1) == 1 } /// Number of C0 sub C-states supported using MWAIT (Bits 03 - 00) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c0_states(&self) -> u16 { get_bits(self.edx, 0, 3) as u16 } /// Number of C1 sub C-states supported using MWAIT (Bits 07 - 04) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c1_states(&self) -> u16 { get_bits(self.edx, 4, 7) as u16 } /// Number of C2 sub C-states supported using MWAIT (Bits 11 - 08) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c2_states(&self) -> u16 { get_bits(self.edx, 8, 11) as u16 } /// Number of C3 sub C-states supported using MWAIT (Bits 15 - 12) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c3_states(&self) -> u16 { get_bits(self.edx, 12, 15) as u16 } /// Number of C4 sub C-states supported using MWAIT (Bits 19 - 16) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c4_states(&self) -> u16 { get_bits(self.edx, 16, 19) as u16 } /// Number of C5 sub C-states supported using MWAIT (Bits 23 - 20) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c5_states(&self) -> u16 { get_bits(self.edx, 20, 23) as u16 } /// Number of C6 sub C-states supported using MWAIT (Bits 27 - 24) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c6_states(&self) -> u16 { get_bits(self.edx, 24, 27) as u16 } /// Number of C7 sub C-states supported using MWAIT (Bits 31 - 28) /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn supported_c7_states(&self) -> u16 { get_bits(self.edx, 28, 31) as u16 } } impl Debug for MonitorMwaitInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("MonitorMwaitInfo") .field("smallest_monitor_line", &self.smallest_monitor_line()) .field("largest_monitor_line", &self.largest_monitor_line()) .field("extensions_supported", &self.extensions_supported()) .field( "interrupts_as_break_event", &self.interrupts_as_break_event(), ) .field("supported_c0_states", &self.supported_c0_states()) .field("supported_c1_states", &self.supported_c1_states()) .field("supported_c2_states", &self.supported_c2_states()) .field("supported_c3_states", &self.supported_c3_states()) .field("supported_c4_states", &self.supported_c4_states()) .field("supported_c5_states", &self.supported_c5_states()) .field("supported_c6_states", &self.supported_c6_states()) .field("supported_c7_states", &self.supported_c7_states()) .finish() } } /// Query information about thermal and power management features of the CPU (LEAF=0x06). /// /// # Platforms /// 🟔 AMD āœ… Intel pub struct ThermalPowerInfo { eax: ThermalPowerFeaturesEax, ebx: u32, ecx: ThermalPowerFeaturesEcx, _edx: u32, } impl ThermalPowerInfo { /// Number of Interrupt Thresholds in Digital Thermal Sensor /// /// # Platforms /// āŒ AMD (undefined/reserved) āœ… Intel pub fn dts_irq_threshold(&self) -> u8 { get_bits(self.ebx, 0, 3) as u8 } /// Digital temperature sensor is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_dts(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::DTS) } /// Intel Turbo Boost Technology Available (see description of /// IA32_MISC_ENABLE\[38\]). /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_turbo_boost(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST) } /// ARAT. APIC-Timer-always-running feature is supported if set. /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_arat(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::ARAT) } /// PLN. Power limit notification controls are supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_pln(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::PLN) } /// ECMD. Clock modulation duty cycle extension is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_ecmd(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::ECMD) } /// PTM. Package thermal management is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_ptm(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::PTM) } /// HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, /// IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::HWP) } /// HWP Notification. IA32_HWP_INTERRUPT MSR is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_notification(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION) } /// HWP Activity Window. IA32_HWP_REQUEST[bits 41:32] is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_activity_window(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW) } /// HWP Energy Performance Preference. IA32_HWP_REQUEST[bits 31:24] is /// supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_energy_performance_preference(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE) } /// HWP Package Level Request. IA32_HWP_REQUEST_PKG MSR is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_package_level_request(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST) } /// HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, /// IA32_THREAD_STALL MSRs are supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hdc(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::HDC) } /// IntelĀ® Turbo Boost Max Technology 3.0 available. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_turbo_boost3(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3) } /// HWP Capabilities. Highest Performance change is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_capabilities(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES) } /// HWP PECI override is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_peci_override(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE) } /// Flexible HWP is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_flexible_hwp(&self) -> bool { self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP) } /// Fast access mode for the IA32_HWP_REQUEST MSR is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_hwp_fast_access_mode(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS) } /// Ignoring Idle Logical Processor HWP request is supported if set. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_ignore_idle_processor_hwp_request(&self) -> bool { self.eax .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST) } /// Hardware Coordination Feedback Capability /// /// Presence of IA32_MPERF and IA32_APERF. /// /// The capability to provide a measure of delivered processor performance /// (since last reset of the counters), as a percentage of expected /// processor performance at frequency specified in CPUID Brand String Bits /// 02 - 01 /// /// # Platforms /// āœ… AMD āœ… Intel pub fn has_hw_coord_feedback(&self) -> bool { self.ecx .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK) } /// The processor supports performance-energy bias preference if /// CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a /// new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H) /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub fn has_energy_bias_pref(&self) -> bool { self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF) } } impl Debug for ThermalPowerInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ThermalPowerInfo") .field("dts_irq_threshold", &self.dts_irq_threshold()) .field("has_dts", &self.has_dts()) .field("has_arat", &self.has_arat()) .field("has_pln", &self.has_pln()) .field("has_ecmd", &self.has_ecmd()) .field("has_ptm", &self.has_ptm()) .field("has_hwp", &self.has_hwp()) .field("has_hwp_notification", &self.has_hwp_notification()) .field("has_hwp_activity_window", &self.has_hwp_activity_window()) .field( "has_hwp_energy_performance_preference", &self.has_hwp_energy_performance_preference(), ) .field( "has_hwp_package_level_request", &self.has_hwp_package_level_request(), ) .field("has_hdc", &self.has_hdc()) .field("has_turbo_boost3", &self.has_turbo_boost3()) .field("has_hwp_capabilities", &self.has_hwp_capabilities()) .field("has_hwp_peci_override", &self.has_hwp_peci_override()) .field("has_flexible_hwp", &self.has_flexible_hwp()) .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode()) .field( "has_ignore_idle_processor_hwp_request", &self.has_ignore_idle_processor_hwp_request(), ) .field("has_hw_coord_feedback", &self.has_hw_coord_feedback()) .field("has_energy_bias_pref", &self.has_energy_bias_pref()) .finish() } } bitflags! { struct ThermalPowerFeaturesEax: u32 { /// Digital temperature sensor is supported if set. (Bit 00) const DTS = 1 << 0; /// Intel Turbo Boost Technology Available (see description of IA32_MISC_ENABLE[38]). (Bit 01) const TURBO_BOOST = 1 << 1; /// ARAT. APIC-Timer-always-running feature is supported if set. (Bit 02) const ARAT = 1 << 2; /// Bit 3: Reserved. const RESERVED_3 = 1 << 3; /// PLN. Power limit notification controls are supported if set. (Bit 04) const PLN = 1 << 4; /// ECMD. Clock modulation duty cycle extension is supported if set. (Bit 05) const ECMD = 1 << 5; /// PTM. Package thermal management is supported if set. (Bit 06) const PTM = 1 << 6; /// Bit 07: HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set. const HWP = 1 << 7; /// Bit 08: HWP_Notification. IA32_HWP_INTERRUPT MSR is supported if set. const HWP_NOTIFICATION = 1 << 8; /// Bit 09: HWP_Activity_Window. IA32_HWP_REQUEST[bits 41:32] is supported if set. const HWP_ACTIVITY_WINDOW = 1 << 9; /// Bit 10: HWP_Energy_Performance_Preference. IA32_HWP_REQUEST[bits 31:24] is supported if set. const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10; /// Bit 11: HWP_Package_Level_Request. IA32_HWP_REQUEST_PKG MSR is supported if set. const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11; /// Bit 12: Reserved. const RESERVED_12 = 1 << 12; /// Bit 13: HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, IA32_THREAD_STALL MSRs are supported if set. const HDC = 1 << 13; /// Bit 14: IntelĀ® Turbo Boost Max Technology 3.0 available. const TURBO_BOOST_3 = 1 << 14; /// Bit 15: HWP Capabilities. Highest Performance change is supported if set. const HWP_CAPABILITIES = 1 << 15; /// Bit 16: HWP PECI override is supported if set. const HWP_PECI_OVERRIDE = 1 << 16; /// Bit 17: Flexible HWP is supported if set. const FLEXIBLE_HWP = 1 << 17; /// Bit 18: Fast access mode for the IA32_HWP_REQUEST MSR is supported if set. const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18; /// Bit 19: Reserved. const RESERVED_19 = 1 << 19; /// Bit 20: Ignoring Idle Logical Processor HWP request is supported if set. const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20; // Bits 31 - 21: Reserved } } bitflags! { struct ThermalPowerFeaturesEcx: u32 { const HW_COORD_FEEDBACK = 1 << 0; /// The processor supports performance-energy bias preference if CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H) const ENERGY_BIAS_PREF = 1 << 3; } } /// Structured Extended Feature Identifiers (LEAF=0x07). /// /// # Platforms /// 🟔 AMD āœ… Intel pub struct ExtendedFeatures { _eax: u32, ebx: ExtendedFeaturesEbx, ecx: ExtendedFeaturesEcx, edx: ExtendedFeaturesEdx, eax1: ExtendedFeaturesEax1, _ebx1: u32, _ecx1: u32, edx1: ExtendedFeaturesEdx1, } impl ExtendedFeatures { /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_fsgsbase(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE) } /// IA32_TSC_ADJUST MSR is supported if 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_tsc_adjust_msr(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR) } /// BMI1 /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_bmi1(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::BMI1) } /// HLE /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_hle(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::HLE) } /// AVX2 /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx2(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX2) } /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if /// 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_fdp(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::FDP) } /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_smep(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::SMEP) } /// BMI2 /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_bmi2(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::BMI2) } /// Supports Enhanced REP MOVSB/STOSB if 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_rep_movsb_stosb(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB) } /// INVPCID. If 1, supports INVPCID instruction for system software that /// manages process-context identifiers. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_invpcid(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::INVPCID) } /// RTM /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_rtm(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::RTM) } /// Supports Intel Resource Director Technology (RDT) Monitoring capability. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_rdtm(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::RDTM) } /// Deprecates FPU CS and FPU DS values if 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_fpu_cs_ds_deprecated(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS) } /// MPX. Supports Intel Memory Protection Extensions if 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_mpx(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::MPX) } /// Supports Intel Resource Director Technology (RDT) Allocation capability. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_rdta(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::RDTA) } /// Supports RDSEED. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_rdseed(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::RDSEED) } /// Supports ADX. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_adx(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::ADX) } /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC /// instructions) if 1. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_smap(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::SMAP) } /// Supports CLFLUSHOPT. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_clflushopt(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT) } /// Supports Intel Processor Trace. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_processor_trace(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE) } /// Supports SHA Instructions. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_sha(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::SHA) } /// Supports IntelĀ® Software Guard Extensions (IntelĀ® SGX Extensions). /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_sgx(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::SGX) } /// Supports AVX512F. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512f(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512F) } /// Supports AVX512DQ. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512dq(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ) } /// AVX512_IFMA /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512_ifma(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA) } /// AVX512PF /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512pf(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512PF) } /// AVX512ER /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512er(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512ER) } /// AVX512CD /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512cd(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512CD) } /// AVX512BW /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512bw(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512BW) } /// AVX512VL /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512vl(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::AVX512VL) } /// CLWB /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_clwb(&self) -> bool { self.ebx.contains(ExtendedFeaturesEbx::CLWB) } /// Has PREFETCHWT1 (IntelĀ® Xeon Phiā„¢ only). /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_prefetchwt1(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1) } /// AVX512VBMI /// /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512vbmi(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI) } /// Supports user-mode instruction prevention if 1. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_umip(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::UMIP) } /// Supports protection keys for user-mode pages. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_pku(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::PKU) } /// OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU /// instructions. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_ospke(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::OSPKE) } /// WAITPKG /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_waitpkg(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::WAITPKG) } /// AVX512VBMI2 /// /// āœ… AMD āœ… Intel #[deprecated(since = "11.4.0", note = "Please use `has_avx512vbmi2` instead")] #[inline] pub const fn has_av512vbmi2(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2) } /// AVX512VBMI2 /// /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512vbmi2(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2) } /// Supports CET shadow stack features. Processors that set this bit define bits 0..2 of the /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs: /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP. /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_cet_ss(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::CETSS) } /// GFNI /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_gfni(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::GFNI) } /// VAES /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_vaes(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::VAES) } /// VPCLMULQDQ /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_vpclmulqdq(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ) } /// AVX512VNNI /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512vnni(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI) } /// AVX512BITALG /// /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512bitalg(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG) } /// Indicates the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. /// /// ā“ AMD āœ… Intel #[inline] pub const fn has_tme_en(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::TMEEN) } /// AVX512VPOPCNTDQ /// /// āœ… AMD āœ… Intel #[inline] pub const fn has_avx512vpopcntdq(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ) } /// Supports 57-bit linear addresses and five-level paging if 1. /// /// # Platforms /// ā“ AMD āœ… Intel #[inline] pub const fn has_la57(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::LA57) } /// RDPID and IA32_TSC_AUX are available. /// /// # Bug /// The Intel manual lists RDPID as bit 22 in the ECX register, but AMD /// lists it as bit 22 in the ebx register. We assumed that the AMD manual /// was wrong and query ecx, let's see what happens. /// /// # Platforms /// āœ… AMD āœ… Intel #[inline] pub const fn has_rdpid(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::RDPID) } /// Supports SGX Launch Configuration. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_sgx_lc(&self) -> bool { self.ecx.contains(ExtendedFeaturesEcx::SGX_LC) } /// The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub fn mawau_value(&self) -> u8 { get_bits(self.ecx.bits(), 17, 21) as u8 } /// Supports AVX512_4VNNIW. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx512_4vnniw(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW) } /// Supports AVX512_4FMAPS. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx512_4fmaps(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS) } /// Supports AVX512_VP2INTERSECT. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx512_vp2intersect(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT) } /// Supports AMX_BF16. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_amx_bf16(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AMX_BF16) } /// Supports AVX512_FP16. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx512_fp16(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16) } /// Supports AMX_TILE. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_amx_tile(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AMX_TILE) } /// Supports AMX_INT8. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_amx_int8(&self) -> bool { self.edx.contains(ExtendedFeaturesEdx::AMX_INT8) } /// Supports AVX_VNNI. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx_vnni(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::AVX_VNNI) } /// Supports AVX512_BF16. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx512_bf16(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::AVX512_BF16) } /// Supports Fast zero-length REP MOVSB /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_fzrm(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::FZRM) } /// Supports Fast Short REP STOSB /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_fsrs(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::FSRS) } /// Supports Fast Short REP CMPSB, REP SCASB /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_fsrcrs(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::FSRCRS) } /// Supports HRESET /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_hreset(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::HRESET) } /// Supports AVX-IFMA Instructions. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx_ifma(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::AVX_IFMA) } /// Supports Linear Address Masking. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_lam(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::LAM) } /// Supports RDMSRLIST and WRMSRLIST Instructions and the IA32_BARRIER MSR. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_msrlist(&self) -> bool { self.eax1.contains(ExtendedFeaturesEax1::MSRLIST) } /// Supports INVD execution prevention after BIOS Done. /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_invd_disable_post_bios_done(&self) -> bool { self.eax1 .contains(ExtendedFeaturesEax1::INVD_DISABLE_POST_BIOS_DONE) } /// Supports AVX_VNNI_INT8 /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx_vnni_int8(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT8) } /// Supports AVX_NE_CONVERT /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx_ne_convert(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::AVX_NE_CONVERT) } /// Supports AVX_VNNI_INT16 /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx_vnni_int16(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT16) } /// Supports PREFETCHI /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_prefetchi(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::PREFETCHI) } /// Supports UIRET_UIF /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_uiret_uif(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::UIRET_UIF) } /// Supports CET_SSS /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_cet_sss(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS) } /// Supports AVX10 /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel #[inline] pub const fn has_avx10(&self) -> bool { self.edx1.contains(ExtendedFeaturesEdx1::AVX10) } } impl Debug for ExtendedFeatures { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ExtendedFeatures") .field("ebx", &self.ebx) .field("ecx", &self.ecx) .field("mawau_value", &self.mawau_value()) .finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeaturesEbx: u32 { /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. (Bit 00) const FSGSBASE = 1 << 0; /// IA32_TSC_ADJUST MSR is supported if 1. (Bit 01) const ADJUST_MSR = 1 << 1; /// Bit 02: SGX. Supports IntelĀ® Software Guard Extensions (IntelĀ® SGX Extensions) if 1. const SGX = 1 << 2; /// BMI1 (Bit 03) const BMI1 = 1 << 3; /// HLE (Bit 04) const HLE = 1 << 4; /// AVX2 (Bit 05) const AVX2 = 1 << 5; /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1. const FDP = 1 << 6; /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. (Bit 07) const SMEP = 1 << 7; /// BMI2 (Bit 08) const BMI2 = 1 << 8; /// Supports Enhanced REP MOVSB/STOSB if 1. (Bit 09) const REP_MOVSB_STOSB = 1 << 9; /// INVPCID. If 1, supports INVPCID instruction for system software that manages process-context identifiers. (Bit 10) const INVPCID = 1 << 10; /// RTM (Bit 11) const RTM = 1 << 11; /// Supports Intel Resource Director Technology (RDT) Monitoring. (Bit 12) const RDTM = 1 << 12; /// Deprecates FPU CS and FPU DS values if 1. (Bit 13) const DEPRECATE_FPU_CS_DS = 1 << 13; /// Supports Intel Memory Protection Extensions if set. (Bit 14) const MPX = 1 << 14; /// Supports Intel Resource Director Technology (RDT) Allocation capability if 1. const RDTA = 1 << 15; /// Bit 16: AVX512F. const AVX512F = 1 << 16; /// Bit 17: AVX512DQ. const AVX512DQ = 1 << 17; /// Supports RDSEED. const RDSEED = 1 << 18; /// Supports ADX. const ADX = 1 << 19; /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1. const SMAP = 1 << 20; /// Bit 21: AVX512_IFMA. const AVX512_IFMA = 1 << 21; // Bit 22: Reserved. /// Bit 23: CLFLUSHOPT const CLFLUSHOPT = 1 << 23; /// Bit 24: CLWB. const CLWB = 1 << 24; /// Bit 25: Intel Processor Trace const PROCESSOR_TRACE = 1 << 25; /// Bit 26: AVX512PF. (IntelĀ® Xeon Phiā„¢ only.) const AVX512PF = 1 << 26; /// Bit 27: AVX512ER. (IntelĀ® Xeon Phiā„¢ only.) const AVX512ER = 1 << 27; /// Bit 28: AVX512CD. const AVX512CD = 1 << 28; /// Bit 29: Intel SHA Extensions const SHA = 1 << 29; /// Bit 30: AVX512BW. const AVX512BW = 1 << 30; /// Bit 31: AVX512VL. const AVX512VL = 1 << 31; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeaturesEcx: u32 { /// Bit 0: Prefetch WT1. (IntelĀ® Xeon Phiā„¢ only). const PREFETCHWT1 = 1 << 0; // Bit 01: AVX512_VBMI const AVX512VBMI = 1 << 1; /// Bit 02: UMIP. Supports user-mode instruction prevention if 1. const UMIP = 1 << 2; /// Bit 03: PKU. Supports protection keys for user-mode pages if 1. const PKU = 1 << 3; /// Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instruc-tions). const OSPKE = 1 << 4; /// Bit 5: WAITPKG const WAITPKG = 1 << 5; /// Bit 6: AV512_VBMI2 const AVX512VBMI2 = 1 << 6; /// Bit 7: CET_SS. Supports CET shadow stack features if 1. Processors that set this bit define bits 0..2 of the /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs: /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP. const CETSS = 1 << 7; /// Bit 8: GFNI const GFNI = 1 << 8; /// Bit 9: VAES const VAES = 1 << 9; /// Bit 10: VPCLMULQDQ const VPCLMULQDQ = 1 << 10; /// Bit 11: AVX512_VNNI const AVX512VNNI = 1 << 11; /// Bit 12: AVX512_BITALG const AVX512BITALG = 1 << 12; /// Bit 13: TME_EN. If 1, the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. const TMEEN = 1 << 13; /// Bit 14: AVX512_VPOPCNTDQ const AVX512VPOPCNTDQ = 1 << 14; // Bit 15: Reserved. /// Bit 16: Supports 57-bit linear addresses and five-level paging if 1. const LA57 = 1 << 16; // Bits 21 - 17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode /// Bit 22: RDPID. RDPID and IA32_TSC_AUX are available if 1. const RDPID = 1 << 22; // Bits 29 - 23: Reserved. /// Bit 30: SGX_LC. Supports SGX Launch Configuration if 1. const SGX_LC = 1 << 30; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeaturesEdx: u32 { /// Bit 02: AVX512_4VNNIW. (IntelĀ® Xeon Phiā„¢ only). const AVX512_4VNNIW = 1 << 2; /// Bit 03: AVX512_4FMAPS. (IntelĀ® Xeon Phiā„¢ only). const AVX512_4FMAPS = 1 << 3; /// Bit 08: AVX512_VP2INTERSECT. const AVX512_VP2INTERSECT = 1 << 8; /// Bit 22: AMX-BF16. If 1, the processor supports tile computational operations on bfloat16 numbers. const AMX_BF16 = 1 << 22; /// Bit 23: AVX512_FP16. const AVX512_FP16 = 1 << 23; /// Bit 24: AMX-TILE. If 1, the processor supports tile architecture const AMX_TILE = 1 << 24; /// Bit 25: AMX-INT8. If 1, the processor supports tile computational operations on 8-bit integers. const AMX_INT8 = 1 << 25; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeaturesEax1: u32 { // Some of the Unimplemented bits are reserved and maybe release in future CPUs, see Intel SDM for future features (Date of comment: 07.17.2024) /// Bit 04: AVX_VNNI. AVX (VEX-encoded) versions of the Vector Neural Network Instructions. const AVX_VNNI = 1 << 4; /// Bit 05: AVX512_BF16. Vector Neural Network Instructions supporting BFLOAT16 inputs and conversion instructions from IEEE single precision. const AVX512_BF16 = 1 << 5; /// Bit 10: If 1, supports fast zero-length REP MOVSB. const FZRM = 1 << 10; /// Bit 11: If 1, supports fast short REP STOSB. const FSRS = 1 << 11; /// Bit 12: If 1, supports fast short REP CMPSB, REP SCASB. const FSRCRS = 1 << 12; /// Bit 22: If 1, supports history reset via the HRESET instruction and the IA32_HRESET_ENABLE MSR. When set, indicates that the Processor History Reset Leaf (EAX = 20H) is valid. const HRESET = 1 << 22; /// Bit 23: If 1, supports the AVX-IFMA instructions. const AVX_IFMA = 1 << 23; /// Bit 26: If 1, supports Linear Address Masking. const LAM = 1 << 26; /// Bit 27: If 1, supports the RDMSRLIST and WRMSRLIST instructions and the IA32_BARRIER MSR. const MSRLIST = 1 << 27; /// Bit 30: If 1, supports INVD execution prevention after BIOS Done. const INVD_DISABLE_POST_BIOS_DONE = 1 << 30; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedFeaturesEdx1: u32 { // Some of the Unimplemented bits are reserved and maybe release in future CPUs, see Intel SDM for future features (Date of comment: 07.17.2024) /// Bit 4: If 1, supports the AVX-VNNI-INT8 instructions. const AVX_VNNI_INT8 = 1 << 4; /// Bit 5: If 1, supports the AVX-NE-CONVERT instructions. const AVX_NE_CONVERT = 1 << 5; /// Bit 10: If 1, supports the AVX-VNNI-INT16 instructions const AVX_VNNI_INT16 = 1 << 10; /// Bit 14: If 1, supports the PREFETCHIT0/1 instructions const PREFETCHI = 1 << 14; /// Bit 17: If 1, UIRET sets UIF to the value of bit 1 of the RFLAGS image loaded from the stack const UIRET_UIF = 1 << 17; /// Bit 18: CET_SSS. If 1, indicates that an operating system can enable supervisor shadow stacks as long as it ensures that a supervisor shadow stack cannot become prematurely busy due to page faults const CET_SSS = 1 << 18; /// Bit 19: If 1, supports the IntelĀ® AVX10 instructions and indicates the presence of CPUID Leaf 24H, /// which enumerates version number and supported vector lengths const AVX10 = 1 << 19; } } /// Direct cache access info (LEAF=0x09). /// /// # Platforms /// āŒ AMD (reserved) āœ… Intel pub struct DirectCacheAccessInfo { eax: u32, } impl DirectCacheAccessInfo { /// Value of bits \[31:0\] of IA32_PLATFORM_DCA_CAP MSR (address 1F8H) pub fn get_dca_cap_value(&self) -> u32 { self.eax } } impl Debug for DirectCacheAccessInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("DirectCacheAccessInfo") .field("dca_cap_value", &self.get_dca_cap_value()) .finish() } } /// Info about performance monitoring -- how many counters etc. (LEAF=0x0A) /// /// # Platforms /// āŒ AMD āœ… Intel pub struct PerformanceMonitoringInfo { eax: u32, ebx: PerformanceMonitoringFeaturesEbx, _ecx: u32, edx: u32, } impl PerformanceMonitoringInfo { /// Version ID of architectural performance monitoring. (Bits 07 - 00) pub fn version_id(&self) -> u8 { get_bits(self.eax, 0, 7) as u8 } /// Number of general-purpose performance monitoring counter per logical processor. (Bits 15- 08) pub fn number_of_counters(&self) -> u8 { get_bits(self.eax, 8, 15) as u8 } /// Bit width of general-purpose, performance monitoring counter. (Bits 23 - 16) pub fn counter_bit_width(&self) -> u8 { get_bits(self.eax, 16, 23) as u8 } /// Length of EBX bit vector to enumerate architectural performance monitoring events. (Bits 31 - 24) pub fn ebx_length(&self) -> u8 { get_bits(self.eax, 24, 31) as u8 } /// Number of fixed-function performance counters (if Version ID > 1). (Bits 04 - 00) pub fn fixed_function_counters(&self) -> u8 { get_bits(self.edx, 0, 4) as u8 } /// Bit width of fixed-function performance counters (if Version ID > 1). (Bits 12- 05) pub fn fixed_function_counters_bit_width(&self) -> u8 { get_bits(self.edx, 5, 12) as u8 } check_bit_fn!( doc = "AnyThread deprecation", has_any_thread_deprecation, edx, 15 ); check_flag!( doc = "Core cycle event not available if 1.", is_core_cyc_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE ); check_flag!( doc = "Instruction retired event not available if 1.", is_inst_ret_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE ); check_flag!( doc = "Reference cycles event not available if 1.", is_ref_cycle_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE ); check_flag!( doc = "Last-level cache reference event not available if 1.", is_cache_ref_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE ); check_flag!( doc = "Last-level cache misses event not available if 1.", is_ll_cache_miss_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE ); check_flag!( doc = "Branch instruction retired event not available if 1.", is_branch_inst_ret_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE ); check_flag!( doc = "Branch mispredict retired event not available if 1.", is_branch_midpred_ev_unavailable, ebx, PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE ); } impl Debug for PerformanceMonitoringInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("PerformanceMonitoringInfo") .field("version_id", &self.version_id()) .field("number_of_counters", &self.number_of_counters()) .field("counter_bit_width", &self.counter_bit_width()) .field("ebx_length", &self.ebx_length()) .field("fixed_function_counters", &self.fixed_function_counters()) .field( "fixed_function_counters_bit_width", &self.fixed_function_counters_bit_width(), ) .finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct PerformanceMonitoringFeaturesEbx: u32 { /// Core cycle event not available if 1. (Bit 0) const CORE_CYC_EV_UNAVAILABLE = 1 << 0; /// Instruction retired event not available if 1. (Bit 01) const INST_RET_EV_UNAVAILABLE = 1 << 1; /// Reference cycles event not available if 1. (Bit 02) const REF_CYC_EV_UNAVAILABLE = 1 << 2; /// Last-level cache reference event not available if 1. (Bit 03) const CACHE_REF_EV_UNAVAILABLE = 1 << 3; /// Last-level cache misses event not available if 1. (Bit 04) const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4; /// Branch instruction retired event not available if 1. (Bit 05) const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5; /// Branch mispredict retired event not available if 1. (Bit 06) const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6; } } /// Information about topology (LEAF=0x0B). /// /// Iterates over the system topology in order to retrieve more system /// information at each level of the topology: how many cores and what kind of /// cores /// /// # Platforms /// āœ… AMD āœ… Intel #[derive(Clone)] pub struct ExtendedTopologyIter { read: R, level: u32, is_v2: bool, } /// Gives information about the current level in the topology. /// /// How many cores, what type etc. #[derive(PartialEq, Eq)] pub struct ExtendedTopologyLevel { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl fmt::Debug for ExtendedTopologyLevel { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ExtendedTopologyLevel") .field("processors", &self.processors()) .field("number", &self.level_number()) .field("type", &self.level_type()) .field("x2apic_id", &self.x2apic_id()) .field("next_apic_id", &self.shift_right_for_next_apic_id()) .finish() } } impl ExtendedTopologyLevel { /// Number of logical processors at this level type. /// The number reflects configuration as shipped. pub fn processors(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } /// Level number. pub fn level_number(&self) -> u8 { get_bits(self.ecx, 0, 7) as u8 } // Level type. pub fn level_type(&self) -> TopologyType { match get_bits(self.ecx, 8, 15) { 0 => TopologyType::Invalid, 1 => TopologyType::SMT, 2 => TopologyType::Core, 3 => TopologyType::Module, 4 => TopologyType::Tile, 5 => TopologyType::Die, _ => unreachable!(), } } /// x2APIC ID the current logical processor. (Bits 31-00) pub fn x2apic_id(&self) -> u32 { self.edx } /// Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type. (Bits 04-00) /// All logical processors with the same next level ID share current level. pub fn shift_right_for_next_apic_id(&self) -> u32 { get_bits(self.eax, 0, 4) } } /// What type of core we have at this level in the topology (real CPU or hyper-threaded). #[derive(PartialEq, Eq, Debug)] pub enum TopologyType { Invalid = 0, /// Hyper-thread (Simultaneous multithreading) SMT = 1, Core = 2, Module = 3, Tile = 4, Die = 5, } impl fmt::Display for TopologyType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let data = match self { TopologyType::Invalid => "Invalid", TopologyType::SMT => "SMT", TopologyType::Core => "Core", TopologyType::Module => "Module", TopologyType::Tile => "Tile", TopologyType::Die => "Die", }; f.write_str(data) } } impl Iterator for ExtendedTopologyIter { type Item = ExtendedTopologyLevel; fn next(&mut self) -> Option { let res = if self.is_v2 { self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level) } else { self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level) }; self.level += 1; let et = ExtendedTopologyLevel { eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }; match et.level_type() { TopologyType::Invalid => None, _ => Some(et), } } } impl Debug for ExtendedTopologyIter { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedStateInfoXCR0Flags: u32 { /// legacy x87 (Bit 00). const LEGACY_X87 = 1 << 0; /// 128-bit SSE (Bit 01). const SSE128 = 1 << 1; /// 256-bit AVX (Bit 02). const AVX256 = 1 << 2; /// MPX BNDREGS (Bit 03). const MPX_BNDREGS = 1 << 3; /// MPX BNDCSR (Bit 04). const MPX_BNDCSR = 1 << 4; /// AVX512 OPMASK (Bit 05). const AVX512_OPMASK = 1 << 5; /// AVX ZMM Hi256 (Bit 06). const AVX512_ZMM_HI256 = 1 << 6; /// AVX 512 ZMM Hi16 (Bit 07). const AVX512_ZMM_HI16 = 1 << 7; /// PKRU state (Bit 09). const PKRU = 1 << 9; /// IA32_XSS HDC State (Bit 13). const IA32_XSS_HDC = 1 << 13; /// AMX TILECFG state (Bit 17) const AMX_TILECFG = 1 << 17; /// AMX TILEDATA state (Bit 17) const AMX_TILEDATA = 1 << 18; } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ExtendedStateInfoXSSFlags: u32 { /// IA32_XSS PT (Trace Packet) State (Bit 08). const PT = 1 << 8; /// IA32_XSS PASID state (Bit 10) const PASID = 1 << 10; /// IA32_XSS CET user state (Bit 11) const CET_USER = 1 << 11; /// IA32_XSS CET supervisor state (Bit 12) const CET_SUPERVISOR = 1 << 12; /// IA32_XSS HDC State (Bit 13). const HDC = 1 << 13; /// IA32_XSS UINTR state (Bit 14) const UINTR = 1 << 14; /// IA32_XSS LBR state (Bit 15) const LBR = 1 << 15; /// IA32_XSS HWP state (Bit 16) const HWP = 1 << 16; } } /// Information for saving/restoring extended register state (LEAF=0x0D). /// /// # Platforms /// āœ… AMD āœ… Intel pub struct ExtendedStateInfo { read: R, eax: ExtendedStateInfoXCR0Flags, ebx: u32, ecx: u32, _edx: u32, eax1: u32, ebx1: u32, ecx1: ExtendedStateInfoXSSFlags, _edx1: u32, } impl ExtendedStateInfo { check_flag!( doc = "Support for legacy x87 in XCR0.", xcr0_supports_legacy_x87, eax, ExtendedStateInfoXCR0Flags::LEGACY_X87 ); check_flag!( doc = "Support for SSE 128-bit in XCR0.", xcr0_supports_sse_128, eax, ExtendedStateInfoXCR0Flags::SSE128 ); check_flag!( doc = "Support for AVX 256-bit in XCR0.", xcr0_supports_avx_256, eax, ExtendedStateInfoXCR0Flags::AVX256 ); check_flag!( doc = "Support for MPX BNDREGS in XCR0.", xcr0_supports_mpx_bndregs, eax, ExtendedStateInfoXCR0Flags::MPX_BNDREGS ); check_flag!( doc = "Support for MPX BNDCSR in XCR0.", xcr0_supports_mpx_bndcsr, eax, ExtendedStateInfoXCR0Flags::MPX_BNDCSR ); check_flag!( doc = "Support for AVX512 OPMASK in XCR0.", xcr0_supports_avx512_opmask, eax, ExtendedStateInfoXCR0Flags::AVX512_OPMASK ); check_flag!( doc = "Support for AVX512 ZMM Hi256 XCR0.", xcr0_supports_avx512_zmm_hi256, eax, ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256 ); check_flag!( doc = "Support for AVX512 ZMM Hi16 in XCR0.", xcr0_supports_avx512_zmm_hi16, eax, ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16 ); check_flag!( doc = "Support for PKRU in XCR0.", xcr0_supports_pkru, eax, ExtendedStateInfoXCR0Flags::PKRU ); check_flag!( doc = "Support for PT in IA32_XSS.", ia32_xss_supports_pt, ecx1, ExtendedStateInfoXSSFlags::PT ); check_flag!( doc = "Support for HDC in IA32_XSS.", ia32_xss_supports_hdc, ecx1, ExtendedStateInfoXSSFlags::HDC ); /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by /// enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area /// are not enabled. pub fn xsave_area_size_enabled_features(&self) -> u32 { self.ebx } /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the /// XSAVE/XRSTOR save area required by all supported features in the processor, /// i.e all the valid bit fields in XCR0. pub fn xsave_area_size_supported_features(&self) -> u32 { self.ecx } /// CPU has xsaveopt feature. pub fn has_xsaveopt(&self) -> bool { self.eax1 & 0x1 > 0 } /// Supports XSAVEC and the compacted form of XRSTOR if set. pub fn has_xsavec(&self) -> bool { self.eax1 & 0b10 > 0 } /// Supports XGETBV with ECX = 1 if set. pub fn has_xgetbv(&self) -> bool { self.eax1 & 0b100 > 0 } /// Supports XSAVES/XRSTORS and IA32_XSS if set. pub fn has_xsaves_xrstors(&self) -> bool { self.eax1 & 0b1000 > 0 } /// The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS. pub fn xsave_size(&self) -> u32 { self.ebx1 } /// Iterator over extended state enumeration levels >= 2. pub fn iter(&self) -> ExtendedStateIter { ExtendedStateIter { read: self.read.clone(), level: 1, supported_xcr0: self.eax.bits(), supported_xss: self.ecx1.bits(), } } } impl Debug for ExtendedStateInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ExtendedStateInfo") .field("eax", &self.eax) .field("ecx1", &self.ecx1) .field( "xsave_area_size_enabled_features", &self.xsave_area_size_enabled_features(), ) .field( "xsave_area_size_supported_features", &self.xsave_area_size_supported_features(), ) .field("has_xsaveopt", &self.has_xsaveopt()) .field("has_xsavec", &self.has_xsavec()) .field("has_xgetbv", &self.has_xgetbv()) .field("has_xsaves_xrstors", &self.has_xsaves_xrstors()) .field("xsave_size", &self.xsave_size()) .field("extended_state_iter", &self.iter()) .finish() } } /// Yields [ExtendedState] structs. #[derive(Clone)] pub struct ExtendedStateIter { read: R, level: u32, supported_xcr0: u32, supported_xss: u32, } /// When CPUID executes with EAX set to 0DH and ECX = n (n > 1, and is a valid /// sub-leaf index), the processor returns information about the size and offset /// of each processor extended state save area within the XSAVE/XRSTOR area. /// /// The iterator goes over the valid sub-leaves and obtain size and offset /// information for each processor extended state save area: impl Iterator for ExtendedStateIter { type Item = ExtendedState; fn next(&mut self) -> Option { self.level += 1; if self.level > 31 { return None; } let bit = 1 << self.level; if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) { let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level); return Some(ExtendedState { subleaf: self.level, eax: res.eax, ebx: res.ebx, ecx: res.ecx, }); } self.next() } } impl Debug for ExtendedStateIter { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } /// What kidn of extended register state this is. #[derive(PartialEq, Eq, Debug)] #[repr(u32)] pub enum ExtendedRegisterType { Avx, MpxBndregs, MpxBndcsr, Avx512Opmask, Avx512ZmmHi256, Avx512ZmmHi16, Pt, Pkru, Hdc, Unknown(u32), } impl From for ExtendedRegisterType { fn from(value: u32) -> ExtendedRegisterType { match value { 0x2 => ExtendedRegisterType::Avx, 0x3 => ExtendedRegisterType::MpxBndregs, 0x4 => ExtendedRegisterType::MpxBndcsr, 0x5 => ExtendedRegisterType::Avx512Opmask, 0x6 => ExtendedRegisterType::Avx512ZmmHi256, 0x7 => ExtendedRegisterType::Avx512ZmmHi16, 0x8 => ExtendedRegisterType::Pt, 0x9 => ExtendedRegisterType::Pkru, 0xd => ExtendedRegisterType::Hdc, x => ExtendedRegisterType::Unknown(x), } } } impl fmt::Display for ExtendedRegisterType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let data = match self { ExtendedRegisterType::Avx => "AVX/YMM", ExtendedRegisterType::MpxBndregs => "MPX BNDREGS", ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR", ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask", ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256", ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM", ExtendedRegisterType::Pkru => "PKRU", ExtendedRegisterType::Pt => "PT", ExtendedRegisterType::Hdc => "HDC", ExtendedRegisterType::Unknown(t) => { return write!(f, "Unknown({})", t); } }; f.write_str(data) } } /// Where the extended register state is stored. #[derive(PartialEq, Eq, Debug)] pub enum ExtendedRegisterStateLocation { Xcr0, Ia32Xss, } impl fmt::Display for ExtendedRegisterStateLocation { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let data = match self { ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)", ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)", }; f.write_str(data) } } /// ExtendedState subleaf structure for things that need to be restored. pub struct ExtendedState { pub subleaf: u32, eax: u32, ebx: u32, ecx: u32, } impl ExtendedState { /// Returns which register this specific extended subleaf contains information for. pub fn register(&self) -> ExtendedRegisterType { self.subleaf.into() } /// The size in bytes (from the offset specified in EBX) of the save area /// for an extended state feature associated with a valid sub-leaf index, n. /// This field reports 0 if the sub-leaf index, n, is invalid. pub fn size(&self) -> u32 { self.eax } /// The offset in bytes of this extended state components save area /// from the beginning of the XSAVE/XRSTOR area. pub fn offset(&self) -> u32 { self.ebx } pub fn location(&self) -> ExtendedRegisterStateLocation { if self.is_in_xcr0() { ExtendedRegisterStateLocation::Xcr0 } else { ExtendedRegisterStateLocation::Ia32Xss } } /// True if the bit n (corresponding to the sub-leaf index) /// is supported in the IA32_XSS MSR; /// /// # Deprecation note /// This will likely be removed in the future. Use `location()` instead. pub fn is_in_ia32_xss(&self) -> bool { self.ecx & 0b1 > 0 } /// True if bit n is supported in XCR0. /// /// # Deprecation note /// This will likely be removed in the future. Use `location()` instead. pub fn is_in_xcr0(&self) -> bool { self.ecx & 0b1 == 0 } /// Returns true when the compacted format of an XSAVE area is used, /// this extended state component located on the next 64-byte /// boundary following the preceding state component /// (otherwise, it is located immediately following the preceding state component). pub fn is_compacted_format(&self) -> bool { self.ecx & 0b10 > 0 } } impl Debug for ExtendedState { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("ExtendedState") .field("size", &self.size()) .field("offset", &self.offset()) .field("is_in_ia32_xss", &self.is_in_ia32_xss()) .field("is_in_xcr0", &self.is_in_xcr0()) .field("is_compacted_format", &self.is_compacted_format()) .finish() } } /// Intel Resource Director Technology RDT (LEAF=0x0F). /// /// Monitoring Enumeration Sub-leaf (EAX = 0FH, ECX = 0 and ECX = 1) /// # Platforms /// āŒ AMD āœ… Intel pub struct RdtMonitoringInfo { read: R, ebx: u32, edx: u32, } impl RdtMonitoringInfo { /// Maximum range (zero-based) of RMID within this physical processor of all types. pub fn rmid_range(&self) -> u32 { self.ebx } check_bit_fn!( doc = "Supports L3 Cache Intel RDT Monitoring.", has_l3_monitoring, edx, 1 ); /// L3 Cache Monitoring. pub fn l3_monitoring(&self) -> Option { if self.has_l3_monitoring() { let res = self.read.cpuid2(EAX_RDT_MONITORING, 1); Some(L3MonitoringInfo { ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } } impl Debug for RdtMonitoringInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("RdtMonitoringInfo") .field("rmid_range", &self.rmid_range()) .field("l3_monitoring", &self.l3_monitoring()) .finish() } } /// Information about L3 cache monitoring. pub struct L3MonitoringInfo { ebx: u32, ecx: u32, edx: u32, } impl L3MonitoringInfo { /// Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes). pub fn conversion_factor(&self) -> u32 { self.ebx } /// Maximum range (zero-based) of RMID of L3. pub fn maximum_rmid_range(&self) -> u32 { self.ecx } check_bit_fn!( doc = "Supports occupancy monitoring.", has_occupancy_monitoring, edx, 0 ); check_bit_fn!( doc = "Supports total bandwidth monitoring.", has_total_bandwidth_monitoring, edx, 1 ); check_bit_fn!( doc = "Supports local bandwidth monitoring.", has_local_bandwidth_monitoring, edx, 2 ); } impl Debug for L3MonitoringInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("L3MonitoringInfo") .field("conversion_factor", &self.conversion_factor()) .field("maximum_rmid_range", &self.maximum_rmid_range()) .finish() } } /// Quality of service enforcement information (LEAF=0x10). /// /// # Platforms /// āŒ AMD āœ… Intel pub struct RdtAllocationInfo { read: R, ebx: u32, } impl RdtAllocationInfo { check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1); check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2); check_bit_fn!( doc = "Supports Memory Bandwidth Allocation.", has_memory_bandwidth_allocation, ebx, 3 ); /// L3 Cache Allocation Information. pub fn l3_cat(&self) -> Option { if self.has_l3_cat() { let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1); Some(L3CatInfo { eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }) } else { None } } /// L2 Cache Allocation Information. pub fn l2_cat(&self) -> Option { if self.has_l2_cat() { let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2); Some(L2CatInfo { eax: res.eax, ebx: res.ebx, edx: res.edx, }) } else { None } } /// Memory Bandwidth Allocation Information. pub fn memory_bandwidth_allocation(&self) -> Option { if self.has_memory_bandwidth_allocation() { let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3); Some(MemBwAllocationInfo { eax: res.eax, ecx: res.ecx, edx: res.edx, }) } else { None } } } impl Debug for RdtAllocationInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("RdtAllocationInfo") .field("l3_cat", &self.l3_cat()) .field("l2_cat", &self.l2_cat()) .field( "memory_bandwidth_allocation", &self.memory_bandwidth_allocation(), ) .finish() } } /// L3 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=1). pub struct L3CatInfo { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl L3CatInfo { /// Length of the capacity bit mask. pub fn capacity_mask_length(&self) -> u8 { (get_bits(self.eax, 0, 4) + 1) as u8 } /// Bit-granular map of isolation/contention of allocation units. pub fn isolation_bitmap(&self) -> u32 { self.ebx } /// Highest COS number supported for this Leaf. pub fn highest_cos(&self) -> u16 { get_bits(self.edx, 0, 15) as u16 } check_bit_fn!( doc = "Is Code and Data Prioritization Technology supported?", has_code_data_prioritization, ecx, 2 ); } impl Debug for L3CatInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("L3CatInfo") .field("capacity_mask_length", &self.capacity_mask_length()) .field("isolation_bitmap", &self.isolation_bitmap()) .field("highest_cos", &self.highest_cos()) .finish() } } /// L2 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=2). #[derive(Eq, PartialEq)] pub struct L2CatInfo { eax: u32, ebx: u32, edx: u32, } impl L2CatInfo { /// Length of the capacity bit mask. pub fn capacity_mask_length(&self) -> u8 { (get_bits(self.eax, 0, 4) + 1) as u8 } /// Bit-granular map of isolation/contention of allocation units. pub fn isolation_bitmap(&self) -> u32 { self.ebx } /// Highest COS number supported for this Leaf. pub fn highest_cos(&self) -> u16 { get_bits(self.edx, 0, 15) as u16 } } impl Debug for L2CatInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("L2CatInfo") .field("capacity_mask_length", &self.capacity_mask_length()) .field("isolation_bitmap", &self.isolation_bitmap()) .field("highest_cos", &self.highest_cos()) .finish() } } /// Memory Bandwidth Allocation Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=3). #[derive(Eq, PartialEq)] pub struct MemBwAllocationInfo { eax: u32, ecx: u32, edx: u32, } impl MemBwAllocationInfo { /// Reports the maximum MBA throttling value supported for the corresponding ResID. pub fn max_hba_throttling(&self) -> u16 { (get_bits(self.eax, 0, 11) + 1) as u16 } /// Highest COS number supported for this Leaf. pub fn highest_cos(&self) -> u16 { get_bits(self.edx, 0, 15) as u16 } check_bit_fn!( doc = "Reports whether the response of the delay values is linear.", has_linear_response_delay, ecx, 2 ); } impl Debug for MemBwAllocationInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("MemBwAllocationInfo") .field("max_hba_throttling", &self.max_hba_throttling()) .field("highest_cos", &self.highest_cos()) .field( "has_linear_response_delay", &self.has_linear_response_delay(), ) .finish() } } /// Intel SGX Capability Enumeration Leaf (LEAF=0x12). /// /// Two sub-leafs: (EAX = 12H, ECX = 0 and ECX = 1) /// /// # Platforms /// āŒ AMD āœ… Intel pub struct SgxInfo { read: R, eax: u32, ebx: u32, _ecx: u32, edx: u32, eax1: u32, ebx1: u32, ecx1: u32, edx1: u32, } impl SgxInfo { check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0); check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1); check_bit_fn!( doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.", has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext, eax, 5 ); check_bit_fn!( doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.", has_encls_leaves_etrackc_erdinfo_eldbc_elduc, eax, 6 ); /// Bit vector of supported extended SGX features. pub fn miscselect(&self) -> u32 { self.ebx } /// The maximum supported enclave size in non-64-bit mode is 2^retval. pub fn max_enclave_size_non_64bit(&self) -> u8 { get_bits(self.edx, 0, 7) as u8 } /// The maximum supported enclave size in 64-bit mode is 2^retval. pub fn max_enclave_size_64bit(&self) -> u8 { get_bits(self.edx, 8, 15) as u8 } /// Reports the valid bits of SECS.ATTRIBUTES\[127:0\] that software can set with ECREATE. pub fn secs_attributes(&self) -> (u64, u64) { let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32; let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32; (lower, upper) } /// Iterator over SGX sub-leafs. pub fn iter(&self) -> SgxSectionIter { SgxSectionIter { read: self.read.clone(), current: 2, } } } impl Debug for SgxInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("SgxInfo") .field("has_sgx1", &self.has_sgx1()) .field("has_sgx2", &self.has_sgx2()) .field("miscselect", &self.miscselect()) .field( "max_enclave_size_non_64bit", &self.max_enclave_size_non_64bit(), ) .field("max_enclave_size_64bit", &self.max_enclave_size_64bit()) .field( "has_encls_leaves_etrackc_erdinfo_eldbc_elduc", &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(), ) .field( "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext", &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(), ) .field("sgx_section_iter", &self.iter()) .finish() } } /// Iterator over the SGX sub-leafs (ECX >= 2). #[derive(Clone)] pub struct SgxSectionIter { read: R, current: u32, } impl Iterator for SgxSectionIter { type Item = SgxSectionInfo; fn next(&mut self) -> Option { let res = self.read.cpuid2(EAX_SGX, self.current); self.current += 1; match get_bits(res.eax, 0, 3) { 0b0001 => Some(SgxSectionInfo::Epc(EpcSection { eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, })), _ => None, } } } impl Debug for SgxSectionIter { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } /// Intel SGX EPC Enumeration Leaf /// /// Sub-leaves 2 or higher. #[derive(Debug)] pub enum SgxSectionInfo { // This would be nice: https://github.com/rust-lang/rfcs/pull/1450 Epc(EpcSection), } /// EBX:EAX and EDX:ECX provide information on the Enclave Page Cache (EPC) section #[derive(Debug)] pub struct EpcSection { eax: u32, ebx: u32, ecx: u32, edx: u32, } impl EpcSection { /// The physical address of the base of the EPC section pub fn physical_base(&self) -> u64 { let lower = (get_bits(self.eax, 12, 31) << 12) as u64; let upper = (get_bits(self.ebx, 0, 19) as u64) << 32; lower | upper } /// Size of the corresponding EPC section within the Processor Reserved Memory. pub fn size(&self) -> u64 { let lower = (get_bits(self.ecx, 12, 31) << 12) as u64; let upper = (get_bits(self.edx, 0, 19) as u64) << 32; lower | upper } } /// Intel Processor Trace Information (LEAF=0x14). /// /// # Platforms /// āŒ AMD āœ… Intel pub struct ProcessorTraceInfo { _eax: u32, ebx: u32, ecx: u32, _edx: u32, leaf1: Option, } impl ProcessorTraceInfo { // EBX features check_bit_fn!( doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \ that IA32_RTIT_CR3_MATCH MSR can be accessed.", has_rtit_cr3_match, ebx, 0 ); check_bit_fn!( doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.", has_configurable_psb_and_cycle_accurate_mode, ebx, 1 ); check_bit_fn!( doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \ preservation of Intel PT MSRs across warm reset.", has_ip_tracestop_filtering, ebx, 2 ); check_bit_fn!( doc = "If true, Indicates support of MTC timing packet and suppression of \ COFI-based packets.", has_mtc_timing_packet_coefi_suppression, ebx, 3 ); check_bit_fn!( doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \ and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets", has_ptwrite, ebx, 4 ); check_bit_fn!( doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \ enabling Power Event Trace packet generation.", has_power_event_trace, ebx, 5 ); // ECX features check_bit_fn!( doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \ utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \ IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.", has_topa, ecx, 0 ); check_bit_fn!( doc = "If true, ToPA tables can hold any number of output entries, up to the \ maximum allowed by the MaskOrTableOffset field of \ IA32_RTIT_OUTPUT_MASK_PTRS.", has_topa_maximum_entries, ecx, 1 ); check_bit_fn!( doc = "If true, Indicates support of Single-Range Output scheme.", has_single_range_output_scheme, ecx, 2 ); check_bit_fn!( doc = "If true, Indicates support of output to Trace Transport subsystem.", has_trace_transport_subsystem, ecx, 3 ); check_bit_fn!( doc = "If true, Generated packets which contain IP payloads have LIP values, \ which include the CS base component.", has_lip_with_cs_base, ecx, 31 ); /// Number of configurable Address Ranges for filtering (Bits 2:0). pub fn configurable_address_ranges(&self) -> u8 { self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8) } /// Bitmap of supported MTC period encodings (Bit 31:16). pub fn supported_mtc_period_encodings(&self) -> u16 { self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16) } /// Bitmap of supported Cycle Threshold value encodings (Bits 15-0). pub fn supported_cycle_threshold_value_encodings(&self) -> u16 { self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16) } /// Bitmap of supported Configurable PSB frequency encodings (Bit 31:16) pub fn supported_psb_frequency_encodings(&self) -> u16 { self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16) } } impl Debug for ProcessorTraceInfo { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ProcessorTraceInfo") .field( "configurable_address_ranges", &self.configurable_address_ranges(), ) .field( "supported_mtc_period_encodings", &self.supported_mtc_period_encodings(), ) .field( "supported_cycle_threshold_value_encodings", &self.supported_cycle_threshold_value_encodings(), ) .field( "supported_psb_frequency_encodings", &self.supported_psb_frequency_encodings(), ) .finish() } } /// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15). /// /// # Platforms /// āŒ AMD āœ… Intel pub struct TscInfo { eax: u32, ebx: u32, ecx: u32, } impl fmt::Debug for TscInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("TscInfo") .field("denominator", &self.denominator()) .field("numerator", &self.numerator()) .field("nominal_frequency", &self.nominal_frequency()) .field("tsc_frequency", &self.tsc_frequency()) .finish() } } impl TscInfo { /// An unsigned integer which is the denominator of the TSC/ā€core crystal clockā€ ratio. pub fn denominator(&self) -> u32 { self.eax } /// An unsigned integer which is the numerator of the TSC/ā€core crystal clockā€ ratio. /// /// If this is 0, the TSC/ā€core crystal clockā€ ratio is not enumerated. pub fn numerator(&self) -> u32 { self.ebx } /// An unsigned integer which is the nominal frequency of the core crystal clock in Hz. /// /// If this is 0, the nominal core crystal clock frequency is not enumerated. pub fn nominal_frequency(&self) -> u32 { self.ecx } /// ā€œTSC frequencyā€ = ā€œcore crystal clock frequencyā€ * EBX/EAX. pub fn tsc_frequency(&self) -> Option { // In some case TscInfo is a valid leaf, but the values reported are still 0 // we should avoid a division by zero in case denominator ends up being 0. if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 { return None; } Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64) } } /// Processor Frequency Information (LEAF=0x16). /// /// # Platforms /// āŒ AMD āœ… Intel pub struct ProcessorFrequencyInfo { eax: u32, ebx: u32, ecx: u32, } impl ProcessorFrequencyInfo { /// Processor Base Frequency (in MHz). pub fn processor_base_frequency(&self) -> u16 { get_bits(self.eax, 0, 15) as u16 } /// Maximum Frequency (in MHz). pub fn processor_max_frequency(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } /// Bus (Reference) Frequency (in MHz). pub fn bus_frequency(&self) -> u16 { get_bits(self.ecx, 0, 15) as u16 } } impl fmt::Debug for ProcessorFrequencyInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ProcessorFrequencyInfo") .field("processor_base_frequency", &self.processor_base_frequency()) .field("processor_max_frequency", &self.processor_max_frequency()) .field("bus_frequency", &self.bus_frequency()) .finish() } } /// Deterministic Address Translation Structure Iterator (LEAF=0x18). /// /// # Platforms /// āŒ AMD āœ… Intel #[derive(Clone)] pub struct DatIter { read: R, current: u32, count: u32, } impl Iterator for DatIter { type Item = DatInfo; /// Iterate over each sub-leaf with an address translation structure. fn next(&mut self) -> Option { loop { // Sub-leaf index n is invalid if n exceeds the value that sub-leaf 0 returns in EAX if self.current > self.count { return None; } let res = self .read .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current); self.current += 1; // A sub-leaf index is also invalid if EDX[4:0] returns 0. if get_bits(res.edx, 0, 4) == 0 { // Valid sub-leaves do not need to be contiguous or in any particular order. // A valid sub-leaf may be in a higher input ECX value than an invalid sub-leaf // or than a valid sub-leaf of a higher or lower-level struc-ture continue; } return Some(DatInfo { _eax: res.eax, ebx: res.ebx, ecx: res.ecx, edx: res.edx, }); } } } impl Debug for DatIter { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let mut debug = f.debug_list(); self.clone().for_each(|ref item| { debug.entry(item); }); debug.finish() } } /// Deterministic Address Translation Structure pub struct DatInfo { _eax: u32, ebx: u32, ecx: u32, edx: u32, } impl DatInfo { check_bit_fn!( doc = "4K page size entries supported by this structure", has_4k_entries, ebx, 0 ); check_bit_fn!( doc = "2MB page size entries supported by this structure", has_2mb_entries, ebx, 1 ); check_bit_fn!( doc = "4MB page size entries supported by this structure", has_4mb_entries, ebx, 2 ); check_bit_fn!( doc = "1GB page size entries supported by this structure", has_1gb_entries, ebx, 3 ); check_bit_fn!( doc = "Fully associative structure", is_fully_associative, edx, 8 ); /// Partitioning (0: Soft partitioning between the logical processors sharing this structure). pub fn partitioning(&self) -> u8 { get_bits(self.ebx, 8, 10) as u8 } /// Ways of associativity. pub fn ways(&self) -> u16 { get_bits(self.ebx, 16, 31) as u16 } /// Number of Sets. pub fn sets(&self) -> u32 { self.ecx } /// Translation cache type field. pub fn cache_type(&self) -> DatType { match get_bits(self.edx, 0, 4) as u8 { 0b00001 => DatType::DataTLB, 0b00010 => DatType::InstructionTLB, 0b00011 => DatType::UnifiedTLB, 0b00000 => DatType::Null, // should never be returned as this indicates invalid struct! 0b00100 => DatType::LoadOnly, 0b00101 => DatType::StoreOnly, _ => DatType::Unknown, } } /// Translation cache level (starts at 1) pub fn cache_level(&self) -> u8 { get_bits(self.edx, 5, 7) as u8 } /// Maximum number of addressable IDs for logical processors sharing this translation cache pub fn max_addressable_ids(&self) -> u16 { // Add one to the return value to get the result: (get_bits(self.edx, 14, 25) + 1) as u16 } } impl Debug for DatInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("DatInfo") .field("has_4k_entries", &self.has_4k_entries()) .field("has_2mb_entries", &self.has_2mb_entries()) .field("has_4mb_entries", &self.has_4mb_entries()) .field("has_1gb_entries", &self.has_1gb_entries()) .field("is_fully_associative", &self.is_fully_associative()) .finish() } } /// Deterministic Address Translation cache type (EDX bits 04 -- 00) #[derive(Eq, PartialEq, Debug)] pub enum DatType { /// Null (indicates this sub-leaf is not valid). Null = 0b00000, DataTLB = 0b00001, InstructionTLB = 0b00010, /// Some unified TLBs will allow a single TLB entry to satisfy data read/write /// and instruction fetches. Others will require separate entries (e.g., one /// loaded on data read/write and another loaded on an instruction fetch) . /// Please see the IntelĀ® 64 and IA-32 Architectures Optimization Reference Manual /// for details of a particular product. UnifiedTLB = 0b00011, LoadOnly = 0b0100, StoreOnly = 0b0101, Unknown, } impl fmt::Display for DatType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let t = match self { DatType::Null => "invalid (0)", DatType::DataTLB => "Data TLB", DatType::InstructionTLB => "Instruction TLB", DatType::UnifiedTLB => "Unified TLB", DatType::LoadOnly => "Load Only", DatType::StoreOnly => "Store Only", DatType::Unknown => "Unknown", }; f.write_str(t) } } /// SoC vendor specific information (LEAF=0x17). /// /// # Platforms /// āŒ AMD āœ… Intel pub struct SoCVendorInfo { read: R, /// MaxSOCID_Index eax: u32, ebx: u32, ecx: u32, edx: u32, } impl SoCVendorInfo { pub fn get_soc_vendor_id(&self) -> u16 { get_bits(self.ebx, 0, 15) as u16 } pub fn get_project_id(&self) -> u32 { self.ecx } pub fn get_stepping_id(&self) -> u32 { self.edx } pub fn get_vendor_brand(&self) -> Option { // Leaf 17H is valid if MaxSOCID_Index >= 3. if self.eax >= 3 { let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1); let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2); let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3); Some(SoCVendorBrand { data: [r1, r2, r3] }) } else { None } } pub fn get_vendor_attributes(&self) -> Option> { if self.eax > 3 { Some(SoCVendorAttributesIter { read: self.read.clone(), count: self.eax, current: 3, }) } else { None } } } impl fmt::Debug for SoCVendorInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SoCVendorInfo") .field("soc_vendor_id", &self.get_soc_vendor_id()) .field("project_id", &self.get_project_id()) .field("stepping_id", &self.get_stepping_id()) .field("vendor_brand", &self.get_vendor_brand()) .field("vendor_attributes", &self.get_vendor_attributes()) .finish() } } /// Iterator for SoC vendor attributes. pub struct SoCVendorAttributesIter { read: R, count: u32, current: u32, } impl fmt::Debug for SoCVendorAttributesIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SocVendorAttributesIter") .field("count", &self.count) .field("current", &self.current) .finish() } } impl Iterator for SoCVendorAttributesIter { type Item = CpuIdResult; /// Iterate over all SoC vendor specific attributes. fn next(&mut self) -> Option { if self.current > self.count { return None; } self.count += 1; Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count)) } } /// A vendor brand string as queried from the cpuid leaf. #[derive(Debug, PartialEq, Eq)] #[repr(C)] pub struct SoCVendorBrand { data: [CpuIdResult; 3], } impl SoCVendorBrand { /// Return the SocVendorBrand as a string. pub fn as_str(&self) -> &str { let brand_string_start = self as *const SoCVendorBrand as *const u8; let slice = unsafe { // Safety: SoCVendorBrand is laid out with repr(C). slice::from_raw_parts(brand_string_start, size_of::()) }; str::from_utf8(slice).unwrap_or("InvalidSoCVendorString") } #[deprecated( since = "10.0.0", note = "Use idiomatic function name `as_str` instead" )] pub fn as_string(&self) -> &str { self.as_str() } } impl fmt::Display for SoCVendorBrand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.as_str()) } } /// Information about Hypervisor (LEAF=0x4000_0001) /// /// More information about this semi-official leaf can be found here /// pub struct HypervisorInfo { read: R, res: CpuIdResult, } impl fmt::Debug for HypervisorInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("HypervisorInfo") .field("identify", &self.identify()) .field("tsc_frequency", &self.tsc_frequency()) .field("apic_frequency", &self.apic_frequency()) .finish() } } /// Identifies the different Hypervisor products. #[derive(Debug, Eq, PartialEq)] pub enum Hypervisor { Xen, VMware, HyperV, KVM, /// QEMU is the hypervisor identity when QEMU is used /// without an accelerator, such as KVM. QEMU, Bhyve, QNX, ACRN, Unknown(u32, u32, u32), } impl HypervisorInfo { /// Returns the identity of the [`Hypervisor`]. /// /// ## Technical Background /// /// The value is a 12-byte (12 character) fixed-length ASCII string. /// /// Usually all of these IDs can be found in the original source code on /// Github relatively easy (if the project is open source). Once you /// have an ID, you find cumulated lists with all kinds of IDs on Github /// relatively easy. pub fn identify(&self) -> Hypervisor { match (self.res.ebx, self.res.ecx, self.res.edx) { // "VMwareVMware" (0x56 => V, 0x4d => M, ...) (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware, // "XenVMMXenVMM" (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen, // "Microsoft Hv" (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV, // "KVMKVMKVM\0\0\0" (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM, // "TCGTCGTCGTCG" // see https://github.com/qemu/qemu/blob/6512fa497c2fa9751b9d774ab32d87a9764d1958/target/i386/cpu.c (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU, // "bhyve bhyve " // found this in another library ("heim-virt") (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve, // "BHyVE BHyVE " // But this value is in the original source code. To be safe, we keep both. // See https://github.com/lattera/bhyve/blob/5946a9115d2771a1d27f14a835c7fbc05b30f7f9/sys/amd64/vmm/x86.c#L165 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve, // "QNXQVMBSQG" // This can be verified in multiple Git repos (e.g. by Intel) // https://github.com/search?q=QNXQVMBSQG&type=code (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX, // "ACRNACRNACRN" (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN, (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx), } } /// TSC frequency in kHz. pub fn tsc_frequency(&self) -> Option { // vm aware tsc frequency retrieval: // # EAX: (Virtual) TSC frequency in kHz. if self.res.eax >= 0x40000010 { let virt_tinfo = self.read.cpuid2(0x40000010, 0); Some(virt_tinfo.eax) } else { None } } /// (Virtual) Bus (local apic timer) frequency in kHz. pub fn apic_frequency(&self) -> Option { // # EBX: (Virtual) Bus (local apic timer) frequency in kHz. if self.res.eax >= 0x40000010 { let virt_tinfo = self.read.cpuid2(0x40000010, 0); Some(virt_tinfo.ebx) } else { None } } } #[cfg(doctest)] mod test_readme { macro_rules! external_doc_test { ($x:expr) => { #[doc = $x] extern "C" {} }; } external_doc_test!(include_str!("../README.md")); } raw-cpuid-11.6.0/src/tests/i5_3337u.rs000064400000000000000000000561341046102023000152750ustar 00000000000000use crate::*; #[test] fn genuine_intel() { let vf = VendorInfo { ebx: 1970169159, edx: 1231384169, ecx: 1818588270, }; assert!(vf.as_str() == "GenuineIntel"); } #[test] fn feature_info() { let finfo = FeatureInfo { vendor: Vendor::Intel, eax: 198313, ebx: 34605056, edx_ecx: FeatureInfoFlags::from_bits_truncate(2109399999 | 3219913727 << 32), }; assert!(finfo.base_model_id() == 10); assert!(finfo.extended_model_id() == 3); assert!(finfo.stepping_id() == 9); assert!(finfo.extended_family_id() == 0); assert!(finfo.base_family_id() == 6); assert!(finfo.stepping_id() == 9); assert!(finfo.brand_index() == 0); assert!(finfo.edx_ecx.contains(FeatureInfoFlags::SSE2)); assert!(finfo.edx_ecx.contains(FeatureInfoFlags::SSE41)); } #[test] fn cache_info() { let cinfos = CacheInfoIter { current: 1, eax: 1979931137, ebx: 15774463, ecx: 0, edx: 13238272, }; for (idx, cache) in cinfos.enumerate() { match idx { 0 => assert!(cache.num == 0xff), 1 => assert!(cache.num == 0x5a), 2 => assert!(cache.num == 0xb2), 3 => assert!(cache.num == 0x03), 4 => assert!(cache.num == 0xf0), 5 => assert!(cache.num == 0xca), 6 => assert!(cache.num == 0x76), _ => unreachable!(), } } } #[test] fn cache_parameters() { let caches: [CacheParameter; 4] = [ CacheParameter { eax: 469778721, ebx: 29360191, ecx: 63, edx: 0, }, CacheParameter { eax: 469778722, ebx: 29360191, ecx: 63, edx: 0, }, CacheParameter { eax: 469778755, ebx: 29360191, ecx: 511, edx: 0, }, CacheParameter { eax: 470008163, ebx: 46137407, ecx: 4095, edx: 6, }, ]; for (idx, cache) in caches.iter().enumerate() { match idx { 0 => { assert!(cache.cache_type() == CacheType::Data); assert!(cache.level() == 1); assert!(cache.is_self_initializing()); assert!(!cache.is_fully_associative()); assert!(cache.max_cores_for_cache() == 2); assert!(cache.max_cores_for_package() == 8); assert!(cache.coherency_line_size() == 64); assert!(cache.physical_line_partitions() == 1); assert!(cache.associativity() == 8); assert!(!cache.is_write_back_invalidate()); assert!(!cache.is_inclusive()); assert!(!cache.has_complex_indexing()); assert!(cache.sets() == 64); } 1 => { assert!(cache.cache_type() == CacheType::Instruction); assert!(cache.level() == 1); assert!(cache.is_self_initializing()); assert!(!cache.is_fully_associative()); assert!(cache.max_cores_for_cache() == 2); assert!(cache.max_cores_for_package() == 8); assert!(cache.coherency_line_size() == 64); assert!(cache.physical_line_partitions() == 1); assert!(cache.associativity() == 8); assert!(!cache.is_write_back_invalidate()); assert!(!cache.is_inclusive()); assert!(!cache.has_complex_indexing()); assert!(cache.sets() == 64); } 2 => { assert!(cache.cache_type() == CacheType::Unified); assert!(cache.level() == 2); assert!(cache.is_self_initializing()); assert!(!cache.is_fully_associative()); assert!(cache.max_cores_for_cache() == 2); assert!(cache.max_cores_for_package() == 8); assert!(cache.coherency_line_size() == 64); assert!(cache.physical_line_partitions() == 1); assert!(cache.associativity() == 8); assert!(!cache.is_write_back_invalidate()); assert!(!cache.is_inclusive()); assert!(!cache.has_complex_indexing()); assert!(cache.sets() == 512); } 3 => { assert!(cache.cache_type() == CacheType::Unified); assert!(cache.level() == 3); assert!(cache.is_self_initializing()); assert!(!cache.is_fully_associative()); assert!(cache.max_cores_for_cache() == 16); assert!(cache.max_cores_for_package() == 8); assert!(cache.coherency_line_size() == 64); assert!(cache.physical_line_partitions() == 1); assert!(cache.associativity() == 12); assert!(!cache.is_write_back_invalidate()); assert!(cache.is_inclusive()); assert!(cache.has_complex_indexing()); assert!(cache.sets() == 4096); } _ => unreachable!(), } } } #[test] fn monitor_mwait_features() { let mmfeatures = MonitorMwaitInfo { eax: 64, ebx: 64, ecx: 3, edx: 135456, }; assert!(mmfeatures.smallest_monitor_line() == 64); assert!(mmfeatures.largest_monitor_line() == 64); assert!(mmfeatures.extensions_supported()); assert!(mmfeatures.interrupts_as_break_event()); assert!(mmfeatures.supported_c0_states() == 0); assert!(mmfeatures.supported_c1_states() == 2); assert!(mmfeatures.supported_c2_states() == 1); assert!(mmfeatures.supported_c3_states() == 1); assert!(mmfeatures.supported_c4_states() == 2); assert!(mmfeatures.supported_c5_states() == 0); assert!(mmfeatures.supported_c6_states() == 0); assert!(mmfeatures.supported_c7_states() == 0); } #[test] fn thermal_power_features() { let tpfeatures = ThermalPowerInfo { eax: ThermalPowerFeaturesEax::from_bits_truncate(119), ebx: 2, ecx: ThermalPowerFeaturesEcx::from_bits_truncate(9), _edx: 0, }; assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::DTS)); assert!(tpfeatures .eax .contains(ThermalPowerFeaturesEax::TURBO_BOOST)); assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::ARAT)); assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::PLN)); assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::ECMD)); assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::PTM)); assert!(tpfeatures .ecx .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)); assert!(tpfeatures .ecx .contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)); assert!(tpfeatures.dts_irq_threshold() == 0x2); let tpfeatures = ThermalPowerInfo { eax: ThermalPowerFeaturesEax::DTS | ThermalPowerFeaturesEax::TURBO_BOOST | ThermalPowerFeaturesEax::ARAT | ThermalPowerFeaturesEax::PLN | ThermalPowerFeaturesEax::ECMD | ThermalPowerFeaturesEax::PTM | ThermalPowerFeaturesEax::HWP | ThermalPowerFeaturesEax::HWP_NOTIFICATION | ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW | ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE | ThermalPowerFeaturesEax::HDC, ebx: 2, ecx: ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK | ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF, _edx: 0, }; assert!(tpfeatures.has_dts()); assert!(!tpfeatures.has_turbo_boost3()); assert!(tpfeatures.has_turbo_boost()); assert!(tpfeatures.has_arat()); assert!(tpfeatures.has_pln()); assert!(tpfeatures.has_ecmd()); assert!(tpfeatures.has_ptm()); assert!(tpfeatures.has_hwp()); assert!(tpfeatures.has_hwp_notification()); assert!(tpfeatures.has_hwp_activity_window()); assert!(tpfeatures.has_hwp_energy_performance_preference()); assert!(!tpfeatures.has_hwp_package_level_request()); assert!(tpfeatures.has_hdc()); assert!(tpfeatures.has_hw_coord_feedback()); assert!(tpfeatures.has_energy_bias_pref()); assert!(tpfeatures.dts_irq_threshold() == 0x2); } #[test] fn extended_features() { let tpfeatures = ExtendedFeatures { _eax: 0, ebx: ExtendedFeaturesEbx::from_bits_truncate(641), ecx: ExtendedFeaturesEcx::from_bits_truncate(0), edx: ExtendedFeaturesEdx::from_bits_truncate(0), eax1: ExtendedFeaturesEax1::from_bits_truncate(0), _ebx1: 0, _ecx1: 0, edx1: ExtendedFeaturesEdx1::from_bits_truncate(0), }; assert!(tpfeatures._eax == 0); assert!(tpfeatures.has_fsgsbase()); assert!(!tpfeatures.has_tsc_adjust_msr()); assert!(!tpfeatures.has_bmi1()); assert!(!tpfeatures.has_hle()); assert!(!tpfeatures.has_avx2()); assert!(tpfeatures.has_smep()); assert!(!tpfeatures.has_bmi2()); assert!(tpfeatures.has_rep_movsb_stosb()); assert!(!tpfeatures.has_invpcid()); assert!(!tpfeatures.has_rtm()); assert!(!tpfeatures.has_rdtm()); assert!(!tpfeatures.has_fpu_cs_ds_deprecated()); let tpfeatures2 = ExtendedFeatures { _eax: 0, ebx: ExtendedFeaturesEbx::FSGSBASE | ExtendedFeaturesEbx::ADJUST_MSR | ExtendedFeaturesEbx::BMI1 | ExtendedFeaturesEbx::AVX2 | ExtendedFeaturesEbx::SMEP | ExtendedFeaturesEbx::BMI2 | ExtendedFeaturesEbx::REP_MOVSB_STOSB | ExtendedFeaturesEbx::INVPCID | ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS | ExtendedFeaturesEbx::MPX | ExtendedFeaturesEbx::RDSEED | ExtendedFeaturesEbx::ADX | ExtendedFeaturesEbx::SMAP | ExtendedFeaturesEbx::CLFLUSHOPT | ExtendedFeaturesEbx::PROCESSOR_TRACE, ecx: ExtendedFeaturesEcx::from_bits_truncate(0), edx: ExtendedFeaturesEdx::from_bits_truncate(201326592), eax1: ExtendedFeaturesEax1::from_bits_truncate(0), _ebx1: 0, _ecx1: 0, edx1: ExtendedFeaturesEdx1::from_bits_truncate(0), }; assert!(tpfeatures2.has_fsgsbase()); assert!(tpfeatures2.has_tsc_adjust_msr()); assert!(tpfeatures2.has_bmi1()); assert!(tpfeatures2.has_avx2()); assert!(tpfeatures2.has_smep()); assert!(tpfeatures2.has_bmi2()); assert!(tpfeatures2.has_rep_movsb_stosb()); assert!(tpfeatures2.has_invpcid()); assert!(tpfeatures2.has_fpu_cs_ds_deprecated()); assert!(tpfeatures2.has_mpx()); assert!(tpfeatures2.has_rdseed()); assert!(tpfeatures2.has_adx()); assert!(tpfeatures2.has_smap()); assert!(tpfeatures2.has_clflushopt()); assert!(tpfeatures2.has_processor_trace()); assert!(!tpfeatures2.has_avx512_4vnniw()); assert!(!tpfeatures2.has_avx512_4fmaps()); assert!(!tpfeatures2.has_avx512_vp2intersect()); assert!(!tpfeatures2.has_amx_bf16()); assert!(!tpfeatures2.has_avx512_fp16()); assert!(!tpfeatures2.has_amx_tile()); assert!(!tpfeatures2.has_amx_int8()); assert!(!tpfeatures2.has_avx_vnni()); assert!(!tpfeatures2.has_avx512_bf16()); assert!(!tpfeatures2.has_fzrm()); assert!(!tpfeatures2.has_fsrs()); assert!(!tpfeatures2.has_fsrcrs()); assert!(!tpfeatures2.has_hreset()); assert!(!tpfeatures2.has_avx_ifma()); assert!(!tpfeatures2.has_lam()); assert!(!tpfeatures2.has_msrlist()); assert!(!tpfeatures2.has_invd_disable_post_bios_done()); assert!(!tpfeatures2.has_avx_vnni_int8()); assert!(!tpfeatures2.has_avx_ne_convert()); assert!(!tpfeatures2.has_avx_vnni_int16()); assert!(!tpfeatures2.has_prefetchi()); assert!(!tpfeatures2.has_uiret_uif()); assert!(!tpfeatures2.has_cet_sss()); assert!(!tpfeatures2.has_avx10()); } #[test] fn direct_cache_access_info() { let dca = DirectCacheAccessInfo { eax: 0x1 }; assert!(dca.get_dca_cap_value() == 0x1); } #[test] fn performance_monitoring_info() { let pm = PerformanceMonitoringInfo { eax: 120587267, ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(0), _ecx: 0, edx: 1539, }; assert!(pm.version_id() == 3); assert!(pm.number_of_counters() == 4); assert!(pm.counter_bit_width() == 48); assert!(pm.ebx_length() == 7); assert!(pm.fixed_function_counters() == 3); assert!(pm.fixed_function_counters_bit_width() == 48); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE)); assert!(!pm .ebx .contains(PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE)); } #[cfg(test)] #[test] fn extended_topology_info() { let l1 = ExtendedTopologyLevel { eax: 1, ebx: 2, ecx: 256, edx: 3, }; let l2 = ExtendedTopologyLevel { eax: 4, ebx: 4, ecx: 513, edx: 3, }; assert!(l1.processors() == 2); assert!(l1.level_number() == 0); assert!(l1.level_type() == TopologyType::SMT); assert!(l1.x2apic_id() == 3); assert!(l1.shift_right_for_next_apic_id() == 1); assert!(l2.processors() == 4); assert!(l2.level_number() == 1); assert!(l2.level_type() == TopologyType::Core); assert!(l2.x2apic_id() == 3); assert!(l2.shift_right_for_next_apic_id() == 4); } #[cfg(test)] #[test] fn extended_topology_info_v2() { let l1 = ExtendedTopologyLevel { eax: 1, ebx: 2, ecx: 256, edx: 3, }; let l2 = ExtendedTopologyLevel { eax: 4, ebx: 4, ecx: 513, edx: 3, }; assert!(l1.processors() == 2); assert!(l1.level_number() == 0); assert!(l1.level_type() == TopologyType::SMT); assert!(l1.x2apic_id() == 3); assert!(l1.shift_right_for_next_apic_id() == 1); assert!(l2.processors() == 4); assert!(l2.level_number() == 1); assert!(l2.level_type() == TopologyType::Core); assert!(l2.x2apic_id() == 3); assert!(l2.shift_right_for_next_apic_id() == 4); } #[test] fn extended_state_info() { let es = ExtendedStateInfo { read: CpuIdReaderNative, eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(7), ebx: 832, ecx: 832, _edx: 0, eax1: 1, ebx1: 0, ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(0), _edx1: 0, }; assert!(es.xsave_area_size_enabled_features() == 832); assert!(es.xsave_area_size_supported_features() == 832); assert!(es.has_xsaveopt()); } #[test] fn extended_state_info3() { /*let cpuid = CpuId::new(); cpuid.get_extended_state_info().map(|info| { println!("{:?}", info); use std::vec::Vec; let es: Vec = info.iter().collect(); println!("{:?}", es); });*/ let esi = ExtendedStateInfo { read: CpuIdReaderNative, eax: ExtendedStateInfoXCR0Flags::LEGACY_X87 | ExtendedStateInfoXCR0Flags::SSE128 | ExtendedStateInfoXCR0Flags::AVX256 | ExtendedStateInfoXCR0Flags::MPX_BNDREGS | ExtendedStateInfoXCR0Flags::MPX_BNDCSR | ExtendedStateInfoXCR0Flags::AVX512_OPMASK | ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256 | ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16 | ExtendedStateInfoXCR0Flags::PKRU, ebx: 2688, ecx: 2696, _edx: 0, eax1: 15, ebx1: 2560, ecx1: ExtendedStateInfoXSSFlags::PT, _edx1: 0, }; assert!(esi.xcr0_supports_legacy_x87()); assert!(esi.xcr0_supports_sse_128()); assert!(esi.xcr0_supports_avx_256()); assert!(esi.xcr0_supports_mpx_bndregs()); assert!(esi.xcr0_supports_mpx_bndcsr()); assert!(esi.xcr0_supports_avx512_opmask()); assert!(esi.xcr0_supports_avx512_zmm_hi256()); assert!(esi.xcr0_supports_avx512_zmm_hi16()); assert!(esi.xcr0_supports_pkru()); assert!(esi.ia32_xss_supports_pt()); assert!(!esi.ia32_xss_supports_hdc()); assert!(esi.xsave_area_size_enabled_features() == 2688); assert!(esi.xsave_area_size_supported_features() == 2696); assert!(esi.has_xsaveopt()); assert!(esi.has_xsavec()); assert!(esi.has_xgetbv()); assert!(esi.has_xsaves_xrstors()); assert!(esi.xsave_size() == 2560); let es = [ ExtendedState { subleaf: 2, eax: 256, ebx: 576, ecx: 0, }, ExtendedState { subleaf: 3, eax: 64, ebx: 960, ecx: 0, }, ExtendedState { subleaf: 4, eax: 64, ebx: 1024, ecx: 0, }, ExtendedState { subleaf: 5, eax: 64, ebx: 1088, ecx: 0, }, ExtendedState { subleaf: 6, eax: 512, ebx: 1152, ecx: 0, }, ExtendedState { subleaf: 7, eax: 1024, ebx: 1664, ecx: 0, }, ExtendedState { subleaf: 8, eax: 128, ebx: 0, ecx: 1, }, ExtendedState { subleaf: 9, eax: 8, ebx: 2688, ecx: 0, }, ]; let e = &es[0]; assert!(e.subleaf == 2); assert!(e.size() == 256); assert!(e.offset() == 576); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[1]; assert!(e.subleaf == 3); assert!(e.size() == 64); assert!(e.offset() == 960); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[2]; assert!(e.subleaf == 4); assert!(e.size() == 64); assert!(e.offset() == 1024); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[3]; assert!(e.subleaf == 5); assert!(e.size() == 64); assert!(e.offset() == 1088); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[4]; assert!(e.subleaf == 6); assert!(e.size() == 512); assert!(e.offset() == 1152); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[5]; assert!(e.subleaf == 7); assert!(e.size() == 1024); assert!(e.offset() == 1664); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[6]; assert!(e.subleaf == 8); assert!(e.size() == 128); assert!(e.offset() == 0); assert!(!e.is_in_xcr0()); assert!(e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); let e = &es[7]; assert!(e.subleaf == 9); assert!(e.size() == 8); assert!(e.offset() == 2688); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); assert!(!e.is_compacted_format()); } #[test] fn extended_state_info2() { let es = ExtendedStateInfo { read: CpuIdReaderNative, eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(31), ebx: 1088, ecx: 1088, _edx: 0, eax1: 15, ebx1: 960, ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(256), _edx1: 0, }; assert!(es.xcr0_supports_legacy_x87()); assert!(es.xcr0_supports_sse_128()); assert!(es.xcr0_supports_avx_256()); assert!(es.xcr0_supports_mpx_bndregs()); assert!(es.xcr0_supports_mpx_bndcsr()); assert!(!es.xcr0_supports_avx512_opmask()); assert!(!es.xcr0_supports_pkru()); assert!(es.ia32_xss_supports_pt()); assert!(es.xsave_area_size_enabled_features() == 0x440); assert!(es.xsave_area_size_supported_features() == 0x440); assert!(es.has_xsaveopt()); assert!(es.has_xsavec()); assert!(es.has_xgetbv()); assert!(es.has_xsaves_xrstors()); assert!(es.xsave_size() == 0x3c0); let esiter: [ExtendedState; 3] = [ ExtendedState { subleaf: 2, eax: 256, ebx: 576, ecx: 0, }, ExtendedState { subleaf: 3, eax: 64, ebx: 960, ecx: 0, }, ExtendedState { subleaf: 4, eax: 64, ebx: 1024, ecx: 0, }, ]; let e = &esiter[0]; assert!(e.subleaf == 2); assert!(e.size() == 256); assert!(e.offset() == 576); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); let e = &esiter[1]; assert!(e.subleaf == 3); assert!(e.size() == 64); assert!(e.offset() == 960); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); let e = &esiter[2]; assert!(e.subleaf == 4); assert!(e.size() == 64); assert!(e.offset() == 1024); assert!(e.is_in_xcr0()); assert!(!e.is_in_ia32_xss()); } #[test] fn quality_of_service_info() { let qos = RdtMonitoringInfo { read: CpuIdReaderNative, ebx: 832, edx: 0, }; assert!(qos.rmid_range() == 832); assert!(!qos.has_l3_monitoring()); } #[test] fn extended_processor_feature_identifiers() { let ef = ExtendedProcessorFeatureIdentifiers::new( Vendor::Intel, CpuIdResult { eax: 0, ebx: 0, ecx: 1, edx: 672139264, }, ); assert!(ef.has_lahf_sahf()); assert!(!ef.has_lzcnt()); assert!(!ef.has_prefetchw()); assert!(ef.has_syscall_sysret()); assert!(ef.has_execute_disable()); assert!(!ef.has_1gib_pages()); assert!(ef.has_rdtscp()); assert!(ef.has_64bit_mode()); } #[test] fn processor_brand_string() { let pbs = crate::extended::ProcessorBrandString::new([ CpuIdResult { eax: 538976288, ebx: 1226842144, ecx: 1818588270, edx: 539578920, }, CpuIdResult { eax: 1701998403, ebx: 692933672, ecx: 758475040, edx: 926102323, }, CpuIdResult { eax: 1346576469, ebx: 541073493, ecx: 808988209, edx: 8013895, }, ]); assert_eq!(pbs.as_str(), "Intel(R) Core(TM) i5-3337U CPU @ 1.80GHz"); } #[cfg(test)] #[test] fn sgx_test() { let sgx = SgxInfo { read: CpuIdReaderNative, eax: 1, ebx: 0, _ecx: 0, edx: 9247, eax1: 54, ebx1: 0, ecx1: 31, edx1: 0, }; assert!(sgx.max_enclave_size_64bit() == 0x24); assert!(sgx.max_enclave_size_non_64bit() == 0x1f); assert!(sgx.has_sgx1()); assert!(!sgx.has_sgx2()); assert!(sgx.miscselect() == 0x0); assert!(sgx.secs_attributes() == (0x0000000000000036, 0x000000000000001f)); } raw-cpuid-11.6.0/src/tests/i7_12700k.rs000064400000000000000000002122731046102023000153350ustar 00000000000000use crate::{CpuId, CpuIdResult}; // CPU: // vendor_id = "GenuineIntel" // version information (1/eax): // processor type = primary processor (0) // family = 0x6 (6) // model = 0x7 (7) // stepping id = 0x2 (2) // extended family = 0x0 (0) // extended model = 0x9 (9) // (family synth) = 0x6 (6) // (model synth) = 0x97 (151) // (simple synth) = Intel Atom (Alder Lake-S) [Golden Cove], 10nm // miscellaneous (1/ebx): // process local APIC physical ID = 0x0 (0) // maximum IDs for CPUs in pkg = 0x80 (128) // CLFLUSH line size = 0x8 (8) // brand index = 0x0 (0) // brand id = 0x00 (0): unknown // feature information (1/edx): // x87 FPU on chip = true // VME: virtual-8086 mode enhancement = true // DE: debugging extensions = true // PSE: page size extensions = true // TSC: time stamp counter = true // RDMSR and WRMSR support = true // PAE: physical address extensions = true // MCE: machine check exception = true // CMPXCHG8B inst. = true // APIC on chip = true // SYSENTER and SYSEXIT = true // MTRR: memory type range registers = true // PTE global bit = true // MCA: machine check architecture = true // CMOV: conditional move/compare instr = true // PAT: page attribute table = true // PSE-36: page size extension = true // PSN: processor serial number = false // CLFLUSH instruction = true // DS: debug store = true // ACPI: thermal monitor and clock ctrl = true // MMX Technology = true // FXSAVE/FXRSTOR = true // SSE extensions = true // SSE2 extensions = true // SS: self snoop = true // hyper-threading / multi-core supported = true // TM: therm. monitor = true // IA64 = false // PBE: pending break event = true // feature information (1/ecx): // PNI/SSE3: Prescott New Instructions = true // PCLMULDQ instruction = true // DTES64: 64-bit debug store = true // MONITOR/MWAIT = true // CPL-qualified debug store = true // VMX: virtual machine extensions = true // SMX: safer mode extensions = true // Enhanced Intel SpeedStep Technology = true // TM2: thermal monitor 2 = true // SSSE3 extensions = true // context ID: adaptive or shared L1 data = false // SDBG: IA32_DEBUG_INTERFACE = true // FMA instruction = true // CMPXCHG16B instruction = true // xTPR disable = true // PDCM: perfmon and debug = true // PCID: process context identifiers = true // DCA: direct cache access = false // SSE4.1 extensions = true // SSE4.2 extensions = true // x2APIC: extended xAPIC support = true // MOVBE instruction = true // POPCNT instruction = true // time stamp counter deadline = true // AES instruction = true // XSAVE/XSTOR states = true // OS-enabled XSAVE/XSTOR = true // AVX: advanced vector extensions = true // F16C half-precision convert instruction = true // RDRAND instruction = true // hypervisor guest status = false // cache and TLB information (2): // 0xff: cache data is in CPUID leaf 4 // 0xfe: TLB data is in CPUID leaf 0x18 // 0xf0: 64 byte prefetching // processor serial number = 0009-0672-0000-0000-0000-0000 // deterministic cache parameters (4): // --- cache 0 --- // cache type = data cache (1) // cache level = 0x1 (1) // self-initializing cache level = true // fully associative cache = false // maximum IDs for CPUs sharing cache = 0x1 (1) // maximum IDs for cores in pkg = 0x3f (63) // system coherency line size = 0x40 (64) // physical line partitions = 0x1 (1) // ways of associativity = 0xc (12) // number of sets = 0x40 (64) // WBINVD/INVD acts on lower caches = false // inclusive to lower caches = false // complex cache indexing = false // number of sets (s) = 64 // (size synth) = 49152 (48 KB) // --- cache 1 --- // cache type = instruction cache (2) // cache level = 0x1 (1) // self-initializing cache level = true // fully associative cache = false // maximum IDs for CPUs sharing cache = 0x1 (1) // maximum IDs for cores in pkg = 0x3f (63) // system coherency line size = 0x40 (64) // physical line partitions = 0x1 (1) // ways of associativity = 0x8 (8) // number of sets = 0x40 (64) // WBINVD/INVD acts on lower caches = false // inclusive to lower caches = false // complex cache indexing = false // number of sets (s) = 64 // (size synth) = 32768 (32 KB) // --- cache 2 --- // cache type = unified cache (3) // cache level = 0x2 (2) // self-initializing cache level = true // fully associative cache = false // maximum IDs for CPUs sharing cache = 0x7 (7) // maximum IDs for cores in pkg = 0x3f (63) // system coherency line size = 0x40 (64) // physical line partitions = 0x1 (1) // ways of associativity = 0xa (10) // number of sets = 0x800 (2048) // WBINVD/INVD acts on lower caches = false // inclusive to lower caches = false // complex cache indexing = false // number of sets (s) = 2048 // (size synth) = 1310720 (1.2 MB) // --- cache 3 --- // cache type = unified cache (3) // cache level = 0x3 (3) // self-initializing cache level = true // fully associative cache = false // maximum IDs for CPUs sharing cache = 0x7f (127) // maximum IDs for cores in pkg = 0x3f (63) // system coherency line size = 0x40 (64) // physical line partitions = 0x1 (1) // ways of associativity = 0xa (10) // number of sets = 0xa000 (40960) // WBINVD/INVD acts on lower caches = false // inclusive to lower caches = false // complex cache indexing = true // number of sets (s) = 40960 // (size synth) = 26214400 (25 MB) // MONITOR/MWAIT (5): // smallest monitor-line size (bytes) = 0x40 (64) // largest monitor-line size (bytes) = 0x40 (64) // enum of Monitor-MWAIT exts supported = true // supports intrs as break-event for MWAIT = true // number of C0 sub C-states using MWAIT = 0x0 (0) // number of C1 sub C-states using MWAIT = 0x2 (2) // number of C2 sub C-states using MWAIT = 0x0 (0) // number of C3 sub C-states using MWAIT = 0x2 (2) // number of C4 sub C-states using MWAIT = 0x0 (0) // number of C5 sub C-states using MWAIT = 0x1 (1) // number of C6 sub C-states using MWAIT = 0x0 (0) // number of C7 sub C-states using MWAIT = 0x1 (1) // Thermal and Power Management Features (6): // digital thermometer = true // Intel Turbo Boost Technology = true // ARAT always running APIC timer = true // PLN power limit notification = true // ECMD extended clock modulation duty = true // PTM package thermal management = true // HWP base registers = true // HWP notification = true // HWP activity window = true // HWP energy performance preference = true // HWP package level request = true // HDC base registers = false // Intel Turbo Boost Max Technology 3.0 = true // HWP capabilities = true // HWP PECI override = true // flexible HWP = true // IA32_HWP_REQUEST MSR fast access mode = true // HW_FEEDBACK MSRs supported = true // ignoring idle logical processor HWP req = true // enhanced hardware feedback interface = true // digital thermometer thresholds = 0x2 (2) // hardware coordination feedback = true // ACNT2 available = false // performance-energy bias capability = false // number of enh hardware feedback classes = 0x4 (4) // performance capability reporting = true // energy efficiency capability reporting = true // size of feedback struct (4KB pages) = 0x1 (1) // index of CPU's row in feedback struct = 0x0 (0) // extended feature flags (7): // FSGSBASE instructions = true // IA32_TSC_ADJUST MSR supported = true // SGX: Software Guard Extensions supported = false // BMI1 instructions = true // HLE hardware lock elision = false // AVX2: advanced vector extensions 2 = true // FDP_EXCPTN_ONLY = true // SMEP supervisor mode exec protection = true // BMI2 instructions = true // enhanced REP MOVSB/STOSB = true // INVPCID instruction = true // RTM: restricted transactional memory = false // RDT-CMT/PQoS cache monitoring = false // deprecated FPU CS/DS = true // MPX: intel memory protection extensions = false // RDT-CAT/PQE cache allocation = false // AVX512F: AVX-512 foundation instructions = false // AVX512DQ: double & quadword instructions = false // RDSEED instruction = true // ADX instructions = true // SMAP: supervisor mode access prevention = true // AVX512IFMA: fused multiply add = false // PCOMMIT instruction = false // CLFLUSHOPT instruction = true // CLWB instruction = true // Intel processor trace = true // AVX512PF: prefetch instructions = false // AVX512ER: exponent & reciprocal instrs = false // AVX512CD: conflict detection instrs = false // SHA instructions = true // AVX512BW: byte & word instructions = false // AVX512VL: vector length = false // PREFETCHWT1 = false // AVX512VBMI: vector byte manipulation = false // UMIP: user-mode instruction prevention = true // PKU protection keys for user-mode = true // OSPKE CR4.PKE and RDPKRU/WRPKRU = true // WAITPKG instructions = true // AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false // CET_SS: CET shadow stack = true // GFNI: Galois Field New Instructions = true // VAES instructions = true // VPCLMULQDQ instruction = true // AVX512_VNNI: neural network instructions = false // AVX512_BITALG: bit count/shiffle = false // TME: Total Memory Encryption = true // AVX512: VPOPCNTDQ instruction = false // 5-level paging = false // BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) // RDPID: read processor D supported = true // KL: key locker = true // CLDEMOTE supports cache line demote = false // MOVDIRI instruction = true // MOVDIR64B instruction = true // ENQCMD instruction = false // SGX_LC: SGX launch config supported = false // PKS: supervisor protection keys = true // AVX512_4VNNIW: neural network instrs = false // AVX512_4FMAPS: multiply acc single prec = false // fast short REP MOV = true // UINTR: user interrupts = false // AVX512_VP2INTERSECT: intersect mask regs = false // SRBDS mitigation MSR available = false // VERW MD_CLEAR microcode support = true // SERIALIZE instruction = true // hybrid part = true // TSXLDTRK: TSX suspend load addr tracking = false // PCONFIG instruction = true // LBR: architectural last branch records = true // CET_IBT: CET indirect branch tracking = true // AMX-BF16: tile bfloat16 support = false // AVX512_FP16: fp16 support = false // AMX-TILE: tile architecture support = false // AMX-INT8: tile 8-bit integer support = false // IBRS/IBPB: indirect branch restrictions = true // STIBP: 1 thr indirect branch predictor = true // L1D_FLUSH: IA32_FLUSH_CMD MSR = true // IA32_ARCH_CAPABILITIES MSR = true // IA32_CORE_CAPABILITIES MSR = true // SSBD: speculative store bypass disable = true // AVX-VNNI: AVX VNNI neural network instrs = true // AVX512_BF16: bfloat16 instructions = false // zero-length MOVSB = false // fast short STOSB = true // fast short CMPSB, SCASB = false // HRESET: history reset support = true // Direct Cache Access Parameters (9): // PLATFORM_DCA_CAP MSR bits = 0 // Architecture Performance Monitoring Features (0xa): // version ID = 0x5 (5) // number of counters per logical processor = 0x6 (6) // bit width of counter = 0x30 (48) // length of EBX bit vector = 0x7 (7) // core cycle event not available = false // instruction retired event not available = false // reference cycles event not available = false // last-level cache ref event not available = false // last-level cache miss event not avail = false // branch inst retired event not available = false // branch mispred retired event not avail = false // fixed counter 0 supported = true // fixed counter 1 supported = true // fixed counter 2 supported = true // fixed counter 3 supported = false // fixed counter 4 supported = false // fixed counter 5 supported = false // fixed counter 6 supported = false // fixed counter 7 supported = false // fixed counter 8 supported = false // fixed counter 9 supported = false // fixed counter 10 supported = false // fixed counter 11 supported = false // fixed counter 12 supported = false // fixed counter 13 supported = false // fixed counter 14 supported = false // fixed counter 15 supported = false // fixed counter 16 supported = false // fixed counter 17 supported = false // fixed counter 18 supported = false // fixed counter 19 supported = false // fixed counter 20 supported = false // fixed counter 21 supported = false // fixed counter 22 supported = false // fixed counter 23 supported = false // fixed counter 24 supported = false // fixed counter 25 supported = false // fixed counter 26 supported = false // fixed counter 27 supported = false // fixed counter 28 supported = false // fixed counter 29 supported = false // fixed counter 30 supported = false // fixed counter 31 supported = false // number of fixed counters = 0x3 (3) // bit width of fixed counters = 0x30 (48) // anythread deprecation = true // x2APIC features / processor topology (0xb): // extended APIC ID = 0 // --- level 0 --- // level number = 0x0 (0) // level type = thread (1) // bit width of level = 0x1 (1) // number of logical processors at level = 0x2 (2) // --- level 1 --- // level number = 0x1 (1) // level type = core (2) // bit width of level = 0x7 (7) // number of logical processors at level = 0x14 (20) // XSAVE features (0xd/0): // XCR0 lower 32 bits valid bit field mask = 0x00000207 // XCR0 upper 32 bits valid bit field mask = 0x00000000 // XCR0 supported: x87 state = true // XCR0 supported: SSE state = true // XCR0 supported: AVX state = true // XCR0 supported: MPX BNDREGS = false // XCR0 supported: MPX BNDCSR = false // XCR0 supported: AVX-512 opmask = false // XCR0 supported: AVX-512 ZMM_Hi256 = false // XCR0 supported: AVX-512 Hi16_ZMM = false // IA32_XSS supported: PT state = false // XCR0 supported: PKRU state = true // XCR0 supported: CET_U state = false // XCR0 supported: CET_S state = false // IA32_XSS supported: HDC state = false // IA32_XSS supported: UINTR state = false // LBR supported = false // IA32_XSS supported: HWP state = false // XTILECFG supported = false // XTILEDATA supported = false // bytes required by fields in XCR0 = 0x00000a88 (2696) // bytes required by XSAVE/XRSTOR area = 0x00000a88 (2696) // XSAVE features (0xd/1): // XSAVEOPT instruction = true // XSAVEC instruction = true // XGETBV instruction = true // XSAVES/XRSTORS instructions = true // XFD: extended feature disable supported = false // SAVE area size in bytes = 0x00000670 (1648) // IA32_XSS lower 32 bits valid bit field mask = 0x00019900 // IA32_XSS upper 32 bits valid bit field mask = 0x00000000 // AVX/YMM features (0xd/2): // AVX/YMM save state byte size = 0x00000100 (256) // AVX/YMM save state byte offset = 0x00000240 (576) // supported in IA32_XSS or XCR0 = XCR0 (user state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // PT features (0xd/8): // PT save state byte size = 0x00000080 (128) // PT save state byte offset = 0x00000000 (0) // supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // PKRU features (0xd/9): // PKRU save state byte size = 0x00000008 (8) // PKRU save state byte offset = 0x00000a80 (2688) // supported in IA32_XSS or XCR0 = XCR0 (user state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // CET_U state features (0xd/0xb): // CET_U state save state byte size = 0x00000010 (16) // CET_U state save state byte offset = 0x00000000 (0) // supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // CET_S state features (0xd/0xc): // CET_S state save state byte size = 0x00000018 (24) // CET_S state save state byte offset = 0x00000000 (0) // supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // LBR features (0xd/0xf): // LBR save state byte size = 0x00000328 (808) // LBR save state byte offset = 0x00000000 (0) // supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // HWP state features (0xd/0x10): // HWP state save state byte size = 0x00000008 (8) // HWP state save state byte offset = 0x00000000 (0) // supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) // 64-byte alignment in compacted XSAVE = false // XFD faulting supported = false // Quality of Service Monitoring Resource Type (0xf/0): // Maximum range of RMID = 0 // supports L3 cache QoS monitoring = false // Resource Director Technology Allocation (0x10/0): // L3 cache allocation technology supported = false // L2 cache allocation technology supported = false // memory bandwidth allocation supported = false // 0x00000011 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 // Software Guard Extensions (SGX) capability (0x12/0): // SGX1 supported = false // SGX2 supported = false // SGX ENCLV E*VIRTCHILD, ESETCONTEXT = false // SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC = false // MISCSELECT.EXINFO supported: #PF & #GP = false // MISCSELECT.CPINFO supported: #CP = false // MaxEnclaveSize_Not64 (log2) = 0x0 (0) // MaxEnclaveSize_64 (log2) = 0x0 (0) // 0x00000013 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 // Intel Processor Trace (0x14): // IA32_RTIT_CR3_MATCH is accessible = true // configurable PSB & cycle-accurate = true // IP & TraceStop filtering; PT preserve = true // MTC timing packet; suppress COFI-based = true // PTWRITE support = true // power event trace support = false // ToPA output scheme support = true // ToPA can hold many output entries = true // single-range output scheme support = true // output to trace transport = false // IP payloads have LIP values & CS = false // configurable address ranges = 0x2 (2) // supported MTC periods bitmask = 0x249 (585) // supported cycle threshold bitmask = 0x3f (63) // supported config PSB freq bitmask = 0x3f (63) // Time Stamp Counter/Core Crystal Clock Information (0x15): // TSC/clock ratio = 188/2 // nominal core crystal clock = 38400000 Hz // Processor Frequency Information (0x16): // Core Base Frequency (MHz) = 0xe10 (3600) // Core Maximum Frequency (MHz) = 0x1388 (5000) // Bus (Reference) Frequency (MHz) = 0x64 (100) // System-On-Chip Vendor Attribute (0x17/0): // vendor id = 0x0 (0) // vendor scheme = assigned by intel // project id = 0x00000000 (0) // stepping id = 0x00000000 (0) // Deterministic Address Translation Parameters (0x18/0): // 4KB page size entries supported = false // 2MB page size entries supported = false // 4MB page size entries supported = false // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x0 (0) // number of sets = 0x00000000 (0) // translation cache type = invalid (0) // translation cache level = 0x1 (1) // fully associative = false // maximum number of addressible IDs = 0x0 (0) // Deterministic Address Translation Parameters (0x18/1): // 4KB page size entries supported = true // 2MB page size entries supported = false // 4MB page size entries supported = false // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x8 (8) // number of sets = 0x00000020 (32) // translation cache type = instruction TLB // translation cache level = 0x2 (2) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/2): // 4KB page size entries supported = false // 2MB page size entries supported = true // 4MB page size entries supported = true // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x8 (8) // number of sets = 0x00000004 (4) // translation cache type = instruction TLB // translation cache level = 0x2 (2) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/3): // 4KB page size entries supported = true // 2MB page size entries supported = true // 4MB page size entries supported = true // 1GB page size entries supported = true // partitioning = soft between logical processors // ways of associativity = 0x10 (16) // number of sets = 0x00000001 (1) // translation cache type = store-only TLB // translation cache level = 0x2 (2) // fully associative = true // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/4): // 4KB page size entries supported = true // 2MB page size entries supported = false // 4MB page size entries supported = false // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x4 (4) // number of sets = 0x00000010 (16) // translation cache type = load-only TLB // translation cache level = 0x2 (2) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/5): // 4KB page size entries supported = false // 2MB page size entries supported = true // 4MB page size entries supported = true // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x4 (4) // number of sets = 0x00000008 (8) // translation cache type = load-only TLB // translation cache level = 0x2 (2) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/6): // 4KB page size entries supported = false // 2MB page size entries supported = false // 4MB page size entries supported = false // 1GB page size entries supported = true // partitioning = soft between logical processors // ways of associativity = 0x8 (8) // number of sets = 0x00000001 (1) // translation cache type = load-only TLB // translation cache level = 0x2 (2) // fully associative = true // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/7): // 4KB page size entries supported = true // 2MB page size entries supported = true // 4MB page size entries supported = true // 1GB page size entries supported = false // partitioning = soft between logical processors // ways of associativity = 0x8 (8) // number of sets = 0x00000080 (128) // translation cache type = unified TLB // translation cache level = 0x3 (3) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Deterministic Address Translation Parameters (0x18/8): // 4KB page size entries supported = true // 2MB page size entries supported = false // 4MB page size entries supported = false // 1GB page size entries supported = true // partitioning = soft between logical processors // ways of associativity = 0x8 (8) // number of sets = 0x00000080 (128) // translation cache type = unified TLB // translation cache level = 0x3 (3) // fully associative = false // maximum number of addressible IDs = 0x1 (1) // Key Locker information (0x19): // CPL0-only restriction supported = true // no-encrypt restriction supported = true // no-decrypt restriction supported = true // AESKLE: AES instructions = false // AES wide instructions = true // MSRs & IWKEY backups = true // LOADIWKEY NoBackup parameter = true // IWKEY randomization supported = true // Hybrid Information (0x1a/0): // native model ID of core = 0x1 (1) // core type = Intel Core // PCONFIG information (0x1b/n): // sub-leaf type = target identifier (1) // identifier of target 1 = 0x00000001 (1) // identifier of target 2 = 0x00000000 (0) // identifier of target 3 = 0x00000000 (0) // Architectural LBR Capabilities (0x1c/0): // IA32_LBR_DEPTH.DEPTH 8 supported = true // IA32_LBR_DEPTH.DEPTH 16 supported = true // IA32_LBR_DEPTH.DEPTH 24 supported = false // IA32_LBR_DEPTH.DEPTH 32 supported = true // IA32_LBR_DEPTH.DEPTH 40 supported = false // IA32_LBR_DEPTH.DEPTH 48 supported = false // IA32_LBR_DEPTH.DEPTH 56 supported = false // IA32_LBR_DEPTH.DEPTH 64 supported = false // deep C-state reset supported = true // LBR IP values contain = EIP (0) // CPL filtering supported = true // branch filtering supported = true // call-stack mode supported = true // mispredict bit supported = true // timed LBRs supported = true // branch type field supported = true // Tile Information (0x1d/0): // max_palette = 0 // TMUL Information (0x1e/0): // tmul_maxk = 0x0 (0) // tmul_maxn = 0x0 (0) // V2 extended topology (0x1f): // x2APIC ID of logical processor = 0x0 (0) // --- level 0 --- // level number = 0x0 (0) // level type = thread (1) // bit width of level = 0x1 (1) // number of logical processors at level = 0x2 (2) // --- level 1 --- // level number = 0x1 (1) // level type = core (2) // bit width of level = 0x7 (7) // number of logical processors at level = 0x14 (20) // --- level 2 --- // level number = 0x2 (2) // level type = invalid (0) // bit width of level = 0x0 (0) // number of logical processors at level = 0x0 (0) // Processor History Reset information (0x20): // HRESET supported: EHFI history = true // extended feature flags (0x80000001/edx): // SYSCALL and SYSRET instructions = true // execution disable = true // 1-GB large page support = true // RDTSCP = true // 64-bit extensions technology available = true // Intel feature flags (0x80000001/ecx): // LAHF/SAHF supported in 64-bit mode = true // LZCNT advanced bit manipulation = true // 3DNow! PREFETCH/PREFETCHW instructions = true // brand = "12th Gen Intel(R) Core(TM) i7-12700K" // L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): // instruction # entries = 0x0 (0) // instruction associativity = 0x0 (0) // data # entries = 0x0 (0) // data associativity = 0x0 (0) // L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): // instruction # entries = 0x0 (0) // instruction associativity = 0x0 (0) // data # entries = 0x0 (0) // data associativity = 0x0 (0) // L1 data cache information (0x80000005/ecx): // line size (bytes) = 0x0 (0) // lines per tag = 0x0 (0) // associativity = 0x0 (0) // size (KB) = 0x0 (0) // L1 instruction cache information (0x80000005/edx): // line size (bytes) = 0x0 (0) // lines per tag = 0x0 (0) // associativity = 0x0 (0) // size (KB) = 0x0 (0) // L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): // instruction # entries = 0x0 (0) // instruction associativity = L2 off (0) // data # entries = 0x0 (0) // data associativity = L2 off (0) // L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): // instruction # entries = 0x0 (0) // instruction associativity = L2 off (0) // data # entries = 0x0 (0) // data associativity = L2 off (0) // L2 unified cache information (0x80000006/ecx): // line size (bytes) = 0x40 (64) // lines per tag = 0x0 (0) // associativity = 0x7 (7) // size (KB) = 0x500 (1280) // L3 cache information (0x80000006/edx): // line size (bytes) = 0x0 (0) // lines per tag = 0x0 (0) // associativity = L2 off (0) // size (in 512KB units) = 0x0 (0) // RAS Capability (0x80000007/ebx): // MCA overflow recovery support = false // SUCCOR support = false // HWA: hardware assert support = false // scalable MCA support = false // Advanced Power Management Features (0x80000007/ecx): // CmpUnitPwrSampleTimeRatio = 0x0 (0) // Advanced Power Management Features (0x80000007/edx): // TS: temperature sensing diode = false // FID: frequency ID control = false // VID: voltage ID control = false // TTP: thermal trip = false // TM: thermal monitor = false // STC: software thermal control = false // 100 MHz multiplier control = false // hardware P-State control = false // TscInvariant = true // CPB: core performance boost = false // read-only effective frequency interface = false // processor feedback interface = false // APM power reporting = false // connected standby = false // RAPL: running average power limit = false // Physical Address and Linear Address Size (0x80000008/eax): // maximum physical address bits = 0x2e (46) // maximum linear (virtual) address bits = 0x30 (48) // maximum guest physical address bits = 0x0 (0) // Extended Feature Extensions ID (0x80000008/ebx): // CLZERO instruction = false // instructions retired count support = false // always save/restore error pointers = false // RDPRU instruction = false // memory bandwidth enforcement = false // WBNOINVD instruction = false // IBPB: indirect branch prediction barrier = false // IBRS: indirect branch restr speculation = false // STIBP: 1 thr indirect branch predictor = false // STIBP always on preferred mode = false // ppin processor id number supported = false // SSBD: speculative store bypass disable = false // virtualized SSBD = false // SSBD fixed in hardware = false // Size Identifiers (0x80000008/ecx): // number of CPU cores = 0x1 (1) // ApicIdCoreIdSize = 0x0 (0) // performance time-stamp counter size = 0x0 (0) // Feature Extended Size (0x80000008/edx): // RDPRU instruction max input support = 0x0 (0) // (multi-processing synth) = multi-core (c=20), hyper-threaded (t=2) // (multi-processing method) = Intel leaf 0x1f // (APIC widths synth): CORE_width=7 SMT_width=1 // (APIC synth): PKG_ID=0 CORE_ID=0 SMT_ID=0 // (uarch synth) = Intel Golden Cove, 10nm // (synth) = Intel Atom (Alder Lake-S) [Golden Cove], 10nm static CPUID_VALUE_MAP: phf::Map = phf::phf_map! { 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000020, ebx: 0x756e6547, ecx: 0x6c65746e, edx: 0x49656e69 }, 0x00000001_00000000u64 => CpuIdResult { eax: 0x00090672, ebx: 0x00800800, ecx: 0x7ffafbff, edx: 0xbfebfbff }, 0x00000002_00000000u64 => CpuIdResult { eax: 0x00feff01, ebx: 0x000000f0, ecx: 0x00000000, edx: 0x00000000 }, 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000004_00000000u64 => CpuIdResult { eax: 0xfc004121, ebx: 0x02c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x00000004_00000001u64 => CpuIdResult { eax: 0xfc004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x00000004_00000002u64 => CpuIdResult { eax: 0xfc01c143, ebx: 0x0240003f, ecx: 0x000007ff, edx: 0x00000000 }, 0x00000004_00000003u64 => CpuIdResult { eax: 0xfc1fc163, ebx: 0x0240003f, ecx: 0x00009fff, edx: 0x00000004 }, 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x10102020 }, 0x00000006_00000000u64 => CpuIdResult { eax: 0x00dfcff7, ebx: 0x00000002, ecx: 0x00000401, edx: 0x00000003 }, 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x239c27eb, ecx: 0x98c027bc, edx: 0xfc1cc410 }, 0x00000007_00000001u64 => CpuIdResult { eax: 0x00400810, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000007_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000001 }, 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000a_00000000u64 => CpuIdResult { eax: 0x07300605, ebx: 0x00000000, ecx: 0x00000007, edx: 0x00008603 }, 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000201, edx: 0x00000000 }, 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000000u64 => CpuIdResult { eax: 0x00000207, ebx: 0x00000a88, ecx: 0x00000a88, edx: 0x00000000 }, 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000670, ecx: 0x00019900, edx: 0x00000000 }, 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000008u64 => CpuIdResult { eax: 0x00000080, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000a80, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_0000000bu64 => CpuIdResult { eax: 0x00000010, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000d_0000000cu64 => CpuIdResult { eax: 0x00000018, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000d_0000000fu64 => CpuIdResult { eax: 0x00000328, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000d_00000010u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000014_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x0000005f, ecx: 0x00000007, edx: 0x00000000 }, 0x00000014_00000001u64 => CpuIdResult { eax: 0x02490002, ebx: 0x003f003f, ecx: 0x00000000, edx: 0x00000000 }, 0x00000015_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x000000bc, ecx: 0x0249f000, edx: 0x00000000 }, 0x00000016_00000000u64 => CpuIdResult { eax: 0x00000e10, ebx: 0x00001388, ecx: 0x00000064, edx: 0x00000000 }, 0x00000017_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000018_00000000u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000018_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080001, ecx: 0x00000020, edx: 0x00004022 }, 0x00000018_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080006, ecx: 0x00000004, edx: 0x00004022 }, 0x00000018_00000003u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0010000f, ecx: 0x00000001, edx: 0x00004125 }, 0x00000018_00000004u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00040001, ecx: 0x00000010, edx: 0x00004024 }, 0x00000018_00000005u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00040006, ecx: 0x00000008, edx: 0x00004024 }, 0x00000018_00000006u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080008, ecx: 0x00000001, edx: 0x00004124 }, 0x00000018_00000007u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080007, ecx: 0x00000080, edx: 0x00004043 }, 0x00000018_00000008u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080009, ecx: 0x00000080, edx: 0x00004043 }, 0x00000019_00000000u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000003, edx: 0x00000000 }, 0x0000001a_00000000u64 => CpuIdResult { eax: 0x40000001, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000001b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, 0x0000001c_00000000u64 => CpuIdResult { eax: 0x4000000b, ebx: 0x00000007, ecx: 0x00000007, edx: 0x00000000 }, 0x0000001d_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000001e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000001f_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, 0x0000001f_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000201, edx: 0x00000000 }, 0x0000001f_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000002, edx: 0x00000000 }, 0x00000020_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000001_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000121, edx: 0x2c100800 }, 0x80000002_00000000u64 => CpuIdResult { eax: 0x68743231, ebx: 0x6e654720, ecx: 0x746e4920, edx: 0x52286c65 }, 0x80000003_00000000u64 => CpuIdResult { eax: 0x6f432029, ebx: 0x54286572, ecx: 0x6920294d, edx: 0x32312d37 }, 0x80000004_00000000u64 => CpuIdResult { eax: 0x4b303037, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000005_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000006_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x05007040, edx: 0x00000000 }, 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000100 }, 0x80000008_00000000u64 => CpuIdResult { eax: 0x0000302e, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, }; fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { let key = (eax as u64) << u32::BITS | ecx as u64; CPUID_VALUE_MAP[&key] } /// Check that vendor is AuthenticAMD. #[test] fn vendor_check() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let v = cpuid.get_vendor_info().expect("Need to find vendor info"); assert_eq!(v.as_str(), "GenuineIntel"); } /// Check feature info gives correct values for CPU #[test] fn version_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let f = cpuid.get_feature_info().expect("Need to find feature info"); assert_eq!(f.base_family_id(), 6); assert_eq!(f.base_model_id(), 7); assert_eq!(f.stepping_id(), 2); assert_eq!(f.extended_family_id(), 0); assert_eq!(f.extended_model_id(), 9); assert_eq!(f.family_id(), 6); assert_eq!(f.model_id(), 151); assert_eq!(f.max_logical_processor_ids(), 128); assert_eq!(f.initial_local_apic_id(), 0); assert_eq!(f.cflush_cache_line_size(), 0x8); assert_eq!(f.brand_index(), 0x0); assert!(f.has_fpu()); assert!(f.has_vme()); assert!(f.has_de()); assert!(f.has_pse()); assert!(f.has_tsc()); assert!(f.has_msr()); assert!(f.has_pae()); assert!(f.has_mce()); assert!(f.has_cmpxchg8b()); assert!(f.has_apic()); assert!(f.has_sysenter_sysexit()); assert!(f.has_mtrr()); assert!(f.has_pge()); assert!(f.has_mca()); assert!(f.has_cmov()); assert!(f.has_pat()); assert!(f.has_pse36()); assert!(!f.has_psn()); assert!(f.has_clflush()); assert!(f.has_ds()); assert!(f.has_acpi()); assert!(f.has_mmx()); assert!(f.has_fxsave_fxstor()); assert!(f.has_sse()); assert!(f.has_sse2()); assert!(f.has_ss()); assert!(f.has_htt()); assert!(f.has_tm()); assert!(f.has_pbe()); assert!(f.has_sse3()); assert!(f.has_pclmulqdq()); assert!(f.has_ds_area()); assert!(f.has_monitor_mwait()); assert!(f.has_cpl()); assert!(f.has_vmx()); assert!(f.has_smx()); assert!(f.has_eist()); assert!(f.has_tm2()); assert!(f.has_ssse3()); assert!(!f.has_cnxtid()); // has_SDBG assert!(f.has_fma()); assert!(f.has_cmpxchg16b()); // xTPR assert!(f.has_pdcm()); assert!(f.has_pcid()); assert!(!f.has_dca()); assert!(f.has_sse41()); assert!(f.has_sse42()); assert!(f.has_x2apic()); assert!(f.has_movbe()); assert!(f.has_popcnt()); assert!(f.has_tsc_deadline()); assert!(f.has_aesni()); assert!(f.has_xsave()); assert!(f.has_oxsave()); assert!(f.has_avx()); assert!(f.has_f16c()); assert!(f.has_rdrand()); assert!(!f.has_hypervisor()); } #[test] fn cache_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let ci = cpuid.get_cache_info().expect("Leaf is supported"); for (idx, cache) in ci.enumerate() { match idx { 0 => assert_eq!(cache.num, 0xf0), 1 => assert_eq!(cache.num, 0xff), 2 => assert_eq!(cache.num, 0xfe), 3 => assert_eq!(cache.num, 0x03), 4 => assert_eq!(cache.num, 0xf0), 5 => assert_eq!(cache.num, 0x76), 6 => assert_eq!(cache.num, 0xc3), _ => unreachable!(), } } } #[test] fn processor_serial() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let psn = cpuid.get_processor_serial().expect("Leaf is supported"); assert_eq!(psn.serial_lower(), 0x0); assert_eq!(psn.serial_middle(), 0x0); } #[test] fn monitor_mwait() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); assert_eq!(mw.largest_monitor_line(), 64); assert_eq!(mw.smallest_monitor_line(), 64); assert!(mw.interrupts_as_break_event()); assert!(mw.extensions_supported()); assert_eq!(mw.supported_c0_states(), 0x0); assert_eq!(mw.supported_c1_states(), 0x2); assert_eq!(mw.supported_c2_states(), 0x0); assert_eq!(mw.supported_c3_states(), 0x2); assert_eq!(mw.supported_c4_states(), 0x0); assert_eq!(mw.supported_c5_states(), 0x1); assert_eq!(mw.supported_c6_states(), 0x0); assert_eq!(mw.supported_c7_states(), 0x1); } #[test] fn thermal_power() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); assert!(mw.has_dts()); assert!(mw.has_turbo_boost()); assert!(mw.has_arat()); assert!(mw.has_pln()); assert!(mw.has_ecmd()); assert!(mw.has_ptm()); assert!(mw.has_hwp()); assert!(mw.has_hwp_notification()); assert!(mw.has_hwp_activity_window()); assert!(mw.has_hwp_energy_performance_preference()); assert!(mw.has_hwp_package_level_request()); assert!(!mw.has_hdc()); assert!(mw.has_turbo_boost3()); assert!(mw.has_hwp_capabilities()); assert!(mw.has_hwp_peci_override()); assert!(mw.has_flexible_hwp()); assert!(mw.has_hwp_fast_access_mode()); assert!(mw.has_hw_coord_feedback()); assert!(mw.has_ignore_idle_processor_hwp_request()); // some missing assert_eq!(mw.dts_irq_threshold(), 0x2); // some missing assert!(!mw.has_energy_bias_pref()); } #[test] fn extended_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_feature_info() .expect("Leaf is supported"); assert!(e.has_fsgsbase()); assert!(e.has_tsc_adjust_msr()); assert!(!e.has_sgx()); assert!(e.has_bmi1()); assert!(!e.has_hle()); assert!(e.has_avx2()); assert!(e.has_fdp()); assert!(e.has_smep()); assert!(e.has_bmi2()); assert!(e.has_rep_movsb_stosb()); assert!(e.has_invpcid()); assert!(!e.has_rtm()); assert!(!e.has_rdtm()); assert!(e.has_fpu_cs_ds_deprecated()); assert!(!e.has_mpx()); assert!(!e.has_rdta()); assert!(!e.has_avx512f()); assert!(!e.has_avx512dq()); assert!(e.has_rdseed()); assert!(e.has_adx()); assert!(e.has_smap()); assert!(!e.has_avx512_ifma()); assert!(e.has_clflushopt()); assert!(e.has_clwb()); assert!(e.has_processor_trace()); assert!(!e.has_avx512pf()); assert!(!e.has_avx512er()); assert!(!e.has_avx512cd()); assert!(e.has_sha()); assert!(!e.has_avx512bw()); assert!(!e.has_avx512vl()); assert!(!e.has_prefetchwt1()); // ... assert!(e.has_umip()); assert!(e.has_pku()); assert!(e.has_ospke()); assert!(!e.has_avx512vnni()); assert!(e.has_rdpid()); assert!(e.has_waitpkg()); assert!(!e.has_sgx_lc()); assert_eq!(e.mawau_value(), 0x0); } #[test] fn direct_cache_access() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let dca = cpuid.get_direct_cache_access_info().expect("Leaf exists"); assert_eq!(dca.get_dca_cap_value(), 0x0); } #[test] fn perfmon_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let pm = cpuid .get_performance_monitoring_info() .expect("Leaf exists"); assert_eq!(pm.version_id(), 0x5); assert_eq!(pm.number_of_counters(), 0x6); assert_eq!(pm.counter_bit_width(), 0x30); assert_eq!(pm.ebx_length(), 0x7); assert!(!pm.is_core_cyc_ev_unavailable()); assert!(!pm.is_inst_ret_ev_unavailable()); assert!(!pm.is_ref_cycle_ev_unavailable()); assert!(!pm.is_cache_ref_ev_unavailable()); assert!(!pm.is_ll_cache_miss_ev_unavailable()); assert!(!pm.is_branch_inst_ret_ev_unavailable()); assert!(!pm.is_branch_midpred_ev_unavailable()); assert_eq!(pm.fixed_function_counters(), 0x3); assert_eq!(pm.fixed_function_counters_bit_width(), 0x30); assert!(pm.has_any_thread_deprecation()); } #[test] fn extended_topology_info() { use crate::TopologyType; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mut e = cpuid .get_extended_topology_info() .expect("Leaf is supported"); let t = e.next().expect("Have level 0"); assert_eq!(t.x2apic_id(), 0); assert_eq!(t.level_number(), 0); assert_eq!(t.level_type(), TopologyType::SMT); assert_eq!(t.shift_right_for_next_apic_id(), 0x1); assert_eq!(t.processors(), 2); let t = e.next().expect("Have level 1"); assert_eq!(t.level_number(), 1); assert_eq!(t.level_type(), TopologyType::Core); assert_eq!(t.shift_right_for_next_apic_id(), 0x7); assert_eq!(t.processors(), 20); assert_eq!(t.x2apic_id(), 0); } #[test] fn extended_topology_info_v2() { use crate::TopologyType; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mut e = cpuid .get_extended_topology_info_v2() .expect("Leaf is supported"); let t = e.next().expect("Have level 0"); assert_eq!(t.x2apic_id(), 0); assert_eq!(t.level_number(), 0); assert_eq!(t.level_type(), TopologyType::SMT); assert_eq!(t.shift_right_for_next_apic_id(), 0x1); assert_eq!(t.processors(), 2); let t = e.next().expect("Have level 1"); assert_eq!(t.level_number(), 1); assert_eq!(t.level_type(), TopologyType::Core); assert_eq!(t.shift_right_for_next_apic_id(), 0x7); assert_eq!(t.processors(), 20); assert_eq!(t.x2apic_id(), 0); } #[test] fn extended_state_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_extended_state_info().expect("Leaf is supported"); assert!(e.xcr0_supports_legacy_x87()); assert!(e.xcr0_supports_sse_128()); assert!(e.xcr0_supports_avx_256()); assert!(!e.xcr0_supports_mpx_bndregs()); assert!(!e.xcr0_supports_mpx_bndcsr()); assert!(!e.xcr0_supports_avx512_opmask()); assert!(!e.xcr0_supports_avx512_zmm_hi256()); assert!(!e.xcr0_supports_avx512_zmm_hi16()); // cpuid binary says this isn't supported, I think it's a bug there and it's // supposed to read from ecx1 like we do: assert!(e.ia32_xss_supports_pt()); assert!(e.xcr0_supports_pkru()); // ... assert!(!e.ia32_xss_supports_hdc()); assert_eq!(e.xsave_area_size_enabled_features(), 2696); assert_eq!(e.xsave_area_size_supported_features(), 2696); assert!(e.has_xsaveopt()); assert!(e.has_xsavec()); assert!(e.has_xgetbv()); assert!(e.has_xsaves_xrstors()); // ... assert_eq!(e.xsave_size(), 1648); // ... let mut e = e.iter(); let ee = e.next().expect("Has level 2"); assert_eq!(ee.size(), 256); assert_eq!(ee.offset(), 576); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 3"); assert_eq!(ee.size(), 128); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 4"); assert_eq!(ee.size(), 8); assert_eq!(ee.offset(), 2688); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 5"); assert_eq!(ee.size(), 16); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 6"); assert_eq!(ee.size(), 24); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 7"); assert_eq!(ee.size(), 808); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 8"); assert_eq!(ee.size(), 8); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); } #[test] fn rdt_monitoring_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); assert_eq!(e.rmid_range(), 0); assert!(!e.has_l3_monitoring()); } #[test] fn rdt_allocation_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); assert!(!e.has_l3_cat()); assert!(!e.has_l2_cat()); assert!(!e.has_memory_bandwidth_allocation()); assert!(e.l2_cat().is_none()); assert!(e.l3_cat().is_none()); } #[test] fn sgx_test() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_sgx_info().is_none()); } #[test] fn processor_trace() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let pt = cpuid.get_processor_trace_info().expect("Leaf is available"); assert!(pt.has_rtit_cr3_match()); assert!(pt.has_configurable_psb_and_cycle_accurate_mode()); assert!(pt.has_ip_tracestop_filtering()); assert!(pt.has_mtc_timing_packet_coefi_suppression()); assert!(pt.has_ptwrite()); assert!(!pt.has_power_event_trace()); assert!(pt.has_topa()); assert!(pt.has_topa_maximum_entries()); assert!(pt.has_single_range_output_scheme()); assert!(!pt.has_trace_transport_subsystem()); assert!(!pt.has_lip_with_cs_base()); assert_eq!(pt.configurable_address_ranges(), 2); assert_eq!(pt.supported_mtc_period_encodings(), 585); assert_eq!(pt.supported_cycle_threshold_value_encodings(), 63); assert_eq!(pt.supported_psb_frequency_encodings(), 63); } #[test] fn tsc() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_tsc_info().expect("Leaf is available"); assert_eq!(e.denominator(), 2); assert_eq!(e.numerator(), 188); assert_eq!(e.nominal_frequency(), 38400000); assert_eq!(e.tsc_frequency(), Some(3609600000)); } #[test] fn processor_frequency() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_frequency_info() .expect("Leaf is supported"); assert_eq!(e.processor_base_frequency(), 3600); assert_eq!(e.processor_max_frequency(), 5000); assert_eq!(e.bus_frequency(), 100); } #[test] fn extended_processor_and_feature_identifiers() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_processor_and_feature_identifiers() .expect("Leaf is supported"); assert_eq!(e.pkg_type(), 0x0); // reserved on Intel assert_eq!(e.brand_id(), 0x0); // reserved on Intel assert!(e.has_lahf_sahf()); assert!(!e.has_cmp_legacy()); assert!(!e.has_svm()); assert!(!e.has_ext_apic_space()); assert!(!e.has_alt_mov_cr8()); assert!(e.has_lzcnt()); assert!(!e.has_sse4a()); assert!(!e.has_misaligned_sse_mode()); assert!(e.has_prefetchw()); assert!(!e.has_osvw()); assert!(!e.has_ibs()); assert!(!e.has_xop()); assert!(!e.has_skinit()); assert!(!e.has_wdt()); assert!(!e.has_lwp()); assert!(!e.has_fma4()); assert!(!e.has_tbm()); assert!(!e.has_topology_extensions()); assert!(!e.has_perf_cntr_extensions()); assert!(!e.has_nb_perf_cntr_extensions()); assert!(!e.has_data_access_bkpt_extension()); assert!(!e.has_perf_tsc()); assert!(!e.has_perf_cntr_llc_extensions()); assert!(!e.has_monitorx_mwaitx()); assert!(!e.has_addr_mask_extension()); assert!(e.has_syscall_sysret()); assert!(e.has_execute_disable()); assert!(!e.has_mmx_extensions()); assert!(!e.has_fast_fxsave_fxstor()); assert!(e.has_1gib_pages()); assert!(e.has_rdtscp()); assert!(e.has_64bit_mode()); assert!(!e.has_amd_3dnow_extensions()); assert!(!e.has_3dnow()); } #[test] fn brand_string() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_brand_string() .expect("Leaf is supported"); assert_eq!(e.as_str(), "12th Gen Intel(R) Core(TM) i7-12700K"); } #[test] fn l1_tlb_cache() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_l1_cache_and_tlb_info().is_none()); } #[test] fn l2_l3_tlb_cache() { use crate::Associativity; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_l2_l3_cache_and_tlb_info() .expect("Leaf is supported"); // Unsupported on Intel assert_eq!(e.itlb_2m_4m_associativity(), Associativity::Disabled); assert_eq!(e.itlb_2m_4m_size(), 0); assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::Disabled); assert_eq!(e.dtlb_2m_4m_size(), 0); assert_eq!(e.itlb_4k_size(), 0); assert_eq!(e.itlb_4k_associativity(), Associativity::Disabled); assert_eq!(e.dtlb_4k_size(), 0); assert_eq!(e.dtlb_4k_associativity(), Associativity::Disabled); // Supported on Intel assert_eq!(e.l2cache_line_size(), 64); assert_eq!(e.l2cache_lines_per_tag(), 0); assert_eq!(e.l2cache_associativity(), Associativity::Unknown); assert_eq!(e.l2cache_size(), 1280); // Unsupported on Intel assert_eq!(e.l3cache_line_size(), 0); assert_eq!(e.l3cache_lines_per_tag(), 0); assert_eq!(e.l3cache_associativity(), Associativity::Disabled); assert_eq!(e.l3cache_size(), 0); } #[test] fn apm() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_advanced_power_mgmt_info() .expect("Leaf is supported"); assert!(!e.has_mca_overflow_recovery()); assert!(!e.has_succor()); assert!(!e.has_hwa()); // ... assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); assert!(!e.has_ts()); assert!(!e.has_freq_id_ctrl()); assert!(!e.has_volt_id_ctrl()); assert!(!e.has_thermtrip()); assert!(!e.has_tm()); assert!(!e.has_100mhz_steps()); assert!(!e.has_hw_pstate()); assert!(e.has_invariant_tsc()); // The only Intel supported feature here assert!(!e.has_cpb()); assert!(!e.has_ro_effective_freq_iface()); assert!(!e.has_feedback_iface()); assert!(!e.has_power_reporting_iface()); } #[test] fn processor_capcity_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_capacity_feature_info() .expect("Leaf is supported"); assert_eq!(e.physical_address_bits(), 46); assert_eq!(e.linear_address_bits(), 48); assert_eq!(e.guest_physical_address_bits(), 0); assert!(!e.has_cl_zero()); assert!(!e.has_inst_ret_cntr_msr()); assert!(!e.has_restore_fp_error_ptrs()); assert!(!e.has_invlpgb()); assert!(!e.has_rdpru()); assert!(!e.has_mcommit()); assert!(!e.has_wbnoinvd()); assert!(!e.has_int_wbinvd()); assert!(!e.has_unsupported_efer_lmsle()); assert!(!e.has_invlpgb_nested()); assert_eq!(e.invlpgb_max_pages(), 0x0); assert_eq!(e.maximum_logical_processors(), 1); // Not sure why this is set, it's reserved :( assert_eq!(e.num_phys_threads(), 1); // Not sure why this is set, it's reserved :( assert_eq!(e.apic_id_size(), 0); assert_eq!(e.perf_tsc_size(), 40); // Not sure why this is set, it's reserved :( assert_eq!(e.max_rdpru_id(), 0); } #[test] fn get_deterministic_address_translation_info() { use crate::DatType; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mut e = cpuid .get_deterministic_address_translation_info() .expect("Leaf is supported"); // This is a null entry, so all of this should be 0/false/invalid/null let t = e.next().expect("Have level 1"); assert!(t.has_4k_entries()); assert!(!t.has_2mb_entries()); assert!(!t.has_4mb_entries()); assert!(!t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 8); assert_eq!(t.sets(), 32); assert_eq!(t.cache_type(), DatType::InstructionTLB); assert_eq!(t.cache_level(), 1); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 2"); assert!(!t.has_4k_entries()); assert!(t.has_2mb_entries()); assert!(t.has_4mb_entries()); assert!(!t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 8); assert_eq!(t.sets(), 4); assert_eq!(t.cache_type(), DatType::InstructionTLB); assert_eq!(t.cache_level(), 1); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 3"); assert!(t.has_4k_entries()); assert!(t.has_2mb_entries()); assert!(t.has_4mb_entries()); assert!(t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 16); assert_eq!(t.sets(), 1); assert_eq!(t.cache_type(), DatType::StoreOnly); assert_eq!(t.cache_level(), 1); assert!(t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 4"); assert!(t.has_4k_entries()); assert!(!t.has_2mb_entries()); assert!(!t.has_4mb_entries()); assert!(!t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 4); assert_eq!(t.sets(), 16); assert_eq!(t.cache_type(), DatType::LoadOnly); assert_eq!(t.cache_level(), 1); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 5"); assert!(!t.has_4k_entries()); assert!(t.has_2mb_entries()); assert!(t.has_4mb_entries()); assert!(!t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 4); assert_eq!(t.sets(), 8); assert_eq!(t.cache_type(), DatType::LoadOnly); assert_eq!(t.cache_level(), 1); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 6"); assert!(!t.has_4k_entries()); assert!(!t.has_2mb_entries()); assert!(!t.has_4mb_entries()); assert!(t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 8); assert_eq!(t.sets(), 1); assert_eq!(t.cache_type(), DatType::LoadOnly); assert_eq!(t.cache_level(), 1); assert!(t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 7"); assert!(t.has_4k_entries()); assert!(t.has_2mb_entries()); assert!(t.has_4mb_entries()); assert!(!t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 8); assert_eq!(t.sets(), 128); assert_eq!(t.cache_type(), DatType::UnifiedTLB); assert_eq!(t.cache_level(), 2); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); let t = e.next().expect("Have level 8"); assert!(t.has_4k_entries()); assert!(!t.has_2mb_entries()); assert!(!t.has_4mb_entries()); assert!(t.has_1gb_entries()); assert_eq!(t.partitioning(), 0); assert_eq!(t.ways(), 8); assert_eq!(t.sets(), 128); assert_eq!(t.cache_type(), DatType::UnifiedTLB); assert_eq!(t.cache_level(), 2); assert!(!t.is_fully_associative()); assert_eq!(t.max_addressable_ids(), 2); } #[test] fn get_soc_vendor() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_soc_vendor_info().expect("Leaf is supported"); assert_eq!(e.get_project_id(), 0); assert_eq!(e.get_soc_vendor_id(), 0); assert_eq!(e.get_stepping_id(), 0); if let Some(attr_iter) = e.get_vendor_attributes() { for attr in attr_iter { println!("{:?}", attr); } } println!("{:?}", e.get_vendor_brand()); } raw-cpuid-11.6.0/src/tests/mod.rs000064400000000000000000000003761046102023000146700ustar 00000000000000#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod i5_3337u; mod i7_12700k; mod ryzen_matisse; mod xeon_gold_6252; use crate::*; #[test] fn cpuid_impls_debug() { fn debug_required(_t: T) {} debug_required(CpuId::new()); } raw-cpuid-11.6.0/src/tests/ryzen_matisse.rs000064400000000000000000001640021046102023000170020ustar 00000000000000use crate::{Associativity, CpuId, CpuIdResult, TopologyType}; use phf::phf_map; /// Raw dump of ryzen mantisse cpuid values. /// /// Key format is (eax << 32 | ecx) e.g., two 32 bit values packed in one 64 bit value /// /// /// # Representation of Hex Values /// /// ```log /// vendor_id = "AuthenticAMD" /// version information (1/eax): /// processor type = primary processor (0) /// family = 0xf (15) /// model = 0x1 (1) /// stepping id = 0x0 (0) /// extended family = 0x8 (8) /// extended model = 0x7 (7) /// (family synth) = 0x17 (23) /// (model synth) = 0x71 (113) /// (simple synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm /// miscellaneous (1/ebx): /// process local APIC physical ID = 0xa (10) /// cpu count = 0xc (12) /// CLFLUSH line size = 0x8 (8) /// brand index = 0x0 (0) /// brand id = 0x00 (0): unknown /// feature information (1/edx): /// x87 FPU on chip = true /// VME: virtual-8086 mode enhancement = true /// DE: debugging extensions = true /// PSE: page size extensions = true /// TSC: time stamp counter = true /// RDMSR and WRMSR support = true /// PAE: physical address extensions = true /// MCE: machine check exception = true /// CMPXCHG8B inst. = true /// APIC on chip = true /// SYSENTER and SYSEXIT = true /// MTRR: memory type range registers = true /// PTE global bit = true /// MCA: machine check architecture = true /// CMOV: conditional move/compare instr = true /// PAT: page attribute table = true /// PSE-36: page size extension = true /// PSN: processor serial number = false /// CLFLUSH instruction = true /// DS: debug store = false /// ACPI: thermal monitor and clock ctrl = false /// MMX Technology = true /// FXSAVE/FXRSTOR = true /// SSE extensions = true /// SSE2 extensions = true /// SS: self snoop = false /// hyper-threading / multi-core supported = true /// TM: therm. monitor = false /// IA64 = false /// PBE: pending break event = false /// feature information (1/ecx): /// PNI/SSE3: Prescott New Instructions = true /// PCLMULDQ instruction = true /// DTES64: 64-bit debug store = false /// MONITOR/MWAIT = true /// CPL-qualified debug store = false /// VMX: virtual machine extensions = false /// SMX: safer mode extensions = false /// Enhanced Intel SpeedStep Technology = false /// TM2: thermal monitor 2 = false /// SSSE3 extensions = true /// context ID: adaptive or shared L1 data = false /// SDBG: IA32_DEBUG_INTERFACE = false /// FMA instruction = true /// CMPXCHG16B instruction = true /// xTPR disable = false /// PDCM: perfmon and debug = false /// PCID: process context identifiers = false /// DCA: direct cache access = false /// SSE4.1 extensions = true /// SSE4.2 extensions = true /// x2APIC: extended xAPIC support = false /// MOVBE instruction = true /// POPCNT instruction = true /// time stamp counter deadline = false /// AES instruction = true /// XSAVE/XSTOR states = true /// OS-enabled XSAVE/XSTOR = true /// AVX: advanced vector extensions = true /// F16C half-precision convert instruction = true /// RDRAND instruction = true /// hypervisor guest status = false /// cache and TLB information (2): /// processor serial number = 0087-0F10-0000-0000-0000-0000 /// MONITOR/MWAIT (5): /// smallest monitor-line size (bytes) = 0x40 (64) /// largest monitor-line size (bytes) = 0x40 (64) /// enum of Monitor-MWAIT exts supported = true /// supports intrs as break-event for MWAIT = true /// number of C0 sub C-states using MWAIT = 0x1 (1) /// number of C1 sub C-states using MWAIT = 0x1 (1) /// number of C2 sub C-states using MWAIT = 0x0 (0) /// number of C3 sub C-states using MWAIT = 0x0 (0) /// number of C4 sub C-states using MWAIT = 0x0 (0) /// number of C5 sub C-states using MWAIT = 0x0 (0) /// number of C6 sub C-states using MWAIT = 0x0 (0) /// number of C7 sub C-states using MWAIT = 0x0 (0) /// Thermal and Power Management Features (6): /// digital thermometer = false /// Intel Turbo Boost Technology = false /// ARAT always running APIC timer = true /// PLN power limit notification = false /// ECMD extended clock modulation duty = false /// PTM package thermal management = false /// HWP base registers = false /// HWP notification = false /// HWP activity window = false /// HWP energy performance preference = false /// HWP package level request = false /// HDC base registers = false /// Intel Turbo Boost Max Technology 3.0 = false /// HWP capabilities = false /// HWP PECI override = false /// flexible HWP = false /// IA32_HWP_REQUEST MSR fast access mode = false /// HW_FEEDBACK = false /// ignoring idle logical processor HWP req = false /// digital thermometer thresholds = 0x0 (0) /// hardware coordination feedback = true /// ACNT2 available = false /// performance-energy bias capability = false /// performance capability reporting = false /// energy efficiency capability reporting = false /// size of feedback struct (4KB pages) = 0x0 (0) /// index of CPU's row in feedback struct = 0x0 (0) /// extended feature flags (7): /// FSGSBASE instructions = true /// IA32_TSC_ADJUST MSR supported = false /// SGX: Software Guard Extensions supported = false /// BMI1 instructions = true /// HLE hardware lock elision = false /// AVX2: advanced vector extensions 2 = true /// FDP_EXCPTN_ONLY = false /// SMEP supervisor mode exec protection = true /// BMI2 instructions = true /// enhanced REP MOVSB/STOSB = false /// INVPCID instruction = false /// RTM: restricted transactional memory = false /// RDT-CMT/PQoS cache monitoring = true /// deprecated FPU CS/DS = false /// MPX: intel memory protection extensions = false /// RDT-CAT/PQE cache allocation = true /// AVX512F: AVX-512 foundation instructions = false /// AVX512DQ: double & quadword instructions = false /// RDSEED instruction = true /// ADX instructions = true /// SMAP: supervisor mode access prevention = true /// AVX512IFMA: fused multiply add = false /// PCOMMIT instruction = false /// CLFLUSHOPT instruction = true /// CLWB instruction = true /// Intel processor trace = false /// AVX512PF: prefetch instructions = false /// AVX512ER: exponent & reciprocal instrs = false /// AVX512CD: conflict detection instrs = false /// SHA instructions = true /// AVX512BW: byte & word instructions = false /// AVX512VL: vector length = false /// PREFETCHWT1 = false /// AVX512VBMI: vector byte manipulation = false /// UMIP: user-mode instruction prevention = true /// PKU protection keys for user-mode = false /// OSPKE CR4.PKE and RDPKRU/WRPKRU = false /// WAITPKG instructions = false /// AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false /// CET_SS: CET shadow stack = false /// GFNI: Galois Field New Instructions = false /// VAES instructions = false /// VPCLMULQDQ instruction = false /// AVX512_VNNI: neural network instructions = false /// AVX512_BITALG: bit count/shiffle = false /// TME: Total Memory Encryption = false /// AVX512: VPOPCNTDQ instruction = false /// 5-level paging = false /// BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) /// RDPID: read processor D supported = true /// CLDEMOTE supports cache line demote = false /// MOVDIRI instruction = false /// MOVDIR64B instruction = false /// ENQCMD instruction = false /// SGX_LC: SGX launch config supported = false /// AVX512_4VNNIW: neural network instrs = false /// AVX512_4FMAPS: multiply acc single prec = false /// fast short REP MOV = false /// AVX512_VP2INTERSECT: intersect mask regs = false /// VERW md-clear microcode support = false /// hybrid part = false /// PCONFIG instruction = false /// CET_IBT: CET indirect branch tracking = false /// IBRS/IBPB: indirect branch restrictions = false /// STIBP: 1 thr indirect branch predictor = false /// L1D_FLUSH: IA32_FLUSH_CMD MSR = false /// IA32_ARCH_CAPABILITIES MSR = false /// IA32_CORE_CAPABILITIES MSR = false /// SSBD: speculative store bypass disable = false /// Direct Cache Access Parameters (9): /// PLATFORM_DCA_CAP MSR bits = 0 /// Architecture Performance Monitoring Features (0xa/eax): /// version ID = 0x0 (0) /// number of counters per logical processor = 0x0 (0) /// bit width of counter = 0x0 (0) /// length of EBX bit vector = 0x0 (0) /// Architecture Performance Monitoring Features (0xa/ebx): /// core cycle event not available = false /// instruction retired event not available = false /// reference cycles event not available = false /// last-level cache ref event not available = false /// last-level cache miss event not avail = false /// branch inst retired event not available = false /// branch mispred retired event not avail = false /// Architecture Performance Monitoring Features (0xa/edx): /// number of fixed counters = 0x0 (0) /// bit width of fixed counters = 0x0 (0) /// anythread deprecation = false /// x2APIC features / processor topology (0xb): /// extended APIC ID = 10 /// --- level 0 --- /// level number = 0x0 (0) /// level type = thread (1) /// bit width of level = 0x1 (1) /// number of logical processors at level = 0x2 (2) /// --- level 1 --- /// level number = 0x1 (1) /// level type = core (2) /// bit width of level = 0x7 (7) /// number of logical processors at level = 0xc (12) /// XSAVE features (0xd/0): /// XCR0 lower 32 bits valid bit field mask = 0x00000207 /// XCR0 upper 32 bits valid bit field mask = 0x00000000 /// XCR0 supported: x87 state = true /// XCR0 supported: SSE state = true /// XCR0 supported: AVX state = true /// XCR0 supported: MPX BNDREGS = false /// XCR0 supported: MPX BNDCSR = false /// XCR0 supported: AVX-512 opmask = false /// XCR0 supported: AVX-512 ZMM_Hi256 = false /// XCR0 supported: AVX-512 Hi16_ZMM = false /// IA32_XSS supported: PT state = false /// XCR0 supported: PKRU state = true /// XCR0 supported: CET_U state = false /// XCR0 supported: CET_S state = false /// IA32_XSS supported: HDC state = false /// bytes required by fields in XCR0 = 0x00000340 (832) /// bytes required by XSAVE/XRSTOR area = 0x00000380 (896) /// XSAVE features (0xd/1): /// XSAVEOPT instruction = true /// XSAVEC instruction = true /// XGETBV instruction = true /// XSAVES/XRSTORS instructions = true /// SAVE area size in bytes = 0x00000340 (832) /// IA32_XSS lower 32 bits valid bit field mask = 0x00000000 /// IA32_XSS upper 32 bits valid bit field mask = 0x00000000 /// AVX/YMM features (0xd/2): /// AVX/YMM save state byte size = 0x00000100 (256) /// AVX/YMM save state byte offset = 0x00000240 (576) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// PKRU features (0xd/9): /// PKRU save state byte size = 0x00000040 (64) /// PKRU save state byte offset = 0x00000340 (832) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// Quality of Service Monitoring Resource Type (0xf/0): /// Maximum range of RMID = 255 /// supports L3 cache QoS monitoring = true /// L3 Cache Quality of Service Monitoring (0xf/1): /// Conversion factor from IA32_QM_CTR to bytes = 64 /// Maximum range of RMID = 255 /// supports L3 occupancy monitoring = true /// supports L3 total bandwidth monitoring = true /// supports L3 local bandwidth monitoring = true /// Resource Director Technology Allocation (0x10/0): /// L3 cache allocation technology supported = true /// L2 cache allocation technology supported = false /// memory bandwidth allocation supported = false /// L3 Cache Allocation Technology (0x10/1): /// length of capacity bit mask = 0x10 (16) /// Bit-granular map of isolation/contention = 0x00000000 /// infrequent updates of COS = false /// code and data prioritization supported = true /// highest COS number supported = 0xf (15) /// extended processor signature (0x80000001/eax): /// family/generation = 0xf (15) /// model = 0x1 (1) /// stepping id = 0x0 (0) /// extended family = 0x8 (8) /// extended model = 0x7 (7) /// (family synth) = 0x17 (23) /// (model synth) = 0x71 (113) /// (simple synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm /// extended feature flags (0x80000001/edx): /// x87 FPU on chip = true /// virtual-8086 mode enhancement = true /// debugging extensions = true /// page size extensions = true /// time stamp counter = true /// RDMSR and WRMSR support = true /// physical address extensions = true /// machine check exception = true /// CMPXCHG8B inst. = true /// APIC on chip = true /// SYSCALL and SYSRET instructions = true /// memory type range registers = true /// global paging extension = true /// machine check architecture = true /// conditional move/compare instruction = true /// page attribute table = true /// page size extension = true /// multiprocessing capable = false /// no-execute page protection = true /// AMD multimedia instruction extensions = true /// MMX Technology = true /// FXSAVE/FXRSTOR = true /// SSE extensions = true /// 1-GB large page support = true /// RDTSCP = true /// long mode (AA-64) = true /// 3DNow! instruction extensions = false /// 3DNow! instructions = false /// extended brand id (0x80000001/ebx): /// raw = 0x20000000 (536870912) /// BrandId = 0x0 (0) /// PkgType = AM4 (2) /// AMD feature flags (0x80000001/ecx): /// LAHF/SAHF supported in 64-bit mode = true /// CMP Legacy = true /// SVM: secure virtual machine = true /// extended APIC space = true /// AltMovCr8 = true /// LZCNT advanced bit manipulation = true /// SSE4A support = true /// misaligned SSE mode = true /// 3DNow! PREFETCH/PREFETCHW instructions = true /// OS visible workaround = true /// instruction based sampling = true /// XOP support = false /// SKINIT/STGI support = true /// watchdog timer support = true /// lightweight profiling support = false /// 4-operand FMA instruction = false /// TCE: translation cache extension = true /// NodeId MSR C001100C = false /// TBM support = false /// topology extensions = true /// core performance counter extensions = true /// NB/DF performance counter extensions = true /// data breakpoint extension = true /// performance time-stamp counter support = false /// LLC performance counter extensions = true /// MWAITX/MONITORX supported = true /// Address mask extension support = true /// brand = "AMD Ryzen 5 3600X 6-Core Processor " /// L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): /// instruction # entries = 0x40 (64) /// instruction associativity = 0xff (255) /// data # entries = 0x40 (64) /// data associativity = 0xff (255) /// L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): /// instruction # entries = 0x40 (64) /// instruction associativity = 0xff (255) /// data # entries = 0x40 (64) /// data associativity = 0xff (255) /// L1 data cache information (0x80000005/ecx): /// line size (bytes) = 0x40 (64) /// lines per tag = 0x1 (1) /// associativity = 0x8 (8) /// size (KB) = 0x20 (32) /// L1 instruction cache information (0x80000005/edx): /// line size (bytes) = 0x40 (64) /// lines per tag = 0x1 (1) /// associativity = 0x8 (8) /// size (KB) = 0x20 (32) /// L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): /// instruction # entries = 0x400 (1024) /// instruction associativity = 8-way (6) /// data # entries = 0x800 (2048) /// data associativity = 4-way (4) /// L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): /// instruction # entries = 0x400 (1024) /// instruction associativity = 8-way (6) /// data # entries = 0x800 (2048) /// data associativity = 8-way (6) /// L2 unified cache information (0x80000006/ecx): /// line size (bytes) = 0x40 (64) /// lines per tag = 0x1 (1) /// associativity = 8-way (6) /// size (KB) = 0x200 (512) /// L3 cache information (0x80000006/edx): /// line size (bytes) = 0x40 (64) /// lines per tag = 0x1 (1) /// associativity = 0x9 (9) /// size (in 512KB units) = 0x40 (64) /// RAS Capability (0x80000007/ebx): /// MCA overflow recovery support = true /// SUCCOR support = true /// HWA: hardware assert support = false /// scalable MCA support = true /// Advanced Power Management Features (0x80000007/ecx): /// CmpUnitPwrSampleTimeRatio = 0x0 (0) /// Advanced Power Management Features (0x80000007/edx): /// TS: temperature sensing diode = true /// FID: frequency ID control = false /// VID: voltage ID control = false /// TTP: thermal trip = true /// TM: thermal monitor = true /// STC: software thermal control = false /// 100 MHz multiplier control = false /// hardware P-State control = true /// TscInvariant = true /// CPB: core performance boost = true /// read-only effective frequency interface = true /// processor feedback interface = false /// APM power reporting = false /// connected standby = true /// RAPL: running average power limit = true /// Physical Address and Linear Address Size (0x80000008/eax): /// maximum physical address bits = 0x30 (48) /// maximum linear (virtual) address bits = 0x30 (48) /// maximum guest physical address bits = 0x0 (0) /// Extended Feature Extensions ID (0x80000008/ebx): /// CLZERO instruction = true /// instructions retired count support = true /// always save/restore error pointers = true /// RDPRU instruction = true /// memory bandwidth enforcement = true /// WBNOINVD instruction = true /// IBPB: indirect branch prediction barrier = true /// IBRS: indirect branch restr speculation = false /// STIBP: 1 thr indirect branch predictor = true /// STIBP always on preferred mode = true /// ppin processor id number supported = false /// SSBD: speculative store bypass disable = true /// virtualized SSBD = false /// SSBD fixed in hardware = false /// Size Identifiers (0x80000008/ecx): /// number of threads = 0xc (12) /// ApicIdCoreIdSize = 0x7 (7) /// performance time-stamp counter size = 0x0 (0) /// Feature Extended Size (0x80000008/edx): /// RDPRU instruction max input support = 0x1 (1) /// SVM Secure Virtual Machine (0x8000000a/eax): /// SvmRev: SVM revision = 0x1 (1) /// SVM Secure Virtual Machine (0x8000000a/edx): /// nested paging = true /// LBR virtualization = true /// SVM lock = true /// NRIP save = true /// MSR based TSC rate control = true /// VMCB clean bits support = true /// flush by ASID = true /// decode assists = true /// SSSE3/SSE5 opcode set disable = false /// pause intercept filter = true /// pause filter threshold = true /// AVIC: AMD virtual interrupt controller = true /// virtualized VMLOAD/VMSAVE = true /// virtualized global interrupt flag (GIF) = true /// GMET: guest mode execute trap = true /// guest Spec_ctl support = true /// NASID: number of address space identifiers = 0x8000 (32768): /// L1 TLB information: 1G pages (0x80000019/eax): /// instruction # entries = 0x40 (64) /// instruction associativity = full (15) /// data # entries = 0x40 (64) /// data associativity = full (15) /// L2 TLB information: 1G pages (0x80000019/ebx): /// instruction # entries = 0x0 (0) /// instruction associativity = L2 off (0) /// data # entries = 0x0 (0) /// data associativity = L2 off (0) /// SVM Secure Virtual Machine (0x8000001a/eax): /// 128-bit SSE executed full-width = false /// MOVU* better than MOVL*/MOVH* = true /// 256-bit SSE executed full-width = true /// Instruction Based Sampling Identifiers (0x8000001b/eax): /// IBS feature flags valid = true /// IBS fetch sampling = true /// IBS execution sampling = true /// read write of op counter = true /// op counting mode = true /// branch target address reporting = true /// IbsOpCurCnt and IbsOpMaxCnt extend 7 = true /// invalid RIP indication support = true /// fused branch micro-op indication support = true /// IBS fetch control extended MSR support = true /// IBS op data 4 MSR support = false /// Lightweight Profiling Capabilities: Availability (0x8000001c/eax): /// lightweight profiling = false /// LWPVAL instruction = false /// instruction retired event = false /// branch retired event = false /// DC miss event = false /// core clocks not halted event = false /// core reference clocks not halted event = false /// interrupt on threshold overflow = false /// Lightweight Profiling Capabilities: Supported (0x8000001c/edx): /// lightweight profiling = false /// LWPVAL instruction = false /// instruction retired event = false /// branch retired event = false /// DC miss event = false /// core clocks not halted event = false /// core reference clocks not halted event = false /// interrupt on threshold overflow = false /// Lightweight Profiling Capabilities (0x8000001c/ebx): /// LWPCB byte size = 0x0 (0) /// event record byte size = 0x0 (0) /// maximum EventId = 0x0 (0) /// EventInterval1 field offset = 0x0 (0) /// Lightweight Profiling Capabilities (0x8000001c/ecx): /// latency counter bit size = 0x0 (0) /// data cache miss address valid = false /// amount cache latency is rounded = 0x0 (0) /// LWP implementation version = 0x0 (0) /// event ring buffer size in records = 0x0 (0) /// branch prediction filtering = false /// IP filtering = false /// cache level filtering = false /// cache latency filteing = false /// Cache Properties (0x8000001d): /// --- cache 0 --- /// type = data (1) /// level = 0x1 (1) /// self-initializing = true /// fully associative = false /// extra cores sharing this cache = 0x1 (1) /// line size in bytes = 0x40 (64) /// physical line partitions = 0x1 (1) /// number of ways = 0x8 (8) /// number of sets = 64 /// write-back invalidate = false /// cache inclusive of lower levels = false /// (synth size) = 32768 (32 KB) /// --- cache 1 --- /// type = instruction (2) /// level = 0x1 (1) /// self-initializing = true /// fully associative = false /// extra cores sharing this cache = 0x1 (1) /// line size in bytes = 0x40 (64) /// physical line partitions = 0x1 (1) /// number of ways = 0x8 (8) /// number of sets = 64 /// write-back invalidate = false /// cache inclusive of lower levels = false /// (synth size) = 32768 (32 KB) /// --- cache 2 --- /// type = unified (3) /// level = 0x2 (2) /// self-initializing = true /// fully associative = false /// extra cores sharing this cache = 0x1 (1) /// line size in bytes = 0x40 (64) /// physical line partitions = 0x1 (1) /// number of ways = 0x8 (8) /// number of sets = 1024 /// write-back invalidate = false /// cache inclusive of lower levels = true /// (synth size) = 524288 (512 KB) /// --- cache 3 --- /// type = unified (3) /// level = 0x3 (3) /// self-initializing = true /// fully associative = false /// extra cores sharing this cache = 0x5 (5) /// line size in bytes = 0x40 (64) /// physical line partitions = 0x1 (1) /// number of ways = 0x10 (16) /// number of sets = 16384 /// write-back invalidate = true /// cache inclusive of lower levels = false /// (synth size) = 16777216 (16 MB) /// extended APIC ID = 10 /// Core Identifiers (0x8000001e/ebx): /// core ID = 0x5 (5) /// threads per core = 0x2 (2) /// Node Identifiers (0x8000001e/ecx): /// node ID = 0x0 (0) /// nodes per processor = 0x1 (1) /// AMD Secure Encryption (0x8000001f): /// SME: secure memory encryption support = true /// SEV: secure encrypted virtualize support = true /// VM page flush MSR support = true /// SEV-ES: SEV encrypted state support = true /// encryption bit position in PTE = 0x2f (47) /// physical address space width reduction = 0x5 (5) /// number of SEV-enabled guests supported = 0x1fd (509) /// minimum SEV guest ASID = 0x1 (1) /// PQoS Enforcement for Memory Bandwidth (0x80000020): /// memory bandwidth enforcement support = true /// capacity bitmask length = 0xc (12) /// number of classes of service = 0xf (15) /// (instruction supported synth): /// CMPXCHG8B = true /// conditional move/compare = true /// PREFETCH/PREFETCHW = true /// (multi-processing synth) = multi-core (c=12) /// (multi-processing method) = AMD /// (APIC widths synth): CORE_width=3 SMT_width=1 /// (APIC synth): PKG_ID=0 CORE_ID=5 SMT_ID=0 /// (uarch synth) = AMD Zen 2, 7nm /// (synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm /// ``` static CPUID_VALUE_MAP: phf::Map = phf_map! { 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000010, ebx: 0x68747541, ecx: 0x444d4163, edx: 0x69746e65 }, 0x00000001_00000000u64 => CpuIdResult { eax: 0x00870f10, ebx: 0x000c0800, ecx: 0x7ed8320b, edx: 0x178bfbff }, 0x00000002_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x00000011 }, 0x00000006_00000000u64 => CpuIdResult { eax: 0x00000004, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x219c91a9, ecx: 0x00400004, edx: 0x00000000 }, 0x00000007_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000a_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x0000000c, ecx: 0x00000201, edx: 0x00000000 }, 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000000u64 => CpuIdResult { eax: 0x00000207, ebx: 0x00000340, ecx: 0x00000380, edx: 0x00000000 }, 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000340, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000340, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x000000ff, ecx: 0x00000000, edx: 0x00000002 }, 0x0000000f_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000040, ecx: 0x000000ff, edx: 0x00000007 }, 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000002, ecx: 0x00000000, edx: 0x00000000 }, 0x00000010_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000000, ecx: 0x00000004, edx: 0x0000000f }, 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000020, ebx: 0x68747541, ecx: 0x444d4163, edx: 0x69746e65 }, 0x80000001_00000000u64 => CpuIdResult { eax: 0x00870f10, ebx: 0x20000000, ecx: 0x75c237ff, edx: 0x2fd3fbff }, 0x80000002_00000000u64 => CpuIdResult { eax: 0x20444d41, ebx: 0x657a7952, ecx: 0x2035206e, edx: 0x30303633 }, 0x80000003_00000000u64 => CpuIdResult { eax: 0x2d362058, ebx: 0x65726f43, ecx: 0x6f725020, edx: 0x73736563 }, 0x80000004_00000000u64 => CpuIdResult { eax: 0x2020726f, ebx: 0x20202020, ecx: 0x20202020, edx: 0x00202020 }, 0x80000005_00000000u64 => CpuIdResult { eax: 0xff40ff40, ebx: 0xff40ff40, ecx: 0x20080140, edx: 0x20080140 }, 0x80000006_00000000u64 => CpuIdResult { eax: 0x48006400, ebx: 0x68006400, ecx: 0x02006140, edx: 0x01009140 }, 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0000001b, ecx: 0x00000000, edx: 0x00006799 }, 0x80000008_00000000u64 => CpuIdResult { eax: 0x00003030, ebx: 0x010eb757, ecx: 0x0000700b, edx: 0x00010000 }, 0x80000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000000a_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00008000, ecx: 0x00000000, edx: 0x0013bcff }, 0x8000000b_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000000d_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000014_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000015_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000016_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000017_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000018_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000019_00000000u64 => CpuIdResult { eax: 0xf040f040, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000001a_00000000u64 => CpuIdResult { eax: 0x00000006, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000001b_00000000u64 => CpuIdResult { eax: 0x000003ff, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000001c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x8000001d_00000000u64 => CpuIdResult { eax: 0x00004121, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x8000001d_00000001u64 => CpuIdResult { eax: 0x00004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x8000001d_00000002u64 => CpuIdResult { eax: 0x00004143, ebx: 0x01c0003f, ecx: 0x000003ff, edx: 0x00000002 }, 0x8000001d_00000003u64 => CpuIdResult { eax: 0x00014163, ebx: 0x03c0003f, ecx: 0x00003fff, edx: 0x00000001 }, 0x8000001e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000100, ecx: 0x00000000, edx: 0x00000000 }, 0x8000001f_00000000u64 => CpuIdResult { eax: 0x0001000f, ebx: 0x0000016f, ecx: 0x000001fd, edx: 0x00000001 }, 0x80000020_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000002, ecx: 0x00000000, edx: 0x00000000 }, 0x80000020_00000001u64 => CpuIdResult { eax: 0x0000000b, ebx: 0x00000000, ecx: 0x00000000, edx: 0x0000000f }, 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, }; fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { let key = (eax as u64) << u32::BITS | ecx as u64; CPUID_VALUE_MAP[&key] } /// Check that vendor is AuthenticAMD. #[test] fn vendor_check() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let v = cpuid.get_vendor_info().expect("Need to find vendor info"); assert_eq!(v.as_str(), "AuthenticAMD"); } /// Check feature info gives correct values for CPU #[test] fn version_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let f = cpuid.get_feature_info().expect("Need to find feature info"); assert_eq!(f.base_family_id(), 0xf); assert_eq!(f.base_model_id(), 0x1); assert_eq!(f.stepping_id(), 0x0); assert_eq!(f.extended_family_id(), 0x8); assert_eq!(f.extended_model_id(), 0x7); assert_eq!(f.brand_index(), 0x0); assert_eq!(f.cflush_cache_line_size(), 0x8); assert_eq!(f.max_logical_processor_ids(), 0xc); assert!(f.has_fpu()); assert!(f.has_vme()); assert!(f.has_de()); assert!(f.has_pse()); assert!(f.has_tsc()); assert!(f.has_msr()); assert!(f.has_pae()); assert!(f.has_mce()); assert!(f.has_cmpxchg8b()); assert!(f.has_apic()); assert!(f.has_sysenter_sysexit()); assert!(f.has_mtrr()); assert!(f.has_pge()); assert!(f.has_mca()); assert!(f.has_cmov()); assert!(f.has_pat()); assert!(f.has_pse36()); assert!(!f.has_psn()); assert!(f.has_clflush()); assert!(!f.has_ds()); assert!(!f.has_acpi()); assert!(f.has_mmx()); assert!(f.has_fxsave_fxstor()); assert!(f.has_sse()); assert!(f.has_sse2()); assert!(!f.has_ss()); assert!(f.has_htt()); assert!(!f.has_tm()); assert!(!f.has_pbe()); assert!(f.has_sse3()); assert!(f.has_pclmulqdq()); assert!(!f.has_ds_area()); assert!(f.has_monitor_mwait()); assert!(!f.has_cpl()); assert!(!f.has_vmx()); assert!(!f.has_smx()); assert!(!f.has_eist()); assert!(!f.has_tm2()); assert!(f.has_ssse3()); assert!(!f.has_cnxtid()); // has_SDBG assert!(f.has_fma()); assert!(f.has_cmpxchg16b()); // xTPR assert!(!f.has_pdcm()); assert!(!f.has_pcid()); assert!(!f.has_dca()); assert!(f.has_sse41()); assert!(f.has_sse42()); assert!(!f.has_x2apic()); assert!(f.has_movbe()); assert!(f.has_popcnt()); assert!(!f.has_tsc_deadline()); assert!(f.has_aesni()); assert!(f.has_xsave()); assert!(f.has_oxsave()); assert!(f.has_avx()); assert!(f.has_f16c()); assert!(f.has_rdrand()); assert!(!f.has_hypervisor()); } #[test] fn cache_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_cache_info().is_none(), "Not supported by AMD"); } #[test] fn processor_serial() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!( cpuid.get_processor_serial().is_none(), "Not supported by AMD" ); } #[test] fn monitor_mwait() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); assert_eq!(mw.largest_monitor_line(), 64); assert_eq!(mw.smallest_monitor_line(), 64); assert!(mw.interrupts_as_break_event()); assert!(mw.extensions_supported()); // supported_cX_states functions are not supported according to the manual } #[test] fn thermal_power() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); assert_eq!(mw.dts_irq_threshold(), 0x0); assert!(!mw.has_dts()); assert!(mw.has_arat()); assert!(!mw.has_turbo_boost()); assert!(!mw.has_pln()); assert!(!mw.has_ecmd()); assert!(!mw.has_ptm()); assert!(!mw.has_hwp()); assert!(!mw.has_hwp_notification()); assert!(!mw.has_hwp_activity_window()); assert!(!mw.has_hwp_energy_performance_preference()); assert!(!mw.has_hwp_package_level_request()); assert!(!mw.has_hdc()); assert!(!mw.has_turbo_boost3()); assert!(!mw.has_hwp_capabilities()); assert!(!mw.has_hwp_peci_override()); assert!(!mw.has_flexible_hwp()); assert!(!mw.has_hwp_fast_access_mode()); assert!(!mw.has_ignore_idle_processor_hwp_request()); assert!(mw.has_hw_coord_feedback()); assert!(!mw.has_energy_bias_pref()); } #[test] fn extended_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_feature_info() .expect("Leaf is supported"); assert!(e.has_fsgsbase()); assert!(!e.has_tsc_adjust_msr()); assert!(e.has_bmi1()); assert!(!e.has_hle()); assert!(e.has_avx2()); assert!(!e.has_fdp()); assert!(e.has_smep()); assert!(e.has_bmi2()); assert!(!e.has_rep_movsb_stosb()); assert!(!e.has_invpcid()); assert!(!e.has_rtm()); assert!(e.has_rdtm()); assert!(!e.has_fpu_cs_ds_deprecated()); assert!(!e.has_mpx()); assert!(e.has_rdta()); assert!(e.has_rdseed()); assert!(e.has_adx()); assert!(e.has_smap()); assert!(e.has_clflushopt()); assert!(!e.has_processor_trace()); assert!(e.has_sha()); assert!(!e.has_sgx()); assert!(!e.has_avx512f()); assert!(!e.has_avx512dq()); assert!(!e.has_avx512_ifma()); assert!(!e.has_avx512pf()); assert!(!e.has_avx512er()); assert!(!e.has_avx512cd()); assert!(!e.has_avx512bw()); assert!(!e.has_avx512vl()); assert!(e.has_clwb()); assert!(!e.has_prefetchwt1()); assert!(e.has_umip()); assert!(!e.has_pku()); assert!(!e.has_ospke()); assert!(!e.has_avx512vnni()); assert!(e.has_rdpid()); assert!(!e.has_sgx_lc()); assert_eq!(e.mawau_value(), 0x0); } #[test] fn direct_cache_access() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!( cpuid.get_direct_cache_access_info().is_none(), "Not supported by AMD" ); } #[test] fn perfmon_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!( cpuid.get_performance_monitoring_info().is_none(), "Not supported by AMD" ); } #[test] fn extended_topology_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mut e = cpuid .get_extended_topology_info() .expect("Leaf is supported"); let t = e.next().expect("Have level 0"); assert_eq!(t.processors(), 2); assert_eq!(t.level_number(), 0); assert_eq!(t.level_type(), TopologyType::SMT); assert_eq!(t.x2apic_id(), 0x0); assert_eq!(t.shift_right_for_next_apic_id(), 0x1); let t = e.next().expect("Have level 1"); assert_eq!(t.processors(), 12); assert_eq!(t.level_number(), 1); assert_eq!(t.level_type(), TopologyType::Core); assert_eq!(t.x2apic_id(), 0x0); assert_eq!(t.shift_right_for_next_apic_id(), 0x7); } #[test] fn extended_state_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_extended_state_info().expect("Leaf is supported"); assert!(e.xcr0_supports_legacy_x87()); assert!(e.xcr0_supports_sse_128()); assert!(e.xcr0_supports_avx_256()); assert!(!e.xcr0_supports_mpx_bndregs()); assert!(!e.xcr0_supports_mpx_bndcsr()); assert!(!e.xcr0_supports_avx512_opmask()); assert!(!e.xcr0_supports_avx512_zmm_hi256()); assert!(!e.xcr0_supports_avx512_zmm_hi16()); assert!(e.xcr0_supports_pkru()); assert!(!e.ia32_xss_supports_pt()); assert!(!e.ia32_xss_supports_hdc()); assert_eq!(e.xsave_area_size_enabled_features(), 0x00000340); assert_eq!(e.xsave_area_size_supported_features(), 0x00000380); assert!(e.has_xsaveopt()); assert!(e.has_xsavec()); assert!(e.has_xgetbv()); assert!(e.has_xsaves_xrstors()); assert_eq!(e.xsave_size(), 0x00000340); let mut e = e.iter(); let ee = e.next().expect("Has level 2"); assert_eq!(ee.size(), 256); assert_eq!(ee.offset(), 576); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 9"); assert_eq!(ee.size(), 64); assert_eq!(ee.offset(), 832); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); } #[test] fn rdt_monitoring_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); assert!(e.has_l3_monitoring()); assert_eq!(e.rmid_range(), 255); let l3m = e.l3_monitoring().expect("Leaf is available"); assert_eq!(l3m.conversion_factor(), 64); assert_eq!(l3m.maximum_rmid_range(), 255); assert!(l3m.has_occupancy_monitoring()); assert!(l3m.has_total_bandwidth_monitoring()); assert!(l3m.has_local_bandwidth_monitoring()); } #[test] fn rdt_allocation_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); assert!(e.has_l3_cat()); assert!(!e.has_l2_cat()); assert!(!e.has_memory_bandwidth_allocation()); assert!(e.l2_cat().is_none()); assert!(e.memory_bandwidth_allocation().is_none()); let l3c = e.l3_cat().expect("Leaf is available"); assert_eq!(l3c.capacity_mask_length(), 0x10); assert_eq!(l3c.isolation_bitmap(), 0x0); assert_eq!(l3c.highest_cos(), 15); assert!(l3c.has_code_data_prioritization()); } #[test] fn extended_processor_and_feature_identifiers() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_processor_and_feature_identifiers() .expect("Leaf is supported"); assert_eq!(e.pkg_type(), 0x2); assert_eq!(e.brand_id(), 0x0); assert!(e.has_lahf_sahf()); assert!(e.has_cmp_legacy()); assert!(e.has_svm()); assert!(e.has_ext_apic_space()); assert!(e.has_alt_mov_cr8()); assert!(e.has_lzcnt()); assert!(e.has_sse4a()); assert!(e.has_misaligned_sse_mode()); assert!(e.has_prefetchw()); assert!(e.has_osvw()); assert!(e.has_ibs()); assert!(!e.has_xop()); assert!(e.has_skinit()); assert!(e.has_wdt()); assert!(!e.has_lwp()); assert!(!e.has_fma4()); assert!(!e.has_tbm()); assert!(e.has_topology_extensions()); assert!(e.has_perf_cntr_extensions()); assert!(e.has_nb_perf_cntr_extensions()); assert!(e.has_data_access_bkpt_extension()); assert!(!e.has_perf_tsc()); assert!(e.has_perf_cntr_llc_extensions()); assert!(e.has_monitorx_mwaitx()); assert!(e.has_addr_mask_extension()); assert!(e.has_syscall_sysret()); assert!(e.has_execute_disable()); assert!(e.has_mmx_extensions()); assert!(e.has_fast_fxsave_fxstor()); assert!(e.has_1gib_pages()); assert!(e.has_rdtscp()); assert!(e.has_64bit_mode()); assert!(!e.has_amd_3dnow_extensions()); assert!(!e.has_3dnow()); } #[test] fn brand_string() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_brand_string() .expect("Leaf is supported"); assert_eq!(e.as_str(), "AMD Ryzen 5 3600X 6-Core Processor"); } #[test] fn l1_tlb_cache() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_l1_cache_and_tlb_info() .expect("Leaf is supported"); assert_eq!( e.dtlb_2m_4m_associativity(), Associativity::FullyAssociative ); assert_eq!(e.dtlb_2m_4m_size(), 64); assert_eq!( e.itlb_2m_4m_associativity(), Associativity::FullyAssociative ); assert_eq!(e.itlb_2m_4m_size(), 64); assert_eq!(e.dtlb_4k_associativity(), Associativity::FullyAssociative); assert_eq!(e.dtlb_4k_size(), 64); assert_eq!(e.itlb_4k_associativity(), Associativity::FullyAssociative); assert_eq!(e.itlb_4k_size(), 64); assert_eq!(e.dcache_line_size(), 64); assert_eq!(e.dcache_lines_per_tag(), 1); assert_eq!(e.dcache_associativity(), Associativity::NWay(8)); assert_eq!(e.dcache_size(), 32); assert_eq!(e.icache_line_size(), 64); assert_eq!(e.icache_lines_per_tag(), 1); assert_eq!(e.icache_associativity(), Associativity::NWay(8)); assert_eq!(e.icache_size(), 32); } #[test] fn l2_l3_tlb_cache() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_l2_l3_cache_and_tlb_info() .expect("Leaf is supported"); assert_eq!(e.itlb_2m_4m_associativity(), Associativity::NWay(8)); assert_eq!(e.itlb_2m_4m_size(), 1024); assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::NWay(4)); assert_eq!(e.dtlb_2m_4m_size(), 2048); assert_eq!(e.itlb_4k_size(), 1024); assert_eq!(e.itlb_4k_associativity(), Associativity::NWay(8)); assert_eq!(e.dtlb_4k_size(), 2048); assert_eq!(e.dtlb_4k_associativity(), Associativity::NWay(8)); assert_eq!(e.l2cache_line_size(), 64); assert_eq!(e.l2cache_lines_per_tag(), 1); assert_eq!(e.l2cache_associativity(), Associativity::NWay(8)); assert_eq!(e.l2cache_size(), 0x200); assert_eq!(e.l3cache_line_size(), 64); assert_eq!(e.l3cache_lines_per_tag(), 1); assert_eq!(e.l3cache_associativity(), Associativity::Unknown); assert_eq!(e.l3cache_size(), 64); } #[test] fn apm() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_advanced_power_mgmt_info() .expect("Leaf is supported"); assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); assert!(e.has_mca_overflow_recovery()); assert!(e.has_succor()); assert!(!e.has_hwa()); assert!(e.has_ts()); assert!(!e.has_freq_id_ctrl()); assert!(!e.has_volt_id_ctrl()); assert!(e.has_thermtrip()); assert!(e.has_tm()); assert!(!e.has_100mhz_steps()); assert!(e.has_hw_pstate()); assert!(e.has_invariant_tsc()); assert!(e.has_cpb()); assert!(e.has_ro_effective_freq_iface()); assert!(!e.has_feedback_iface()); assert!(!e.has_power_reporting_iface()); } #[test] fn processor_capcity_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_capacity_feature_info() .expect("Leaf is supported"); assert_eq!(e.physical_address_bits(), 48); assert_eq!(e.linear_address_bits(), 48); assert_eq!(e.guest_physical_address_bits(), 0); // These are hard to test if they are correct. I think the cpuid CLI tool // displays bogus values here (see above) -- or I can't tell how they // correspond to the AMD manual... assert!(e.has_cl_zero()); assert!(e.has_inst_ret_cntr_msr()); assert!(e.has_restore_fp_error_ptrs()); assert!(!e.has_invlpgb()); assert!(e.has_rdpru()); assert!(e.has_mcommit()); assert!(e.has_wbnoinvd()); assert!(e.has_int_wbinvd()); assert!(!e.has_unsupported_efer_lmsle()); assert!(!e.has_invlpgb_nested()); assert_eq!(e.invlpgb_max_pages(), 0x0); assert_eq!(e.maximum_logical_processors(), 128); assert_eq!(e.num_phys_threads(), 12); assert_eq!(e.apic_id_size(), 7); assert_eq!(e.perf_tsc_size(), 40); assert_eq!(e.max_rdpru_id(), 0x1); } #[test] fn secure_encryption() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_memory_encryption_info() .expect("Leaf is supported"); assert!(e.has_sme()); assert!(e.has_sev()); assert!(e.has_page_flush_msr()); assert!(e.has_sev_es()); assert!(!e.has_sev_snp()); assert!(!e.has_vmpl()); assert!(!e.has_hw_enforced_cache_coh()); assert!(!e.has_64bit_mode()); assert!(!e.has_restricted_injection()); assert!(!e.has_alternate_injection()); assert!(!e.has_debug_swap()); assert!(!e.has_prevent_host_ibs()); assert!(e.has_vte()); assert_eq!(e.c_bit_position(), 0x2f); assert_eq!(e.physical_address_reduction(), 0x5); assert_eq!(e.max_encrypted_guests(), 0x1fd); assert_eq!(e.min_sev_no_es_asid(), 0x1); } #[test] fn svm() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_svm_info().expect("Leaf is supported"); assert_eq!(e.revision(), 0x1); assert_eq!(e.supported_asids(), 0x8000); assert!(e.has_nested_paging()); assert!(e.has_lbr_virtualization()); assert!(e.has_svm_lock()); assert!(e.has_nrip()); assert!(e.has_tsc_rate_msr()); assert!(e.has_vmcb_clean_bits()); assert!(e.has_flush_by_asid()); assert!(e.has_decode_assists()); assert!(e.has_pause_filter()); assert!(e.has_pause_filter_threshold()); assert!(e.has_avic()); assert!(e.has_vmsave_virtualization()); assert!(e.has_gmet()); assert!(!e.has_sss_check()); assert!(e.has_spec_ctrl()); assert!(!e.has_host_mce_override()); assert!(!e.has_tlb_ctrl()); } #[test] fn tlb_1gb_page_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_tlb_1gb_page_info().expect("Leaf is supported"); assert!(e.dtlb_l1_1gb_associativity() == Associativity::FullyAssociative); assert!(e.dtlb_l1_1gb_size() == 64); assert!(e.itlb_l1_1gb_associativity() == Associativity::FullyAssociative); assert!(e.itlb_l1_1gb_size() == 64); assert!(e.dtlb_l2_1gb_associativity() == Associativity::Disabled); assert!(e.dtlb_l2_1gb_size() == 0); assert!(e.itlb_l2_1gb_associativity() == Associativity::Disabled); assert!(e.itlb_l2_1gb_size() == 0); } #[test] fn performance_optimization_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_performance_optimization_info() .expect("Leaf is supported"); assert!(!e.has_fp128()); assert!(e.has_movu()); assert!(e.has_fp256()); } #[test] fn instruction_based_sampling_capabilities() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_instruction_based_sampling_capabilities() .expect("Leaf is supported"); assert!(e.has_feature_flags()); assert!(e.has_fetch_sampling()); assert!(e.has_execution_sampling()); assert!(e.has_read_write_operation_counter()); assert!(e.has_operation_counter()); assert!(e.has_branch_target_address_reporting()); assert!(e.has_operation_counter_extended()); assert!(e.has_invalid_rip_indication()); assert!(e.has_fused_branch_micro_op_indication()); assert!(!e.has_l3_miss_filtering()); } #[test] fn processor_topology_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_topology_info() .expect("Leaf is supported"); assert!(e.x2apic_id() == 0); assert!(e.core_id() == 0); assert!(e.threads_per_core() == 2); assert!(e.node_id() == 0); assert!(e.nodes_per_processor() == 1); } #[test] fn remaining_unsupported_leafs() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_sgx_info().is_none()); assert!(cpuid.get_processor_trace_info().is_none()); assert!(cpuid.get_tsc_info().is_none()); assert!(cpuid.get_processor_frequency_info().is_none()); assert!(cpuid.get_deterministic_address_translation_info().is_none()); assert!(cpuid.get_soc_vendor_info().is_none()); assert!(cpuid.get_extended_topology_info_v2().is_none()); assert!(cpuid.get_extended_feature_identification_2().is_none()); assert!(cpuid .get_extended_performance_monitoring_and_debug() .is_none()); assert!(cpuid .get_multi_key_encrypted_memory_capabilities() .is_none()); assert!(cpuid.get_extended_cpu_topology().is_none()); } #[test] fn platform_quality_service() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_pqos_extended_feature_info() .expect("Leaf is supported"); assert!(e.has_l3mbe()); assert!(!e.has_l3smbe()); assert!(!e.has_abmc()); assert!(!e.has_bmec()); assert!(!e.has_l3rr()); assert!(!e.has_sdciae()); let f = e .get_l3_memory_bandwidth_enforcement_info() .expect("SubLeaf is supported"); assert!(f.bandwidth_length() == 0x0000_000b); assert!(f.cos_max() == 0x0000_000f); } raw-cpuid-11.6.0/src/tests/xeon_gold_6252.rs000064400000000000000000001527111046102023000165460ustar 00000000000000use crate::{CpuId, CpuIdResult}; use phf::phf_map; /// Raw dump of a cascade lake cpuid values. /// /// Key format is (eax << 32 | ecx) e.g., two 32 bit values packed in one 64 bit value /// /// /// # Representation of Hex Values /// ///```log /// CPU: /// vendor_id = "GenuineIntel" /// version information (1/eax): /// processor type = primary processor (0) /// family = 0x6 (6) /// model = 0x5 (5) /// stepping id = 0x7 (7) /// extended family = 0x0 (0) /// extended model = 0x5 (5) /// (family synth) = 0x6 (6) /// (model synth) = 0x55 (85) /// (simple synth) = Intel Core (unknown type) (Skylake / Skylake-X / Cascade Lake / Cascade Lake-X) {Skylake}, 14nm /// miscellaneous (1/ebx): /// process local APIC physical ID = 0xda (218) /// cpu count = 0x40 (64) /// CLFLUSH line size = 0x8 (8) /// brand index = 0x0 (0) /// brand id = 0x00 (0): unknown /// feature information (1/edx): /// x87 FPU on chip = true /// VME: virtual-8086 mode enhancement = true /// DE: debugging extensions = true /// PSE: page size extensions = true /// TSC: time stamp counter = true /// RDMSR and WRMSR support = true /// PAE: physical address extensions = true /// MCE: machine check exception = true /// CMPXCHG8B inst. = true /// APIC on chip = true /// SYSENTER and SYSEXIT = true /// MTRR: memory type range registers = true /// PTE global bit = true /// MCA: machine check architecture = true /// CMOV: conditional move/compare instr = true /// PAT: page attribute table = true /// PSE-36: page size extension = true /// PSN: processor serial number = false /// CLFLUSH instruction = true /// DS: debug store = true /// ACPI: thermal monitor and clock ctrl = true /// MMX Technology = true /// FXSAVE/FXRSTOR = true /// SSE extensions = true /// SSE2 extensions = true /// SS: self snoop = true /// hyper-threading / multi-core supported = true /// TM: therm. monitor = true /// IA64 = false /// PBE: pending break event = true /// feature information (1/ecx): /// PNI/SSE3: Prescott New Instructions = true /// PCLMULDQ instruction = true /// DTES64: 64-bit debug store = true /// MONITOR/MWAIT = true /// CPL-qualified debug store = true /// VMX: virtual machine extensions = true /// SMX: safer mode extensions = true /// Enhanced Intel SpeedStep Technology = true /// TM2: thermal monitor 2 = true /// SSSE3 extensions = true /// context ID: adaptive or shared L1 data = false /// SDBG: IA32_DEBUG_INTERFACE = true /// FMA instruction = true /// CMPXCHG16B instruction = true /// xTPR disable = true /// PDCM: perfmon and debug = true /// PCID: process context identifiers = true /// DCA: direct cache access = true /// SSE4.1 extensions = true /// SSE4.2 extensions = true /// x2APIC: extended xAPIC support = true /// MOVBE instruction = true /// POPCNT instruction = true /// time stamp counter deadline = true /// AES instruction = true /// XSAVE/XSTOR states = true /// OS-enabled XSAVE/XSTOR = true /// AVX: advanced vector extensions = true /// F16C half-precision convert instruction = true /// RDRAND instruction = true /// hypervisor guest status = false /// cache and TLB information (2): /// 0x63: data TLB: 2M/4M pages, 4-way, 32 entries /// data TLB: 1G pages, 4-way, 4 entries /// 0x03: data TLB: 4K pages, 4-way, 64 entries /// 0x76: instruction TLB: 2M/4M pages, fully, 8 entries /// 0xff: cache data is in CPUID leaf 4 /// 0xb5: instruction TLB: 4K, 8-way, 64 entries /// 0xf0: 64 byte prefetching /// 0xc3: L2 TLB: 4K/2M pages, 6-way, 1536 entries /// processor serial number = 0005-0657-0000-0000-0000-0000 /// deterministic cache parameters (4): /// --- cache 0 --- /// cache type = data cache (1) /// cache level = 0x1 (1) /// self-initializing cache level = true /// fully associative cache = false /// extra threads sharing this cache = 0x1 (1) /// extra processor cores on this die = 0x1f (31) /// system coherency line size = 0x40 (64) /// physical line partitions = 0x1 (1) /// ways of associativity = 0x8 (8) /// number of sets = 0x40 (64) /// WBINVD/INVD acts on lower caches = false /// inclusive to lower caches = false /// complex cache indexing = false /// number of sets (s) = 64 /// (size synth) = 32768 (32 KB) /// --- cache 1 --- /// cache type = instruction cache (2) /// cache level = 0x1 (1) /// self-initializing cache level = true /// fully associative cache = false /// extra threads sharing this cache = 0x1 (1) /// extra processor cores on this die = 0x1f (31) /// system coherency line size = 0x40 (64) /// physical line partitions = 0x1 (1) /// ways of associativity = 0x8 (8) /// number of sets = 0x40 (64) /// WBINVD/INVD acts on lower caches = false /// inclusive to lower caches = false /// complex cache indexing = false /// number of sets (s) = 64 /// (size synth) = 32768 (32 KB) /// --- cache 2 --- /// cache type = unified cache (3) /// cache level = 0x2 (2) /// self-initializing cache level = true /// fully associative cache = false /// extra threads sharing this cache = 0x1 (1) /// extra processor cores on this die = 0x1f (31) /// system coherency line size = 0x40 (64) /// physical line partitions = 0x1 (1) /// ways of associativity = 0x10 (16) /// number of sets = 0x400 (1024) /// WBINVD/INVD acts on lower caches = false /// inclusive to lower caches = false /// complex cache indexing = false /// number of sets (s) = 1024 /// (size synth) = 1048576 (1024 KB) /// --- cache 3 --- /// cache type = unified cache (3) /// cache level = 0x3 (3) /// self-initializing cache level = true /// fully associative cache = false /// extra threads sharing this cache = 0x3f (63) /// extra processor cores on this die = 0x1f (31) /// system coherency line size = 0x40 (64) /// physical line partitions = 0x1 (1) /// ways of associativity = 0xb (11) /// number of sets = 0xd000 (53248) /// WBINVD/INVD acts on lower caches = true /// inclusive to lower caches = false /// complex cache indexing = true /// number of sets (s) = 53248 /// (size synth) = 37486592 (35.8 MB) /// MONITOR/MWAIT (5): /// smallest monitor-line size (bytes) = 0x40 (64) /// largest monitor-line size (bytes) = 0x40 (64) /// enum of Monitor-MWAIT exts supported = true /// supports intrs as break-event for MWAIT = true /// number of C0 sub C-states using MWAIT = 0x0 (0) /// number of C1 sub C-states using MWAIT = 0x2 (2) /// number of C2 sub C-states using MWAIT = 0x0 (0) /// number of C3 sub C-states using MWAIT = 0x2 (2) /// number of C4 sub C-states using MWAIT = 0x0 (0) /// number of C5 sub C-states using MWAIT = 0x0 (0) /// number of C6 sub C-states using MWAIT = 0x0 (0) /// number of C7 sub C-states using MWAIT = 0x0 (0) /// Thermal and Power Management Features (6): /// digital thermometer = true /// Intel Turbo Boost Technology = true /// ARAT always running APIC timer = true /// PLN power limit notification = true /// ECMD extended clock modulation duty = true /// PTM package thermal management = true /// HWP base registers = false /// HWP notification = false /// HWP activity window = false /// HWP energy performance preference = false /// HWP package level request = false /// HDC base registers = false /// Intel Turbo Boost Max Technology 3.0 = false /// HWP capabilities = false /// HWP PECI override = false /// flexible HWP = false /// IA32_HWP_REQUEST MSR fast access mode = false /// HW_FEEDBACK = false /// ignoring idle logical processor HWP req = false /// digital thermometer thresholds = 0x2 (2) /// hardware coordination feedback = true /// ACNT2 available = false /// performance-energy bias capability = true /// performance capability reporting = false /// energy efficiency capability reporting = false /// size of feedback struct (4KB pages) = 0x0 (0) /// index of CPU's row in feedback struct = 0x0 (0) /// extended feature flags (7): /// FSGSBASE instructions = true /// IA32_TSC_ADJUST MSR supported = true /// SGX: Software Guard Extensions supported = false /// BMI1 instructions = true /// HLE hardware lock elision = false /// AVX2: advanced vector extensions 2 = true /// FDP_EXCPTN_ONLY = true /// SMEP supervisor mode exec protection = true /// BMI2 instructions = true /// enhanced REP MOVSB/STOSB = true /// INVPCID instruction = true /// RTM: restricted transactional memory = false /// RDT-CMT/PQoS cache monitoring = true /// deprecated FPU CS/DS = true /// MPX: intel memory protection extensions = true /// RDT-CAT/PQE cache allocation = true /// AVX512F: AVX-512 foundation instructions = true /// AVX512DQ: double & quadword instructions = true /// RDSEED instruction = true /// ADX instructions = true /// SMAP: supervisor mode access prevention = true /// AVX512IFMA: fused multiply add = false /// PCOMMIT instruction = false /// CLFLUSHOPT instruction = true /// CLWB instruction = true /// Intel processor trace = true /// AVX512PF: prefetch instructions = false /// AVX512ER: exponent & reciprocal instrs = false /// AVX512CD: conflict detection instrs = true /// SHA instructions = false /// AVX512BW: byte & word instructions = true /// AVX512VL: vector length = true /// PREFETCHWT1 = false /// AVX512VBMI: vector byte manipulation = false /// UMIP: user-mode instruction prevention = false /// PKU protection keys for user-mode = true /// OSPKE CR4.PKE and RDPKRU/WRPKRU = true /// WAITPKG instructions = false /// AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false /// CET_SS: CET shadow stack = false /// GFNI: Galois Field New Instructions = false /// VAES instructions = false /// VPCLMULQDQ instruction = false /// AVX512_VNNI: neural network instructions = true /// AVX512_BITALG: bit count/shiffle = false /// TME: Total Memory Encryption = false /// AVX512: VPOPCNTDQ instruction = false /// 5-level paging = false /// BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) /// RDPID: read processor D supported = false /// CLDEMOTE supports cache line demote = false /// MOVDIRI instruction = false /// MOVDIR64B instruction = false /// ENQCMD instruction = false /// SGX_LC: SGX launch config supported = false /// AVX512_4VNNIW: neural network instrs = false /// AVX512_4FMAPS: multiply acc single prec = false /// fast short REP MOV = false /// AVX512_VP2INTERSECT: intersect mask regs = false /// VERW md-clear microcode support = true /// hybrid part = false /// PCONFIG instruction = false /// CET_IBT: CET indirect branch tracking = false /// IBRS/IBPB: indirect branch restrictions = true /// STIBP: 1 thr indirect branch predictor = true /// L1D_FLUSH: IA32_FLUSH_CMD MSR = true /// IA32_ARCH_CAPABILITIES MSR = true /// IA32_CORE_CAPABILITIES MSR = false /// SSBD: speculative store bypass disable = true /// Direct Cache Access Parameters (9): /// PLATFORM_DCA_CAP MSR bits = 0 /// Architecture Performance Monitoring Features (0xa/eax): /// version ID = 0x4 (4) /// number of counters per logical processor = 0x4 (4) /// bit width of counter = 0x30 (48) /// length of EBX bit vector = 0x7 (7) /// Architecture Performance Monitoring Features (0xa/ebx): /// core cycle event not available = false /// instruction retired event not available = false /// reference cycles event not available = false /// last-level cache ref event not available = false /// last-level cache miss event not avail = false /// branch inst retired event not available = false /// branch mispred retired event not avail = false /// Architecture Performance Monitoring Features (0xa/edx): /// number of fixed counters = 0x3 (3) /// bit width of fixed counters = 0x30 (48) /// anythread deprecation = false /// x2APIC features / processor topology (0xb): /// extended APIC ID = 218 /// --- level 0 --- /// level number = 0x0 (0) /// level type = thread (1) /// bit width of level = 0x1 (1) /// number of logical processors at level = 0x2 (2) /// --- level 1 --- /// level number = 0x1 (1) /// level type = core (2) /// bit width of level = 0x6 (6) /// number of logical processors at level = 0x30 (48) /// XSAVE features (0xd/0): /// XCR0 lower 32 bits valid bit field mask = 0x000002ff /// XCR0 upper 32 bits valid bit field mask = 0x00000000 /// XCR0 supported: x87 state = true /// XCR0 supported: SSE state = true /// XCR0 supported: AVX state = true /// XCR0 supported: MPX BNDREGS = true /// XCR0 supported: MPX BNDCSR = true /// XCR0 supported: AVX-512 opmask = true /// XCR0 supported: AVX-512 ZMM_Hi256 = true /// XCR0 supported: AVX-512 Hi16_ZMM = true /// IA32_XSS supported: PT state = false /// XCR0 supported: PKRU state = true /// XCR0 supported: CET_U state = false /// XCR0 supported: CET_S state = false /// IA32_XSS supported: HDC state = false /// bytes required by fields in XCR0 = 0x00000a88 (2696) /// bytes required by XSAVE/XRSTOR area = 0x00000a88 (2696) /// XSAVE features (0xd/1): /// XSAVEOPT instruction = true /// XSAVEC instruction = true /// XGETBV instruction = true /// XSAVES/XRSTORS instructions = true /// SAVE area size in bytes = 0x00000a08 (2568) /// IA32_XSS lower 32 bits valid bit field mask = 0x00000100 /// IA32_XSS upper 32 bits valid bit field mask = 0x00000000 /// AVX/YMM features (0xd/2): /// AVX/YMM save state byte size = 0x00000100 (256) /// AVX/YMM save state byte offset = 0x00000240 (576) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// MPX BNDREGS features (0xd/3): /// MPX BNDREGS save state byte size = 0x00000040 (64) /// MPX BNDREGS save state byte offset = 0x000003c0 (960) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// MPX BNDCSR features (0xd/4): /// MPX BNDCSR save state byte size = 0x00000040 (64) /// MPX BNDCSR save state byte offset = 0x00000400 (1024) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// AVX-512 opmask features (0xd/5): /// AVX-512 opmask save state byte size = 0x00000040 (64) /// AVX-512 opmask save state byte offset = 0x00000440 (1088) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// AVX-512 ZMM_Hi256 features (0xd/6): /// AVX-512 ZMM_Hi256 save state byte size = 0x00000200 (512) /// AVX-512 ZMM_Hi256 save state byte offset = 0x00000480 (1152) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// AVX-512 Hi16_ZMM features (0xd/7): /// AVX-512 Hi16_ZMM save state byte size = 0x00000400 (1024) /// AVX-512 Hi16_ZMM save state byte offset = 0x00000680 (1664) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// PT features (0xd/8): /// PT save state byte size = 0x00000080 (128) /// PT save state byte offset = 0x00000000 (0) /// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) /// 64-byte alignment in compacted XSAVE = false /// PKRU features (0xd/9): /// PKRU save state byte size = 0x00000008 (8) /// PKRU save state byte offset = 0x00000a80 (2688) /// supported in IA32_XSS or XCR0 = XCR0 (user state) /// 64-byte alignment in compacted XSAVE = false /// Quality of Service Monitoring Resource Type (0xf/0): /// Maximum range of RMID = 207 /// supports L3 cache QoS monitoring = true /// L3 Cache Quality of Service Monitoring (0xf/1): /// Conversion factor from IA32_QM_CTR to bytes = 106496 /// Maximum range of RMID = 207 /// supports L3 occupancy monitoring = true /// supports L3 total bandwidth monitoring = true /// supports L3 local bandwidth monitoring = true /// Resource Director Technology Allocation (0x10/0): /// L3 cache allocation technology supported = true /// L2 cache allocation technology supported = false /// memory bandwidth allocation supported = true /// L3 Cache Allocation Technology (0x10/1): /// length of capacity bit mask = 0xb (11) /// Bit-granular map of isolation/contention = 0x00000600 /// infrequent updates of COS = false /// code and data prioritization supported = true /// highest COS number supported = 0xf (15) /// Memory Bandwidth Allocation (0x10/3): /// maximum throttling value = 0x5a (90) /// delay values are linear = true /// highest COS number supported = 0x7 (7) /// 0x00000011 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 /// Software Guard Extensions (SGX) capability (0x12/0): /// SGX1 supported = false /// SGX2 supported = false /// SGX ENCLV E*VIRTCHILD, ESETCONTEXT = false /// SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC = false /// MISCSELECT.EXINFO supported: #PF & #GP = false /// MISCSELECT.CPINFO supported: #CP = false /// MaxEnclaveSize_Not64 (log2) = 0x0 (0) /// MaxEnclaveSize_64 (log2) = 0x0 (0) /// 0x00000013 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 /// Intel Processor Trace (0x14): /// IA32_RTIT_CR3_MATCH is accessible = true /// configurable PSB & cycle-accurate = true /// IP & TraceStop filtering; PT preserve = true /// MTC timing packet; suppress COFI-based = true /// PTWRITE support = false /// power event trace support = false /// ToPA output scheme support = true /// ToPA can hold many output entries = true /// single-range output scheme support = true /// output to trace transport = false /// IP payloads have LIP values & CS = false /// configurable address ranges = 0x2 (2) /// supported MTC periods bitmask = 0x249 (585) /// supported cycle threshold bitmask = 0x3fff (16383) /// supported config PSB freq bitmask = 0x3f (63) /// Time Stamp Counter/Core Crystal Clock Information (0x15): /// TSC/clock ratio = 168/2 /// nominal core crystal clock = 0 Hz /// Processor Frequency Information (0x16): /// Core Base Frequency (MHz) = 0x834 (2100) /// Core Maximum Frequency (MHz) = 0xe74 (3700) /// Bus (Reference) Frequency (MHz) = 0x64 (100) /// extended feature flags (0x80000001/edx): /// SYSCALL and SYSRET instructions = true /// execution disable = true /// 1-GB large page support = true /// RDTSCP = true /// 64-bit extensions technology available = true /// Intel feature flags (0x80000001/ecx): /// LAHF/SAHF supported in 64-bit mode = true /// LZCNT advanced bit manipulation = true /// 3DNow! PREFETCH/PREFETCHW instructions = true /// brand = "Intel(R) Xeon(R) Gold 6252 CPU @ 2.10GHz" /// L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): /// instruction # entries = 0x0 (0) /// instruction associativity = 0x0 (0) /// data # entries = 0x0 (0) /// data associativity = 0x0 (0) /// L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): /// instruction # entries = 0x0 (0) /// instruction associativity = 0x0 (0) /// data # entries = 0x0 (0) /// data associativity = 0x0 (0) /// L1 data cache information (0x80000005/ecx): /// line size (bytes) = 0x0 (0) /// lines per tag = 0x0 (0) /// associativity = 0x0 (0) /// size (KB) = 0x0 (0) /// L1 instruction cache information (0x80000005/edx): /// line size (bytes) = 0x0 (0) /// lines per tag = 0x0 (0) /// associativity = 0x0 (0) /// size (KB) = 0x0 (0) /// L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): /// instruction # entries = 0x0 (0) /// instruction associativity = L2 off (0) /// data # entries = 0x0 (0) /// data associativity = L2 off (0) /// L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): /// instruction # entries = 0x0 (0) /// instruction associativity = L2 off (0) /// data # entries = 0x0 (0) /// data associativity = L2 off (0) /// L2 unified cache information (0x80000006/ecx): /// line size (bytes) = 0x40 (64) /// lines per tag = 0x0 (0) /// associativity = 8-way (6) /// size (KB) = 0x100 (256) /// L3 cache information (0x80000006/edx): /// line size (bytes) = 0x0 (0) /// lines per tag = 0x0 (0) /// associativity = L2 off (0) /// size (in 512KB units) = 0x0 (0) /// RAS Capability (0x80000007/ebx): /// MCA overflow recovery support = false /// SUCCOR support = false /// HWA: hardware assert support = false /// scalable MCA support = false /// Advanced Power Management Features (0x80000007/ecx): /// CmpUnitPwrSampleTimeRatio = 0x0 (0) /// Advanced Power Management Features (0x80000007/edx): /// TS: temperature sensing diode = false /// FID: frequency ID control = false /// VID: voltage ID control = false /// TTP: thermal trip = false /// TM: thermal monitor = false /// STC: software thermal control = false /// 100 MHz multiplier control = false /// hardware P-State control = false /// TscInvariant = true /// CPB: core performance boost = false /// read-only effective frequency interface = false /// processor feedback interface = false /// APM power reporting = false /// connected standby = false /// RAPL: running average power limit = false /// Physical Address and Linear Address Size (0x80000008/eax): /// maximum physical address bits = 0x2e (46) /// maximum linear (virtual) address bits = 0x30 (48) /// maximum guest physical address bits = 0x0 (0) /// Extended Feature Extensions ID (0x80000008/ebx): /// CLZERO instruction = false /// instructions retired count support = false /// always save/restore error pointers = false /// RDPRU instruction = false /// memory bandwidth enforcement = false /// WBNOINVD instruction = false /// IBPB: indirect branch prediction barrier = false /// IBRS: indirect branch restr speculation = false /// STIBP: 1 thr indirect branch predictor = false /// STIBP always on preferred mode = false /// ppin processor id number supported = false /// SSBD: speculative store bypass disable = false /// virtualized SSBD = false /// SSBD fixed in hardware = false /// Size Identifiers (0x80000008/ecx): /// number of CPU cores = 0x1 (1) /// ApicIdCoreIdSize = 0x0 (0) /// performance time-stamp counter size = 0x0 (0) /// Feature Extended Size (0x80000008/edx): /// RDPRU instruction max input support = 0x0 (0) /// (multi-processing synth) = multi-core (c=24), hyper-threaded (t=2) /// (multi-processing method) = Intel leaf 0xb /// (APIC widths synth): CORE_width=6 SMT_width=1 /// (APIC synth): PKG_ID=1 CORE_ID=45 SMT_ID=0 /// (uarch synth) = Intel Cascade Lake {Skylake}, 14nm /// (synth) = Intel Scalable (2nd Gen) Bronze/Silver/Gold/Platinum (Cascade Lake B1/L1/R1) {Skylake}, 14nm /// ``` static CPUID_VALUE_MAP: phf::Map = phf_map! { 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000016, ebx: 0x756e6547, ecx: 0x6c65746e, edx: 0x49656e69 }, 0x00000001_00000000u64 => CpuIdResult { eax: 0x00050657, ebx: 0xc7400800, ecx: 0x7ffefbff, edx: 0xbfebfbff }, 0x00000002_00000000u64 => CpuIdResult { eax: 0x76036301, ebx: 0x00f0b5ff, ecx: 0x00000000, edx: 0x00c30000 }, 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000004_00000000u64 => CpuIdResult { eax: 0x7c004121, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x00000004_00000001u64 => CpuIdResult { eax: 0x7c004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, 0x00000004_00000002u64 => CpuIdResult { eax: 0x7c004143, ebx: 0x03c0003f, ecx: 0x000003ff, edx: 0x00000000 }, 0x00000004_00000003u64 => CpuIdResult { eax: 0x7c0fc163, ebx: 0x0280003f, ecx: 0x0000cfff, edx: 0x00000005 }, 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x00002020 }, 0x00000006_00000000u64 => CpuIdResult { eax: 0x00000077, ebx: 0x00000002, ecx: 0x00000009, edx: 0x00000000 }, 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0xd39ff7eb, ecx: 0x00000818, edx: 0xbc000400 }, 0x00000007_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000a_00000000u64 => CpuIdResult { eax: 0x07300404, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000603 }, 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x000000c7 }, 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000006, ebx: 0x00000030, ecx: 0x00000201, edx: 0x000000c7 }, 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000000u64 => CpuIdResult { eax: 0x000002ff, ebx: 0x00000a88, ecx: 0x00000a88, edx: 0x00000000 }, 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000a08, ecx: 0x00000100, edx: 0x00000000 }, 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000003u64 => CpuIdResult { eax: 0x00000040, ebx: 0x000003c0, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000004u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000400, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000005u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000440, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000006u64 => CpuIdResult { eax: 0x00000200, ebx: 0x00000480, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000007u64 => CpuIdResult { eax: 0x00000400, ebx: 0x00000680, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000d_00000008u64 => CpuIdResult { eax: 0x00000080, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000a80, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x000000cf, ecx: 0x00000000, edx: 0x00000002 }, 0x0000000f_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0001a000, ecx: 0x000000cf, edx: 0x00000007 }, 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0000000a, ecx: 0x00000000, edx: 0x00000000 }, 0x00000010_00000001u64 => CpuIdResult { eax: 0x0000000a, ebx: 0x00000600, ecx: 0x00000004, edx: 0x0000000f }, 0x00000010_00000003u64 => CpuIdResult { eax: 0x00000059, ebx: 0x00000000, ecx: 0x00000004, edx: 0x00000007 }, 0x00000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x00000014_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x0000000f, ecx: 0x00000007, edx: 0x00000000 }, 0x00000014_00000001u64 => CpuIdResult { eax: 0x02490002, ebx: 0x003f3fff, ecx: 0x00000000, edx: 0x00000000 }, 0x00000015_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x000000a8, ecx: 0x00000000, edx: 0x00000000 }, 0x00000016_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000001_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000121, edx: 0x2c100800 }, 0x80000002_00000000u64 => CpuIdResult { eax: 0x65746e49, ebx: 0x2952286c, ecx: 0x6f655820, edx: 0x2952286e }, 0x80000003_00000000u64 => CpuIdResult { eax: 0x6c6f4720, ebx: 0x32362064, ecx: 0x43203235, edx: 0x40205550 }, 0x80000004_00000000u64 => CpuIdResult { eax: 0x312e3220, ebx: 0x7a484730, ecx: 0x00000000, edx: 0x00000000 }, 0x80000005_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80000006_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x01006040, edx: 0x00000000 }, 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000100 }, 0x80000008_00000000u64 => CpuIdResult { eax: 0x0000302e, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, }; fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { let key = (eax as u64) << u32::BITS | ecx as u64; CPUID_VALUE_MAP[&key] } /// Check that vendor is AuthenticAMD. #[test] fn vendor_check() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let v = cpuid.get_vendor_info().expect("Need to find vendor info"); assert_eq!(v.as_str(), "GenuineIntel"); } /// Check feature info gives correct values for CPU #[test] fn version_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let f = cpuid.get_feature_info().expect("Need to find feature info"); assert_eq!(f.base_family_id(), 6); assert_eq!(f.base_model_id(), 5); assert_eq!(f.stepping_id(), 7); assert_eq!(f.extended_family_id(), 0); assert_eq!(f.extended_model_id(), 5); assert_eq!(f.family_id(), 6); assert_eq!(f.model_id(), 85); assert_eq!(f.max_logical_processor_ids(), 64); assert_eq!(f.initial_local_apic_id(), 199); // different from recorded output assert_eq!(f.cflush_cache_line_size(), 0x8); assert_eq!(f.brand_index(), 0x0); assert!(f.has_fpu()); assert!(f.has_vme()); assert!(f.has_de()); assert!(f.has_pse()); assert!(f.has_tsc()); assert!(f.has_msr()); assert!(f.has_pae()); assert!(f.has_mce()); assert!(f.has_cmpxchg8b()); assert!(f.has_apic()); assert!(f.has_sysenter_sysexit()); assert!(f.has_mtrr()); assert!(f.has_pge()); assert!(f.has_mca()); assert!(f.has_cmov()); assert!(f.has_pat()); assert!(f.has_pse36()); assert!(!f.has_psn()); assert!(f.has_clflush()); assert!(f.has_ds()); assert!(f.has_acpi()); assert!(f.has_mmx()); assert!(f.has_fxsave_fxstor()); assert!(f.has_sse()); assert!(f.has_sse2()); assert!(f.has_ss()); assert!(f.has_htt()); assert!(f.has_tm()); assert!(f.has_pbe()); assert!(f.has_sse3()); assert!(f.has_pclmulqdq()); assert!(f.has_ds_area()); assert!(f.has_monitor_mwait()); assert!(f.has_cpl()); assert!(f.has_vmx()); assert!(f.has_smx()); assert!(f.has_eist()); assert!(f.has_tm2()); assert!(f.has_ssse3()); assert!(!f.has_cnxtid()); // has_SDBG assert!(f.has_fma()); assert!(f.has_cmpxchg16b()); // xTPR assert!(f.has_pdcm()); assert!(f.has_pcid()); assert!(f.has_dca()); assert!(f.has_sse41()); assert!(f.has_sse42()); assert!(f.has_x2apic()); assert!(f.has_movbe()); assert!(f.has_popcnt()); assert!(f.has_tsc_deadline()); assert!(f.has_aesni()); assert!(f.has_xsave()); assert!(f.has_oxsave()); assert!(f.has_avx()); assert!(f.has_f16c()); assert!(f.has_rdrand()); assert!(!f.has_hypervisor()); } #[test] fn cache_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let ci = cpuid.get_cache_info().expect("Leaf is supported"); for (idx, cache) in ci.enumerate() { match idx { 0 => assert_eq!(cache.num, 0xff), 1 => assert_eq!(cache.num, 0x63), 2 => assert_eq!(cache.num, 0xb5), 3 => assert_eq!(cache.num, 0x03), 4 => assert_eq!(cache.num, 0xf0), 5 => assert_eq!(cache.num, 0x76), 6 => assert_eq!(cache.num, 0xc3), _ => unreachable!(), } } } #[test] fn processor_serial() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let psn = cpuid.get_processor_serial().expect("Leaf is supported"); assert_eq!(psn.serial_lower(), 0x0); assert_eq!(psn.serial_middle(), 0x0); } #[test] fn monitor_mwait() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); assert_eq!(mw.largest_monitor_line(), 64); assert_eq!(mw.smallest_monitor_line(), 64); assert!(mw.interrupts_as_break_event()); assert!(mw.extensions_supported()); assert_eq!(mw.supported_c0_states(), 0x0); assert_eq!(mw.supported_c1_states(), 0x2); assert_eq!(mw.supported_c2_states(), 0x0); assert_eq!(mw.supported_c3_states(), 0x2); assert_eq!(mw.supported_c4_states(), 0x0); assert_eq!(mw.supported_c5_states(), 0x0); assert_eq!(mw.supported_c6_states(), 0x0); assert_eq!(mw.supported_c7_states(), 0x0); } #[test] fn thermal_power() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); assert!(mw.has_dts()); assert!(mw.has_turbo_boost()); assert!(mw.has_arat()); assert!(mw.has_pln()); assert!(mw.has_ecmd()); assert!(mw.has_ptm()); assert!(!mw.has_hwp()); assert!(!mw.has_hwp_notification()); assert!(!mw.has_hwp_activity_window()); assert!(!mw.has_hwp_energy_performance_preference()); assert!(!mw.has_hwp_package_level_request()); assert!(!mw.has_hdc()); assert!(!mw.has_turbo_boost3()); assert!(!mw.has_hwp_capabilities()); assert!(!mw.has_hwp_peci_override()); assert!(!mw.has_flexible_hwp()); assert!(!mw.has_hwp_fast_access_mode()); assert!(mw.has_hw_coord_feedback()); assert!(!mw.has_ignore_idle_processor_hwp_request()); // some missing assert_eq!(mw.dts_irq_threshold(), 0x2); // some missing assert!(mw.has_energy_bias_pref()); } #[test] fn extended_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_feature_info() .expect("Leaf is supported"); assert!(e.has_fsgsbase()); assert!(e.has_tsc_adjust_msr()); assert!(!e.has_sgx()); assert!(e.has_bmi1()); assert!(!e.has_hle()); assert!(e.has_avx2()); assert!(e.has_fdp()); assert!(e.has_smep()); assert!(e.has_bmi2()); assert!(e.has_rep_movsb_stosb()); assert!(e.has_invpcid()); assert!(!e.has_rtm()); assert!(e.has_rdtm()); assert!(e.has_fpu_cs_ds_deprecated()); assert!(e.has_mpx()); assert!(e.has_rdta()); assert!(e.has_avx512f()); assert!(e.has_avx512dq()); assert!(e.has_rdseed()); assert!(e.has_adx()); assert!(e.has_smap()); assert!(!e.has_avx512_ifma()); assert!(e.has_clflushopt()); assert!(e.has_clwb()); assert!(e.has_processor_trace()); assert!(!e.has_avx512pf()); assert!(!e.has_avx512er()); assert!(e.has_avx512cd()); assert!(!e.has_sha()); assert!(e.has_avx512bw()); assert!(e.has_avx512vl()); assert!(!e.has_prefetchwt1()); // ... assert!(!e.has_umip()); assert!(e.has_pku()); assert!(e.has_ospke()); assert!(e.has_avx512vnni()); assert!(!e.has_rdpid()); assert!(!e.has_sgx_lc()); assert_eq!(e.mawau_value(), 0x0); } #[test] fn direct_cache_access() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let dca = cpuid.get_direct_cache_access_info().expect("Leaf exists"); assert_eq!(dca.get_dca_cap_value(), 0x0); } #[test] fn perfmon_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let pm = cpuid .get_performance_monitoring_info() .expect("Leaf exists"); assert_eq!(pm.version_id(), 0x4); assert_eq!(pm.number_of_counters(), 0x4); assert_eq!(pm.counter_bit_width(), 0x30); assert_eq!(pm.ebx_length(), 0x7); assert!(!pm.is_core_cyc_ev_unavailable()); assert!(!pm.is_inst_ret_ev_unavailable()); assert!(!pm.is_ref_cycle_ev_unavailable()); assert!(!pm.is_cache_ref_ev_unavailable()); assert!(!pm.is_ll_cache_miss_ev_unavailable()); assert!(!pm.is_branch_inst_ret_ev_unavailable()); assert!(!pm.is_branch_midpred_ev_unavailable()); assert_eq!(pm.fixed_function_counters(), 0x3); assert_eq!(pm.fixed_function_counters_bit_width(), 0x30); assert!(!pm.has_any_thread_deprecation()); } #[test] fn extended_topology_info() { use crate::TopologyType; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let mut e = cpuid .get_extended_topology_info() .expect("Leaf is supported"); let t = e.next().expect("Have level 0"); assert_eq!(t.x2apic_id(), 199); // different from doc, unpinned execution assert_eq!(t.level_number(), 0); assert_eq!(t.level_type(), TopologyType::SMT); assert_eq!(t.shift_right_for_next_apic_id(), 0x1); assert_eq!(t.processors(), 2); let t = e.next().expect("Have level 1"); assert_eq!(t.level_number(), 1); assert_eq!(t.level_type(), TopologyType::Core); assert_eq!(t.shift_right_for_next_apic_id(), 0x6); assert_eq!(t.processors(), 48); assert_eq!(t.x2apic_id(), 199); // different from doc, unpinned execution } #[test] fn extended_state_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_extended_state_info().expect("Leaf is supported"); assert!(e.xcr0_supports_legacy_x87()); assert!(e.xcr0_supports_sse_128()); assert!(e.xcr0_supports_avx_256()); assert!(e.xcr0_supports_mpx_bndregs()); assert!(e.xcr0_supports_mpx_bndcsr()); assert!(e.xcr0_supports_avx512_opmask()); assert!(e.xcr0_supports_avx512_zmm_hi256()); assert!(e.xcr0_supports_avx512_zmm_hi16()); // cpuid binary says this isn't supported, I think it's a bug there and it's // supposed to read from ecx1 like we do: assert!(e.ia32_xss_supports_pt()); assert!(e.xcr0_supports_pkru()); // ... assert!(!e.ia32_xss_supports_hdc()); assert_eq!(e.xsave_area_size_enabled_features(), 2696); assert_eq!(e.xsave_area_size_supported_features(), 2696); assert!(e.has_xsaveopt()); assert!(e.has_xsavec()); assert!(e.has_xgetbv()); assert!(e.has_xsaves_xrstors()); // ... assert_eq!(e.xsave_size(), 2568); // ... let mut e = e.iter(); let ee = e.next().expect("Has level 2"); assert_eq!(ee.size(), 256); assert_eq!(ee.offset(), 576); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 3"); assert_eq!(ee.size(), 64); assert_eq!(ee.offset(), 960); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 4"); assert_eq!(ee.size(), 64); assert_eq!(ee.offset(), 1024); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 5"); assert_eq!(ee.size(), 64); assert_eq!(ee.offset(), 1088); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 6"); assert_eq!(ee.size(), 512); assert_eq!(ee.offset(), 1152); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 7"); assert_eq!(ee.size(), 1024); assert_eq!(ee.offset(), 1664); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 8"); assert_eq!(ee.size(), 128); assert_eq!(ee.offset(), 0); assert!(!ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); let ee = e.next().expect("Has level 9"); assert_eq!(ee.size(), 8); assert_eq!(ee.offset(), 2688); assert!(ee.is_in_xcr0()); assert!(!ee.is_compacted_format()); } #[test] fn rdt_monitoring_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); assert_eq!(e.rmid_range(), 207); assert!(e.has_l3_monitoring()); let l3m = e.l3_monitoring().expect("Leaf is available"); assert_eq!(l3m.conversion_factor(), 106496); assert_eq!(l3m.maximum_rmid_range(), 207); assert!(l3m.has_occupancy_monitoring()); assert!(l3m.has_total_bandwidth_monitoring()); assert!(l3m.has_local_bandwidth_monitoring()); } #[test] fn rdt_allocation_info() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); assert!(e.has_l3_cat()); assert!(!e.has_l2_cat()); assert!(e.has_memory_bandwidth_allocation()); assert!(e.l2_cat().is_none()); let l3c = e.l3_cat().expect("Leaf is available"); assert_eq!(l3c.capacity_mask_length(), 0xb); assert_eq!(l3c.isolation_bitmap(), 0x00000600); assert_eq!(l3c.highest_cos(), 15); assert!(l3c.has_code_data_prioritization()); // infrequent updates of COS missing let mba = e.memory_bandwidth_allocation().expect("Leaf is available"); assert_eq!(mba.max_hba_throttling(), 90); assert!(mba.has_linear_response_delay()); assert_eq!(mba.highest_cos(), 0x7); } #[test] fn sgx_test() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_sgx_info().is_none()); } #[test] fn processor_trace() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let pt = cpuid.get_processor_trace_info().expect("Leaf is available"); assert!(pt.has_rtit_cr3_match()); assert!(pt.has_configurable_psb_and_cycle_accurate_mode()); assert!(pt.has_ip_tracestop_filtering()); assert!(pt.has_mtc_timing_packet_coefi_suppression()); assert!(!pt.has_ptwrite()); assert!(!pt.has_power_event_trace()); assert!(pt.has_topa()); assert!(pt.has_topa_maximum_entries()); assert!(pt.has_single_range_output_scheme()); assert!(!pt.has_trace_transport_subsystem()); assert!(!pt.has_lip_with_cs_base()); assert_eq!(pt.configurable_address_ranges(), 2); assert_eq!(pt.supported_mtc_period_encodings(), 585); assert_eq!(pt.supported_cycle_threshold_value_encodings(), 16383); assert_eq!(pt.supported_psb_frequency_encodings(), 63); } #[test] fn tsc() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid.get_tsc_info().expect("Leaf is available"); assert_eq!(e.denominator(), 2); assert_eq!(e.numerator(), 168); assert_eq!(e.nominal_frequency(), 0x0); assert_eq!(e.tsc_frequency(), None); } #[test] fn processor_frequency() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_frequency_info() .expect("Leaf is supported"); assert_eq!(e.processor_base_frequency(), 2100); assert_eq!(e.processor_max_frequency(), 3700); assert_eq!(e.bus_frequency(), 100); } #[test] fn extended_processor_and_feature_identifiers() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_extended_processor_and_feature_identifiers() .expect("Leaf is supported"); assert_eq!(e.pkg_type(), 0x0); // reserved on Intel assert_eq!(e.brand_id(), 0x0); // reserved on Intel assert!(e.has_lahf_sahf()); assert!(!e.has_cmp_legacy()); assert!(!e.has_svm()); assert!(!e.has_ext_apic_space()); assert!(!e.has_alt_mov_cr8()); assert!(e.has_lzcnt()); assert!(!e.has_sse4a()); assert!(!e.has_misaligned_sse_mode()); assert!(e.has_prefetchw()); assert!(!e.has_osvw()); assert!(!e.has_ibs()); assert!(!e.has_xop()); assert!(!e.has_skinit()); assert!(!e.has_wdt()); assert!(!e.has_lwp()); assert!(!e.has_fma4()); assert!(!e.has_tbm()); assert!(!e.has_topology_extensions()); assert!(!e.has_perf_cntr_extensions()); assert!(!e.has_nb_perf_cntr_extensions()); assert!(!e.has_data_access_bkpt_extension()); assert!(!e.has_perf_tsc()); assert!(!e.has_perf_cntr_llc_extensions()); assert!(!e.has_monitorx_mwaitx()); assert!(!e.has_addr_mask_extension()); assert!(e.has_syscall_sysret()); assert!(e.has_execute_disable()); assert!(!e.has_mmx_extensions()); assert!(!e.has_fast_fxsave_fxstor()); assert!(e.has_1gib_pages()); assert!(e.has_rdtscp()); assert!(e.has_64bit_mode()); assert!(!e.has_amd_3dnow_extensions()); assert!(!e.has_3dnow()); } #[test] fn brand_string() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_brand_string() .expect("Leaf is supported"); assert_eq!(e.as_str(), "Intel(R) Xeon(R) Gold 6252 CPU @ 2.10GHz"); } #[test] fn l1_tlb_cache() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_l1_cache_and_tlb_info().is_none()); } #[test] fn l2_l3_tlb_cache() { use crate::Associativity; let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_l2_l3_cache_and_tlb_info() .expect("Leaf is supported"); // Unsupported on Intel assert_eq!(e.itlb_2m_4m_associativity(), Associativity::Disabled); assert_eq!(e.itlb_2m_4m_size(), 0); assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::Disabled); assert_eq!(e.dtlb_2m_4m_size(), 0); assert_eq!(e.itlb_4k_size(), 0); assert_eq!(e.itlb_4k_associativity(), Associativity::Disabled); assert_eq!(e.dtlb_4k_size(), 0); assert_eq!(e.dtlb_4k_associativity(), Associativity::Disabled); // Supported on Intel assert_eq!(e.l2cache_line_size(), 64); assert_eq!(e.l2cache_lines_per_tag(), 0); assert_eq!(e.l2cache_associativity(), Associativity::NWay(8)); assert_eq!(e.l2cache_size(), 256); // Unsupported on Intel assert_eq!(e.l3cache_line_size(), 0); assert_eq!(e.l3cache_lines_per_tag(), 0); assert_eq!(e.l3cache_associativity(), Associativity::Disabled); assert_eq!(e.l3cache_size(), 0); } #[test] fn apm() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_advanced_power_mgmt_info() .expect("Leaf is supported"); assert!(!e.has_mca_overflow_recovery()); assert!(!e.has_succor()); assert!(!e.has_hwa()); // ... assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); assert!(!e.has_ts()); assert!(!e.has_freq_id_ctrl()); assert!(!e.has_volt_id_ctrl()); assert!(!e.has_thermtrip()); assert!(!e.has_tm()); assert!(!e.has_100mhz_steps()); assert!(!e.has_hw_pstate()); assert!(e.has_invariant_tsc()); // The only Intel supported feature here assert!(!e.has_cpb()); assert!(!e.has_ro_effective_freq_iface()); assert!(!e.has_feedback_iface()); assert!(!e.has_power_reporting_iface()); } #[test] fn processor_capcity_features() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); let e = cpuid .get_processor_capacity_feature_info() .expect("Leaf is supported"); assert_eq!(e.physical_address_bits(), 46); assert_eq!(e.linear_address_bits(), 48); assert_eq!(e.guest_physical_address_bits(), 0); assert!(!e.has_cl_zero()); assert!(!e.has_inst_ret_cntr_msr()); assert!(!e.has_restore_fp_error_ptrs()); assert!(!e.has_invlpgb()); assert!(!e.has_rdpru()); assert!(!e.has_mcommit()); assert!(!e.has_wbnoinvd()); assert!(!e.has_int_wbinvd()); assert!(!e.has_unsupported_efer_lmsle()); assert!(!e.has_invlpgb_nested()); assert_eq!(e.invlpgb_max_pages(), 0x0); assert_eq!(e.maximum_logical_processors(), 1); // Not sure why this is set, it's reserved :( assert_eq!(e.num_phys_threads(), 1); // Not sure why this is set, it's reserved :( assert_eq!(e.apic_id_size(), 0); assert_eq!(e.perf_tsc_size(), 40); // Not sure why this is set, it's reserved :( assert_eq!(e.max_rdpru_id(), 0); } #[test] fn remaining_unsupported_leafs() { let cpuid = CpuId::with_cpuid_fn(cpuid_reader); assert!(cpuid.get_deterministic_address_translation_info().is_none()); assert!(cpuid.get_soc_vendor_info().is_none()); assert!(cpuid.get_extended_topology_info_v2().is_none()); assert!(cpuid.get_tlb_1gb_page_info().is_none()); assert!(cpuid.get_performance_optimization_info().is_none()); assert!(cpuid.get_processor_topology_info().is_none()); assert!(cpuid.get_memory_encryption_info().is_none()); }