From 651b008e838f5208e84d9aaece665ab54484ce2a Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 14:20:43 +0100 Subject: [PATCH 1/8] vmm: Enable AMX states prior to checking CPUID compatibility Since enabling AMX tile state components affect the result returned by `Hypervisor::get_supported_cpuid` we want this enabled prior to checking CPUID compatibility between the source and destination VMs. Although this is not required today, it is necessary in order for the upcoming CPU profiles correctly, and it will also be necessary once the check_cpuid_compatibility checks are extended to take state components into account. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- vmm/src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index b6a1cba271..7497d3cc2d 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -35,7 +35,7 @@ use std::thread::JoinHandle; use std::time::{Duration, Instant}; use std::{io, mem, result, thread}; -use anyhow::anyhow; +use anyhow::{Context, anyhow}; #[cfg(feature = "dbus_api")] use api::dbus::{DBusApiOptions, DBusApiShutdownChannels}; use api::http::HttpApiHandle; @@ -2354,6 +2354,16 @@ impl Vmm { let dest_cpuid = &{ let vm_config = &src_vm_config.lock().unwrap(); + if vm_config.cpus.features.amx { + // Need to enable AMX tile state components before generating common cpuid + // as this affects what Hypervisor::get_supported_cpuid returns. + hypervisor::arch::x86::XsaveState::enable_amx_state_components( + self.hypervisor.as_ref(), + ) + .context("Unable to enable AMX before generating common CPUID") + .map_err(MigratableError::MigrateReceive)?; + } + let phys_bits = vm::physical_bits(&self.hypervisor, vm_config.cpus.max_phys_bits); arch::generate_common_cpuid( &self.hypervisor.clone(), From 0eb0dcf870660b4f06024856811049ee22c6b1e6 Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 18:23:11 +0100 Subject: [PATCH 2/8] hypervisor: Permit enabling AMX tile state components more than once Temporary workaround until we switch over to the WIP fix upstream Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- hypervisor/src/arch/x86/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hypervisor/src/arch/x86/mod.rs b/hypervisor/src/arch/x86/mod.rs index 56d1e98a24..f81734f0a9 100644 --- a/hypervisor/src/arch/x86/mod.rs +++ b/hypervisor/src/arch/x86/mod.rs @@ -396,9 +396,7 @@ impl XsaveState { ((size as usize) - size_of::()) .div_ceil(size_of::()) }; - XSAVE_FAM_LENGTH - .set(fam_length) - .expect("This should only be set once"); + let _ = XSAVE_FAM_LENGTH.set(fam_length); } Ok(()) From a77f6c525a8d932c31bcafbd20172aa78b1e27ac Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 10:44:05 +0100 Subject: [PATCH 3/8] arch: Initial data structures for describing CPUID parameters These data structures are required to define CPU profiles. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- Cargo.lock | 69 ++++++++++++ arch/Cargo.toml | 5 + arch/src/x86_64/cpuid_definitions/mod.rs | 136 +++++++++++++++++++++++ arch/src/x86_64/mod.rs | 4 +- 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 arch/src/x86_64/cpuid_definitions/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 92b01e42c1..b96aead2cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,7 +114,9 @@ dependencies = [ "libc", "linux-loader", "log", + "proptest", "serde", + "serde_json", "thiserror 2.0.12", "uuid", "vm-fdt", @@ -322,6 +324,21 @@ dependencies = [ "syn", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitfield-struct" version = "0.10.1" @@ -1809,6 +1826,31 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.9.4", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.40" @@ -1853,6 +1895,15 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core", +] + [[package]] name = "range_map_vec" version = "0.2.0" @@ -2030,6 +2081,18 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.20" @@ -2372,6 +2435,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/arch/Cargo.toml b/arch/Cargo.toml index 804be793d0..3e82367707 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -28,5 +28,10 @@ vmm-sys-util = { workspace = true, features = ["with-serde"] } fdt_parser = { version = "0.1.5", package = "fdt" } vm-fdt = { workspace = true } +# Use this to test our custom serialization logic +[dev-dependencies] +proptest = "1.0.0" +serde_json = { workspace = true } + [lints] workspace = true diff --git a/arch/src/x86_64/cpuid_definitions/mod.rs b/arch/src/x86_64/cpuid_definitions/mod.rs new file mode 100644 index 0000000000..a5b39dbe03 --- /dev/null +++ b/arch/src/x86_64/cpuid_definitions/mod.rs @@ -0,0 +1,136 @@ +// Copyright © 2025 Cyberus Technology GmbH +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::io::Write; +use std::ops::RangeInclusive; + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::x86_64::CpuidReg; + +pub(in crate::x86_64) fn serialize_as_hex( + input: &u32, + serializer: S, +) -> Result { + // two bytes for "0x" prefix and eight for the hex encoded number + let mut buffer = [0_u8; 10]; + let _ = write!(&mut buffer[..], "{:#010x}", input); + let str = core::str::from_utf8(&buffer[..]) + .expect("the buffer should be filled with valid UTF-8 bytes"); + serializer.serialize_str(str) +} + +pub(in crate::x86_64) fn deserialize_from_hex<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result { + let hex = <&'de str as Deserialize>::deserialize(deserializer)?; + u32::from_str_radix(hex.strip_prefix("0x").unwrap_or(""), 16).map_err(|_| { + ::custom(format!("{hex} is not a hex encoded 32 bit integer")) + }) +} + +/// Parameters for inspecting CPUID definitions. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct Parameters { + // The leaf (EAX) parameter used with the CPUID instruction + #[serde(serialize_with = "serialize_as_hex")] + #[serde(deserialize_with = "deserialize_from_hex")] + pub leaf: u32, + // The sub-leaf (ECX) parameter used with the CPUID instruction + pub sub_leaf: RangeInclusive, + // The register we are interested in inspecting which gets filled by the CPUID instruction + pub register: CpuidReg, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use serde::Deserialize; + + use super::{Parameters, deserialize_from_hex, serialize_as_hex}; + use crate::x86_64::CpuidReg; + + /* + Check that the leaves get the string representation we expect. + This does not really matter from a functionality point of view, but we want + to read it in the expected format when manually viewing the generated CPU + profile files. + + Also assert that deserialization gives the original value back + */ + #[test] + fn hex_serialization() { + for (leaf, expected) in [ + 0x0_u32, 0x7, 0xd, 0x1e, 0x40000000, 0x4fffffff, 0x80000000, 0x8fffffff, + ] + .into_iter() + .zip([ + "0x00000000", + "0x00000007", + "0x0000000d", + "0x0000001e", + "0x40000000", + "0x4fffffff", + "0x80000000", + "0x8fffffff", + ]) { + let mut v = Vec::new(); + let mut serializer = serde_json::Serializer::new(&mut v); + serialize_as_hex(&leaf, &mut serializer).unwrap(); + let serialized = str::from_utf8(&v[..]).unwrap(); + // JSON Strings have surrounding "" hence we trim that + let serialized_trimmed = serialized + .strip_prefix('"') + .unwrap() + .strip_suffix('"') + .unwrap(); + dbg!(serialized_trimmed); + assert_eq!(serialized_trimmed, expected); + // Also check that we can deserialize this back to the original value + let mut deserializer = serde_json::Deserializer::from_str(serialized); + let deserialized = deserialize_from_hex(&mut deserializer).unwrap(); + assert_eq!(deserialized, leaf); + } + } + + // Check that serializing and then deserializing a value of type `Parameter` results in the + // same value we started with. + proptest! { + #[test] + fn parameter_serialization_roundtrip_works(leaf in 0u32..u32::MAX, x1 in 0u32..100, x2 in 0u32..100, reg in 0..4) { + let sub_leaf_range_start = std::cmp::min(x1, x2); + let sub_leaf_range_end = std::cmp::max(x1,x2); + let sub_leaf = sub_leaf_range_start..=sub_leaf_range_end; + let register = match reg { + 0 => CpuidReg::EAX, + 1 => CpuidReg::EBX, + 2 => CpuidReg::ECX, + 3 => CpuidReg::EDX, + _ => unreachable!() + }; + let cpuid_parameters = Parameters { + leaf, + sub_leaf, + register + }; + let serialized = serde_json::to_string(&cpuid_parameters).unwrap(); + let deserialized: Parameters = serde_json::from_str(&serialized).unwrap(); + prop_assert_eq!(&deserialized, &cpuid_parameters); + } + } + + // Check that `deserialize_from_hex` does not succeed if the stringified u32 does not start with 0x + proptest! { + #[test] + fn hex_deserialization_requires_prefix(leaf in any::().prop_map(|leaf| std::iter::once('"').chain(leaf.to_string().chars()).chain(std::iter::once('"')).collect::())) { + let mut deserializer = serde_json::Deserializer::from_str(leaf.as_str()); + // Check that standard deserialization works + let result = ::deserialize(&mut deserializer); + prop_assert!(result.is_ok()); + let mut deserializer = serde_json::Deserializer::from_str(leaf.as_str()); + prop_assert!(deserialize_from_hex(&mut deserializer).is_err()); + } + } +} diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 648220e070..7edb0d03ab 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -7,6 +7,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-BSD-3-Clause file. use std::sync::Arc; +pub mod cpuid_definitions; pub mod interrupts; pub mod layout; mod mpspec; @@ -20,6 +21,7 @@ use linux_loader::loader::bootparam::{boot_params, setup_header}; use linux_loader::loader::elf::start_info::{ hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, }; +use serde::{Deserialize, Serialize}; use thiserror::Error; use vm_memory::{ Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, @@ -181,7 +183,7 @@ pub fn get_max_x2apic_id(topology: (u16, u16, u16, u16)) -> u32 { ) } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum CpuidReg { EAX, EBX, From b338de5e6f24266ed082f4f6586e0072570f17df Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 7 Oct 2025 04:39:38 +0200 Subject: [PATCH 4/8] hypervisor: Implement common traits for HypervisorType and CpuVendor We want CPU profiles to keep a record of the hypervisor type and cpu vendor that they are intended to work with. This is made more convenient if all of these types implement common traits (used for serialization). Signed-Off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- hypervisor/src/cpu.rs | 2 +- hypervisor/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index 519b99f567..bfd24f12e8 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -30,7 +30,7 @@ use crate::kvm::{TdxExitDetails, TdxExitStatus}; use crate::{CpuState, MpState, StandardRegisters}; #[cfg(target_arch = "x86_64")] -#[derive(Copy, Clone, Default)] +#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize, Eq, PartialEq)] pub enum CpuVendor { #[default] Unknown, diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs index 205691a421..2e653708c5 100644 --- a/hypervisor/src/lib.rs +++ b/hypervisor/src/lib.rs @@ -69,7 +69,7 @@ pub use vm::{ pub use crate::hypervisor::{Hypervisor, HypervisorError}; -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] pub enum HypervisorType { #[cfg(feature = "kvm")] Kvm, From f62dc8de9125fe464fe1b6c163fcacd11c22804c Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 13:27:00 +0100 Subject: [PATCH 5/8] arch: CpuProfile data structures We introduce essential data structures together with basic functionality that is necessary to apply a CPU profile to a host. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/src/lib.rs | 30 ++++ arch/src/x86_64/cpu_profile.rs | 246 +++++++++++++++++++++++++++++++++ arch/src/x86_64/mod.rs | 1 + 3 files changed, 277 insertions(+) create mode 100644 arch/src/x86_64/cpu_profile.rs diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 36fa20f13c..2a298d0ba3 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -12,12 +12,17 @@ extern crate log; use std::collections::BTreeMap; +use std::str::FromStr; use std::sync::Arc; use std::{fmt, result}; +use serde::de::IntoDeserializer; use serde::{Deserialize, Serialize}; use thiserror::Error; +#[cfg(target_arch = "x86_64")] +pub use crate::x86_64::cpu_profile::CpuProfile; + type GuestMemoryMmap = vm_memory::GuestMemoryMmap; type GuestRegionMmap = vm_memory::GuestRegionMmap; @@ -56,6 +61,31 @@ pub enum Error { /// Type for returning public functions outcome. pub type Result = result::Result; +// If the target_arch is x86_64 we import CpuProfile from the x86_64 module, otherwise we +// declare it here. +#[cfg(not(target_arch = "x86_64"))] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "kebab-case")] +/// A [`CpuProfile`] is a mechanism for ensuring live migration compatibility +/// between host's with potentially different CPU models. +pub enum CpuProfile { + #[default] + Host, +} + +impl FromStr for CpuProfile { + type Err = serde::de::value::Error; + fn from_str(s: &str) -> result::Result { + // Should accept both plain strings, and strings surrounded by `"`. + let normalized = s + .strip_prefix('"') + .unwrap_or(s) + .strip_suffix('"') + .unwrap_or(s); + Self::deserialize(normalized.into_deserializer()) + } +} + /// Type for memory region types. #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum RegionType { diff --git a/arch/src/x86_64/cpu_profile.rs b/arch/src/x86_64/cpu_profile.rs new file mode 100644 index 0000000000..bf5d90f061 --- /dev/null +++ b/arch/src/x86_64/cpu_profile.rs @@ -0,0 +1,246 @@ +// Copyright © 2025 Cyberus Technology GmbH +// +// SPDX-License-Identifier: Apache-2.0 +// + +use hypervisor::arch::x86::CpuIdEntry; +use hypervisor::{CpuVendor, HypervisorType}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::x86_64::CpuidReg; +use crate::x86_64::cpuid_definitions::{Parameters, deserialize_from_hex, serialize_as_hex}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "kebab-case")] +/// A [`CpuProfile`] is a mechanism for ensuring live migration compatibility +/// between host's with potentially different CPU models. +pub enum CpuProfile { + #[default] + Host, + Skylake, + SapphireRapids, +} + +impl CpuProfile { + /// Loads pre-generated data associated with a CPU profile. + /// + /// If the `amx` flag is false then the AMX tile state components will be + /// zeroed out from the associated profile data. This is necessary because + /// they will then not be present in the vector of [`CpuidEntry`] values + /// obtained from the hypervisor. + // + // We can only generate CPU profiles for the KVM hypervisor for the time being. + #[cfg(feature = "kvm")] + pub(in crate::x86_64) fn data(&self, amx: bool) -> Option { + let mut data: CpuProfileData = match self { + Self::Host => None, + Self::Skylake => todo!(), + Self::SapphireRapids => todo!(), + }?; + + if !amx { + // In this case we will need to wipe out the AMX tile state components (if they are included in the profile) + for adj in data.adjustments.iter_mut() { + if adj.0.sub_leaf.start() != adj.0.sub_leaf.end() { + // The generated profiles produce as many sub-leaf entries as possible, and only use ranges for + // values not found. + continue; + } + let sub_leaf = *adj.0.sub_leaf.start(); + let leaf = adj.0.leaf; + if (leaf == 0xd) && (sub_leaf == 0) && (adj.0.register == CpuidReg::EAX) { + adj.1.replacements &= !((1 << 17) | (1 << 18)); + } + + if (leaf == 0xd) && (sub_leaf == 1) && (adj.0.register == CpuidReg::ECX) { + adj.1.replacements &= !((1 << 17) | (1 << 18)); + } + + if (leaf == 0xd) && ((sub_leaf == 17) | (sub_leaf == 18)) { + adj.1.replacements = 0; + } + } + } + + Some(data) + } + + #[cfg(not(feature = "kvm"))] + pub(in crate::x86_64) fn data(&self, _amx: bool) -> Option { + if matches!(*self, Self::Host) { + return None; + } + // This will need to be addressed before upstreaming. + // We will probably need one profile per hypervisor. + unimplemented!() + } +} + +/// Every [`CpuProfile`] different from `Host` has associated [`CpuProfileData`]. +/// +/// New constructors of this struct may only be generated through the CHV CLI (when built from source with +/// the `cpu-profile-generation` feature) which other hosts may then attempt to load in order to +/// increase the likelihood of successful live migrations among all hosts that opted in to the given +/// CPU profile. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[allow(dead_code)] +pub struct CpuProfileData { + /// The hypervisor used when generating this CPU profile. + pub(in crate::x86_64) hypervisor: HypervisorType, + /// The vendor of the CPU belonging to the host that generated this CPU profile. + pub(in crate::x86_64) cpu_vendor: CpuVendor, + /// Adjustments necessary to become compatible with the desired target. + pub(in crate::x86_64) adjustments: Vec<(Parameters, CpuidOutputRegisterAdjustments)>, +} + +/* TODO: The [`CpuProfile`] struct will likely need a few more iterations. The following +section should explain why: + +# MSR restrictions + +CPU profiles also need to restrict which MSRs may be manipulated by the guest as various physical CPUs +can have differing supported MSRs. + +The CPU profile will thus necessarily need to contain some data related to MSR restrictions. That will +be taken care of in a follow up MR. + +*/ + +/// Used for adjusting an entire cpuid output register (EAX, EBX, ECX or EDX) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub(super) struct CpuidOutputRegisterAdjustments { + #[serde(serialize_with = "serialize_as_hex")] + #[serde(deserialize_with = "deserialize_from_hex")] + pub(in crate::x86_64) replacements: u32, + /// Used to zero out the area `replacements` occupy. This mask is not necessarily !replacements, as replacements may pack values of different types (i.e. it is wrong to think of it as a bitset conceptually speaking). + #[serde(serialize_with = "serialize_as_hex")] + #[serde(deserialize_with = "deserialize_from_hex")] + pub(in crate::x86_64) mask: u32, +} +impl CpuidOutputRegisterAdjustments { + pub(in crate::x86_64) fn adjust(self, cpuid_output_register: &mut u32) { + let temp_register_copy = *cpuid_output_register; + let replacements_area_masked_in_temp_copy = temp_register_copy & self.mask; + *cpuid_output_register = replacements_area_masked_in_temp_copy | self.replacements; + } + + pub(in crate::x86_64) fn adjust_cpuid_entries( + mut cpuid: Vec, + adjustments: &[(Parameters, Self)], + ) -> Result, MissingCpuidEntriesError> { + for entry in &mut cpuid { + for (reg, reg_value) in [ + (CpuidReg::EAX, &mut entry.eax), + (CpuidReg::EBX, &mut entry.ebx), + (CpuidReg::ECX, &mut entry.ecx), + (CpuidReg::EDX, &mut entry.edx), + ] { + // Get the adjustment corresponding to the entry's function/leaf and index/sub-leaf for each of the register. If no such + // adjustment is found we use the trivial adjustment (leading to the register being zeroed out entirely). + let adjustment = adjustments + .iter() + .find_map(|(param, adjustment)| { + ((param.leaf == entry.function) + & param.sub_leaf.contains(&entry.index) + & (param.register == reg)) + .then_some(*adjustment) + }) + .unwrap_or(CpuidOutputRegisterAdjustments { + mask: 0, + replacements: 0, + }); + adjustment.adjust(reg_value); + } + } + + Self::expected_entries_found(&cpuid, adjustments).map(|_| cpuid) + } + + /// Check that we found every value that was supposed to be replaced with something else than 0 + /// + /// IMPORTANT: This function assumes that the given `cpuid` has already been adjusted with the + /// provided `adjustments`. + fn expected_entries_found( + cpuid: &[CpuIdEntry], + adjustments: &[(Parameters, Self)], + ) -> Result<(), MissingCpuidEntriesError> { + let mut missing_entry = false; + + // Invalid state components can be ignored. The next few lines obtain the relevant entries to + // check for this. + let eax_0xd_0 = cpuid + .iter() + .find(|entry| (entry.function == 0xd) && (entry.index == 0)) + .map(|entry| entry.eax) + .unwrap_or(0); + let ecx_0xd_1 = cpuid + .iter() + .find(|entry| (entry.function == 0xd) && (entry.index == 1)) + .map(|entry| entry.ecx) + .unwrap_or(0); + + let edx_0xd_0 = cpuid + .iter() + .find(|entry| (entry.function == 0xd) && (entry.index == 0)) + .map(|entry| entry.edx) + .unwrap_or(0); + let edx_0xd_1 = cpuid + .iter() + .find(|entry| (entry.function == 0xd) && (entry.index == 1)) + .map(|entry| entry.edx) + .unwrap_or(0); + + for (param, adjustment) in adjustments { + if adjustment.replacements == 0 { + continue; + } + let sub_start = *param.sub_leaf.start(); + let sub_end = *param.sub_leaf.end(); + + let can_skip_lo = if (param.leaf == 0xd) && (2..32).contains(&sub_start) { + let start = sub_start; + let end = std::cmp::min(sub_end, 31); + let mask = (start..=end).fold(0, |acc, next| acc | (1 << next)); + ((mask & eax_0xd_0) == 0) & ((mask & ecx_0xd_1) == 0) + } else { + false + }; + + let can_skip_hi = if (param.leaf == 0xd) && (32..64).contains(&sub_end) { + let start = std::cmp::max(32, sub_start); + let end = sub_end; + let mask = (start..=end) + .map(|val| val - 32) + .fold(0, |acc, next| acc | (1 << next)); + ((mask & edx_0xd_0) == 0) & ((mask & edx_0xd_1) == 0) + } else { + false + }; + + if can_skip_lo && can_skip_hi { + // This means that all state components referred to by the specified sub-leaf range are not valid + // and may be skipped. + continue; + } + if !cpuid.iter().any(|entry| { + (entry.function == param.leaf) && (param.sub_leaf.contains(&entry.index)) + }) { + error!( + "cannot adjust CPU profile. No entry found matching the required parameters: {:?}", + param + ); + missing_entry = true; + } + } + if missing_entry { + Err(MissingCpuidEntriesError) + } else { + Ok(()) + } + } +} + +#[derive(Debug, Error)] +#[error("Required CPUID entries not found")] +pub(in crate::x86_64) struct MissingCpuidEntriesError; diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 7edb0d03ab..c8d7d49f2a 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -7,6 +7,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-BSD-3-Clause file. use std::sync::Arc; +pub mod cpu_profile; pub mod cpuid_definitions; pub mod interrupts; pub mod layout; From 1ceda9d79b351951ffd43e91696e3df6262a4d1d Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 7 Oct 2025 05:34:22 +0200 Subject: [PATCH 6/8] misc: Make CPU profile part of various configs We integrate the CPU profile into the various configs that ultimately get set by the user. This quickly ends up involving multiple files, luckily Rust helps us find which ones via compilation errors. Signed-Off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/src/x86_64/mod.rs | 3 ++- src/main.rs | 1 + vmm/src/config.rs | 9 +++++++++ vmm/src/cpu.rs | 1 + vmm/src/lib.rs | 21 +++++++++++++++++---- vmm/src/vm.rs | 15 +++++++++------ vmm/src/vm_config.rs | 4 ++++ 7 files changed, 43 insertions(+), 11 deletions(-) diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index c8d7d49f2a..7ee535472d 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -29,7 +29,7 @@ use vm_memory::{ GuestMemoryRegion, }; -use crate::{GuestMemoryMmap, InitramfsConfig, RegionType}; +use crate::{CpuProfile, GuestMemoryMmap, InitramfsConfig, RegionType}; mod smbios; use std::arch::x86_64; #[cfg(feature = "tdx")] @@ -87,6 +87,7 @@ pub struct CpuidConfig { #[cfg(feature = "tdx")] pub tdx: bool, pub amx: bool, + pub profile: CpuProfile, } #[derive(Debug, Error)] diff --git a/src/main.rs b/src/main.rs index 87a13805a9..9436b3e160 100644 --- a/src/main.rs +++ b/src/main.rs @@ -961,6 +961,7 @@ mod unit_tests { max_phys_bits: 46, affinity: None, features: CpuFeatures::default(), + profile: Default::default(), }, memory: MemoryConfig { size: 536_870_912, diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 2ca2505814..815ad7a7ea 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -11,6 +11,7 @@ use std::path::PathBuf; use std::result; use std::str::FromStr; +use arch::CpuProfile; use clap::ArgMatches; use option_parser::{ ByteSized, IntegerList, OptionParser, OptionParserError, StringList, Toggle, Tuple, @@ -600,6 +601,7 @@ impl CpusConfig { .add("kvm_hyperv") .add("max_phys_bits") .add("affinity") + .add("profile") .add("features"); parser.parse(cpus).map_err(Error::ParseCpus)?; @@ -632,6 +634,12 @@ impl CpusConfig { }) .collect() }); + + let profile = parser + .convert::("profile") + .map_err(Error::ParseCpus)? + .unwrap_or_default(); + let features_list = parser .convert::("features") .map_err(Error::ParseCpus)? @@ -663,6 +671,7 @@ impl CpusConfig { max_phys_bits, affinity, features, + profile, }) } } diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index ebdfbf478c..416bce5d45 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -812,6 +812,7 @@ impl CpuManager { #[cfg(feature = "tdx")] tdx, amx: self.config.features.amx, + profile: self.config.profile, }, ) .map_err(Error::CommonCpuId)? diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 7497d3cc2d..3d92c74a8c 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -2224,17 +2224,26 @@ impl Vmm { ))); }; - let amx = vm_config.lock().unwrap().cpus.features.amx; - let phys_bits = - vm::physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits); + let (amx, phys_bits, profile, kvm_hyperv) = { + let guard = vm_config.lock().unwrap(); + let amx = guard.cpus.features.amx; + let max_phys_bits = guard.cpus.max_phys_bits; + let profile = guard.cpus.profile; + let kvm_hyperv = guard.cpus.kvm_hyperv; + // Drop lock before function call + core::mem::drop(guard); + let phys_bits = vm::physical_bits(&hypervisor, max_phys_bits); + (amx, phys_bits, profile, kvm_hyperv) + }; arch::generate_common_cpuid( &hypervisor, &arch::CpuidConfig { phys_bits, - kvm_hyperv: vm_config.lock().unwrap().cpus.kvm_hyperv, + kvm_hyperv, #[cfg(feature = "tdx")] tdx: false, amx, + profile, }, ) .map_err(|e| { @@ -2373,6 +2382,7 @@ impl Vmm { #[cfg(feature = "tdx")] tdx: false, amx: vm_config.cpus.features.amx, + profile: vm_config.cpus.profile, }, ) .map_err(|e| { @@ -3500,6 +3510,8 @@ const DEVICE_MANAGER_SNAPSHOT_ID: &str = "device-manager"; #[cfg(test)] mod unit_tests { + use arch::CpuProfile; + use super::*; #[cfg(target_arch = "x86_64")] use crate::vm_config::DebugConsoleConfig; @@ -3533,6 +3545,7 @@ mod unit_tests { max_phys_bits: 46, affinity: None, features: CpuFeatures::default(), + profile: CpuProfile::default(), }, memory: MemoryConfig { size: 536_870_912, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index a776d0d943..aa981e226b 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -2893,19 +2893,22 @@ impl Snapshottable for Vm { #[cfg(all(feature = "kvm", target_arch = "x86_64"))] let common_cpuid = { - let amx = self.config.lock().unwrap().cpus.features.amx; - let phys_bits = physical_bits( - &self.hypervisor, - self.config.lock().unwrap().cpus.max_phys_bits, - ); + let guard = self.config.lock().unwrap(); + let amx = guard.cpus.features.amx; + let phys_bits = physical_bits(&self.hypervisor, guard.cpus.max_phys_bits); + let kvm_hyperv = guard.cpus.kvm_hyperv; + let profile = guard.cpus.profile; + // Drop the guard before function call + core::mem::drop(guard); arch::generate_common_cpuid( &self.hypervisor, &arch::CpuidConfig { phys_bits, - kvm_hyperv: self.config.lock().unwrap().cpus.kvm_hyperv, + kvm_hyperv, #[cfg(feature = "tdx")] tdx: false, amx, + profile, }, ) .map_err(|e| { diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index 45bd382b9c..7238a7ca23 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -8,6 +8,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fs, result}; +use arch::CpuProfile; use net_util::MacAddr; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -68,6 +69,8 @@ pub struct CpusConfig { pub affinity: Option>, #[serde(default)] pub features: CpuFeatures, + #[serde(default)] + pub profile: CpuProfile, } pub const DEFAULT_VCPUS: u32 = 1; @@ -82,6 +85,7 @@ impl Default for CpusConfig { max_phys_bits: DEFAULT_MAX_PHYS_BITS, affinity: None, features: CpuFeatures::default(), + profile: CpuProfile::default(), } } } From 73f219898e70ec5efd1bbdc6e21bdaecd1f1dd22 Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 16:57:31 +0100 Subject: [PATCH 7/8] arch: Apply CPU profile (if any) when generating common CPUID If a CPU profile is configured it should result in guests seeing a restricted subset of CPUID. This is what we finally achieve in this commit. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/src/x86_64/cpu_profile.rs | 2 +- arch/src/x86_64/mod.rs | 356 ++++++++++++++++++++------------- 2 files changed, 221 insertions(+), 137 deletions(-) diff --git a/arch/src/x86_64/cpu_profile.rs b/arch/src/x86_64/cpu_profile.rs index bf5d90f061..47237d720f 100644 --- a/arch/src/x86_64/cpu_profile.rs +++ b/arch/src/x86_64/cpu_profile.rs @@ -243,4 +243,4 @@ impl CpuidOutputRegisterAdjustments { #[derive(Debug, Error)] #[error("Required CPUID entries not found")] -pub(in crate::x86_64) struct MissingCpuidEntriesError; +pub struct MissingCpuidEntriesError; diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 7ee535472d..92822eec20 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -29,6 +29,7 @@ use vm_memory::{ GuestMemoryRegion, }; +use crate::x86_64::cpu_profile::CpuidOutputRegisterAdjustments; use crate::{CpuProfile, GuestMemoryMmap, InitramfsConfig, RegionType}; mod smbios; use std::arch::x86_64; @@ -128,6 +129,26 @@ pub enum Error { #[error("Error getting supported CPUID through the hypervisor API")] CpuidGetSupported(#[source] HypervisorError), + #[error( + "The selected CPU profile cannot be utilized because the host's CPUID entries are not compatible with the profile" + )] + CpuProfileCpuidIncompatibility, + /// Error because TDX cannot be enabled when a custom (non host) CPU profile has been selected + #[error("TDX cannot be enabled when a custom CPU profile has been selected")] + CpuProfileTdxIncompatibility, + #[error( + "The selected CPU profile cannot be utilized because a necessary CPUID entry was not found" + )] + /// Error when trying to apply a CPU profile because a necessary CPUID entry was not found + MissingExpectedCpuidEntry(#[source] cpu_profile::MissingCpuidEntriesError), + /// Error when trying to apply a CPU profile because the host has a CPU from a different vendor + #[error( + "The selected CPU profile cannot be utilized because the host has a CPU from a different vendor" + )] + CpuProfileVendorIncompatibility { + cpu_vendor_profile: CpuVendor, + cpu_vendor_host: CpuVendor, + }, /// Error populating CPUID with KVM HyperV emulation details #[error("Error populating CPUID with KVM HyperV emulation details")] CpuidKvmHyperV(#[source] vmm_sys_util::fam::Error), @@ -283,7 +304,7 @@ impl CpuidPatch { } } - pub fn patch_cpuid(cpuid: &mut [CpuIdEntry], patches: Vec) { + pub fn patch_cpuid(cpuid: &mut [CpuIdEntry], patches: &[CpuidPatch]) { for entry in cpuid { for patch in patches.iter() { if entry.function == patch.function && entry.index == patch.index { @@ -550,10 +571,15 @@ impl CpuidFeatureEntry { } } +/// This function generates the CPUID entries to be set for all CPUs. +/// +/// If the `config` has a CPU profile set (other than host) then the profile +/// will be applied pub fn generate_common_cpuid( hypervisor: &Arc, config: &CpuidConfig, ) -> super::Result> { + info!("calling generate_common_cpuid"); // SAFETY: cpuid called with valid leaves if unsafe { x86_64::__cpuid(1) }.ecx & (1 << HYPERVISOR_ECX_BIT) == 1 << HYPERVISOR_ECX_BIT { // SAFETY: cpuid called with valid leaves @@ -615,167 +641,225 @@ pub fn generate_common_cpuid( }); } - // Supported CPUID - let mut cpuid = hypervisor + // Supported CPUID according to the host and hypervisor + let mut host_cpuid = hypervisor .get_supported_cpuid() .map_err(Error::CpuidGetSupported)?; - CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches); + // Copy CPU identification string + // + // If a CPU profile has been applied then this will get + // overwritten as soon as the profile is applied + for i in 0x8000_0002..=0x8000_0004 { + host_cpuid.retain(|c| c.function != i); + // SAFETY: call cpuid with valid leaves + let leaf = unsafe { std::arch::x86_64::__cpuid(i) }; + host_cpuid.push(CpuIdEntry { + function: i, + eax: leaf.eax, + ebx: leaf.ebx, + ecx: leaf.ecx, + edx: leaf.edx, + ..Default::default() + }); + } - #[cfg(feature = "tdx")] - let tdx_capabilities = if config.tdx { - let caps = hypervisor - .tdx_capabilities() - .map_err(Error::TdxCapabilities)?; - info!("TDX capabilities {:#?}", caps); - Some(caps) - } else { - None + let use_custom_profile = config.profile != CpuProfile::Host; + // Obtain cpuid entries that are adjusted to the specified CPU profile and the cpuid entries of the compatibility target + // TODO: Try to write this in a clearer way + let (host_adjusted_to_profile, profile_cpu_vendor) = { + config + .profile + .data(config.amx) + .map(|profile_data| { + ( + CpuidOutputRegisterAdjustments::adjust_cpuid_entries( + host_cpuid.clone(), + &profile_data.adjustments, + ) + .map(Some), + Some(profile_data.cpu_vendor), + ) + }) + .unwrap_or((Ok(None), None)) }; + let mut host_adjusted_to_profile = + host_adjusted_to_profile.map_err(Error::MissingExpectedCpuidEntry)?; + + // There should be relatively few cases where live migration can succeed between hosts from different + // CPU vendors and making our checks account for that possibility would complicate things substantially. + // We thus require that the host's cpu vendor matches the one used to generate the CPU profile. + if let Some(cpu_vendor_profile) = profile_cpu_vendor + && let cpu_vendor_host = hypervisor.get_cpu_vendor() + && cpu_vendor_profile != cpu_vendor_host + { + return Err(Error::CpuProfileVendorIncompatibility { + cpu_vendor_profile, + cpu_vendor_host, + } + .into()); + } + // We now make the modifications according to the config parameters to each of the cpuid entries + // declared above and then perform a compatibility check. + for cpuid_optiion in [Some(&mut host_cpuid), host_adjusted_to_profile.as_mut()] { + let Some(cpuid) = cpuid_optiion else { + break; + }; + CpuidPatch::patch_cpuid(cpuid, &cpuid_patches); - // Update some existing CPUID - for entry in cpuid.as_mut_slice().iter_mut() { - match entry.function { - // Clear AMX related bits if the AMX feature is not enabled - 0x7 => { - if !config.amx && entry.index == 0 { - entry.edx &= !((1 << AMX_BF16) | (1 << AMX_TILE) | (1 << AMX_INT8)) - } + #[cfg(feature = "tdx")] + let tdx_capabilities = if config.tdx { + if use_custom_profile { + return Err(Error::CpuProfileTdxIncompatibility.into()); } - 0xd => - { - #[cfg(feature = "tdx")] - if let Some(caps) = &tdx_capabilities { - let xcr0_mask: u64 = 0x82ff; - let xss_mask: u64 = !xcr0_mask; - if entry.index == 0 { - entry.eax &= (caps.xfam_fixed0 as u32) & (xcr0_mask as u32); - entry.eax |= (caps.xfam_fixed1 as u32) & (xcr0_mask as u32); - entry.edx &= ((caps.xfam_fixed0 & xcr0_mask) >> 32) as u32; - entry.edx |= ((caps.xfam_fixed1 & xcr0_mask) >> 32) as u32; - } else if entry.index == 1 { - entry.ecx &= (caps.xfam_fixed0 as u32) & (xss_mask as u32); - entry.ecx |= (caps.xfam_fixed1 as u32) & (xss_mask as u32); - entry.edx &= ((caps.xfam_fixed0 & xss_mask) >> 32) as u32; - entry.edx |= ((caps.xfam_fixed1 & xss_mask) >> 32) as u32; + let caps = hypervisor + .tdx_capabilities() + .map_err(Error::TdxCapabilities)?; + info!("TDX capabilities {:#?}", caps); + Some(caps) + } else { + None + }; + + // Update some existing CPUID + for entry in cpuid.as_mut_slice().iter_mut() { + match entry.function { + // Clear AMX related bits if the AMX feature is not enabled + 0x7 => { + if !config.amx && entry.index == 0 { + entry.edx &= !((1 << AMX_BF16) | (1 << AMX_TILE) | (1 << AMX_INT8)) } } - } - // Copy host L1 cache details if not populated by KVM - 0x8000_0005 => { - if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 { - // SAFETY: cpuid called with valid leaves - if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0005 { + 0xd => + { + #[cfg(feature = "tdx")] + if let Some(caps) = &tdx_capabilities { + let xcr0_mask: u64 = 0x82ff; + let xss_mask: u64 = !xcr0_mask; + if entry.index == 0 { + entry.eax &= (caps.xfam_fixed0 as u32) & (xcr0_mask as u32); + entry.eax |= (caps.xfam_fixed1 as u32) & (xcr0_mask as u32); + entry.edx &= ((caps.xfam_fixed0 & xcr0_mask) >> 32) as u32; + entry.edx |= ((caps.xfam_fixed1 & xcr0_mask) >> 32) as u32; + } else if entry.index == 1 { + entry.ecx &= (caps.xfam_fixed0 as u32) & (xss_mask as u32); + entry.ecx |= (caps.xfam_fixed1 as u32) & (xss_mask as u32); + entry.edx &= ((caps.xfam_fixed0 & xss_mask) >> 32) as u32; + entry.edx |= ((caps.xfam_fixed1 & xss_mask) >> 32) as u32; + } + } + } + // Copy host L1 cache details if not populated by KVM + 0x8000_0005 => { + if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 { // SAFETY: cpuid called with valid leaves - let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0005) }; - entry.eax = leaf.eax; - entry.ebx = leaf.ebx; - entry.ecx = leaf.ecx; - entry.edx = leaf.edx; + if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0005 { + // SAFETY: cpuid called with valid leaves + let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0005) }; + entry.eax = leaf.eax; + entry.ebx = leaf.ebx; + entry.ecx = leaf.ecx; + entry.edx = leaf.edx; + } } } - } - // Copy host L2 cache details if not populated by KVM - 0x8000_0006 => { - if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 { - // SAFETY: cpuid called with valid leaves - if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0006 { + // Copy host L2 cache details if not populated by KVM + 0x8000_0006 => { + if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 { // SAFETY: cpuid called with valid leaves - let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0006) }; - entry.eax = leaf.eax; - entry.ebx = leaf.ebx; - entry.ecx = leaf.ecx; - entry.edx = leaf.edx; + if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0006 { + // SAFETY: cpuid called with valid leaves + let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0006) }; + entry.eax = leaf.eax; + entry.ebx = leaf.ebx; + entry.ecx = leaf.ecx; + entry.edx = leaf.edx; + } } } - } - // Set CPU physical bits - 0x8000_0008 => { - entry.eax = (entry.eax & 0xffff_ff00) | (config.phys_bits as u32 & 0xff); - } - 0x4000_0001 => { - // Enable KVM_FEATURE_MSI_EXT_DEST_ID. This allows the guest to target - // device interrupts to cpus with APIC IDs > 254 without interrupt remapping. - entry.eax |= 1 << KVM_FEATURE_MSI_EXT_DEST_ID; - - // These features are not supported by TDX - #[cfg(feature = "tdx")] - if config.tdx { - entry.eax &= !((1 << KVM_FEATURE_CLOCKSOURCE_BIT) - | (1 << KVM_FEATURE_CLOCKSOURCE2_BIT) - | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) - | (1 << KVM_FEATURE_ASYNC_PF_BIT) - | (1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT) - | (1 << KVM_FEATURE_STEAL_TIME_BIT)) + // Set CPU physical bits + 0x8000_0008 => { + entry.eax = (entry.eax & 0xffff_ff00) | (config.phys_bits as u32 & 0xff); + } + 0x4000_0001 => { + // Enable KVM_FEATURE_MSI_EXT_DEST_ID. This allows the guest to target + // device interrupts to cpus with APIC IDs > 254 without interrupt remapping. + entry.eax |= 1 << KVM_FEATURE_MSI_EXT_DEST_ID; + + // These features are not supported by TDX + #[cfg(feature = "tdx")] + if config.tdx { + entry.eax &= !((1 << KVM_FEATURE_CLOCKSOURCE_BIT) + | (1 << KVM_FEATURE_CLOCKSOURCE2_BIT) + | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) + | (1 << KVM_FEATURE_ASYNC_PF_BIT) + | (1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT) + | (1 << KVM_FEATURE_STEAL_TIME_BIT)) + } } + _ => {} } - _ => {} } - } - // Copy CPU identification string - for i in 0x8000_0002..=0x8000_0004 { - cpuid.retain(|c| c.function != i); - // SAFETY: call cpuid with valid leaves - let leaf = unsafe { std::arch::x86_64::__cpuid(i) }; - cpuid.push(CpuIdEntry { - function: i, - eax: leaf.eax, - ebx: leaf.ebx, - ecx: leaf.ecx, - edx: leaf.edx, - ..Default::default() - }); - } - - if config.kvm_hyperv { - // Remove conflicting entries - cpuid.retain(|c| c.function != 0x4000_0000); - cpuid.retain(|c| c.function != 0x4000_0001); - // See "Hypervisor Top Level Functional Specification" for details - // Compliance with "Hv#1" requires leaves up to 0x4000_000a - cpuid.push(CpuIdEntry { - function: 0x40000000, - eax: 0x4000000a, // Maximum cpuid leaf - ebx: 0x756e694c, // "Linu" - ecx: 0x564b2078, // "x KV" - edx: 0x7648204d, // "M Hv" - ..Default::default() - }); - cpuid.push(CpuIdEntry { - function: 0x40000001, - eax: 0x31237648, // "Hv#1" - ..Default::default() - }); - cpuid.push(CpuIdEntry { - function: 0x40000002, - eax: 0x3839, // "Build number" - ebx: 0xa0000, // "Version" - ..Default::default() - }); - cpuid.push(CpuIdEntry { - function: 0x4000_0003, - eax: (1 << 1) // AccessPartitionReferenceCounter + if config.kvm_hyperv { + // Remove conflicting entries + cpuid.retain(|c| c.function != 0x4000_0000); + cpuid.retain(|c| c.function != 0x4000_0001); + // See "Hypervisor Top Level Functional Specification" for details + // Compliance with "Hv#1" requires leaves up to 0x4000_000a + cpuid.push(CpuIdEntry { + function: 0x40000000, + eax: 0x4000000a, // Maximum cpuid leaf + ebx: 0x756e694c, // "Linu" + ecx: 0x564b2078, // "x KV" + edx: 0x7648204d, // "M Hv" + ..Default::default() + }); + cpuid.push(CpuIdEntry { + function: 0x40000001, + eax: 0x31237648, // "Hv#1" + ..Default::default() + }); + cpuid.push(CpuIdEntry { + function: 0x40000002, + eax: 0x3839, // "Build number" + ebx: 0xa0000, // "Version" + ..Default::default() + }); + cpuid.push(CpuIdEntry { + function: 0x4000_0003, + eax: (1 << 1) // AccessPartitionReferenceCounter | (1 << 2) // AccessSynicRegs | (1 << 3) // AccessSyntheticTimerRegs | (1 << 9), // AccessPartitionReferenceTsc - edx: 1 << 3, // CPU dynamic partitioning - ..Default::default() - }); - cpuid.push(CpuIdEntry { - function: 0x4000_0004, - eax: 1 << 5, // Recommend relaxed timing - ..Default::default() - }); - for i in 0x4000_0005..=0x4000_000a { + edx: 1 << 3, // CPU dynamic partitioning + ..Default::default() + }); cpuid.push(CpuIdEntry { - function: i, + function: 0x4000_0004, + eax: 1 << 5, // Recommend relaxed timing ..Default::default() }); + for i in 0x4000_0005..=0x4000_000a { + cpuid.push(CpuIdEntry { + function: i, + ..Default::default() + }); + } } } - - Ok(cpuid) + if !use_custom_profile { + Ok(host_cpuid) + } else { + // Final compatibility checks to ensure that the CPUID values we return are compatible both with the CPU profile and the host we are currently running on. + let host_adjusted_to_profile = host_adjusted_to_profile.expect("The profile adjusted cpuid entries should exist as we checked that we have a custom CPU profile"); + + // Check that the host's cpuid is indeed compatible with the adjusted profile. This is not by construction. + info!("checking compatibility between host adjusted to profile and the host itself"); + CpuidFeatureEntry::check_cpuid_compatibility(&host_adjusted_to_profile, &host_cpuid) + .map_err(|_| Error::CpuProfileCpuidIncompatibility)?; + Ok(host_adjusted_to_profile) + } } pub fn configure_vcpu( @@ -1419,7 +1503,7 @@ fn update_cpuid_topology( edx_bit: Some(28), }, ]; - CpuidPatch::patch_cpuid(cpuid, cpuid_patches); + CpuidPatch::patch_cpuid(cpuid, &cpuid_patches); CpuidPatch::set_cpuid_reg( cpuid, 0x8000_0008, From 1b943188d6c46904eb86d5f5a919f083f5d9c2a8 Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 9 Dec 2025 17:21:01 +0100 Subject: [PATCH 8/8] arch: Include Skylake and Sapphire rapids CPU profiles We include CPU profiles corresponding to Intel Skylake and Sapphire rapids server that we generated using our WIP CPU profile generation tool. Signed-of-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/Cargo.toml | 2 + arch/src/x86_64/cpu_profile.rs | 22 +- .../x86_64/cpu_profiles/sapphire-rapids.json | 3016 +++++++++++++++++ arch/src/x86_64/cpu_profiles/skylake.json | 2848 ++++++++++++++++ 4 files changed, 5883 insertions(+), 5 deletions(-) create mode 100644 arch/src/x86_64/cpu_profiles/sapphire-rapids.json create mode 100644 arch/src/x86_64/cpu_profiles/skylake.json diff --git a/arch/Cargo.toml b/arch/Cargo.toml index 3e82367707..5cc8b0fd71 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -19,6 +19,8 @@ libc = { workspace = true } linux-loader = { workspace = true, features = ["bzimage", "elf", "pe"] } log = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } +# We currently use this for (de-)serializing CPU profile data +serde_json = { workspace = true } thiserror = { workspace = true } uuid = { workspace = true } vm-memory = { workspace = true, features = ["backend-bitmap", "backend-mmap"] } diff --git a/arch/src/x86_64/cpu_profile.rs b/arch/src/x86_64/cpu_profile.rs index 47237d720f..36c8a62e2d 100644 --- a/arch/src/x86_64/cpu_profile.rs +++ b/arch/src/x86_64/cpu_profile.rs @@ -18,7 +18,9 @@ use crate::x86_64::cpuid_definitions::{Parameters, deserialize_from_hex, seriali pub enum CpuProfile { #[default] Host, + #[cfg(feature = "kvm")] Skylake, + #[cfg(feature = "kvm")] SapphireRapids, } @@ -35,16 +37,26 @@ impl CpuProfile { pub(in crate::x86_64) fn data(&self, amx: bool) -> Option { let mut data: CpuProfileData = match self { Self::Host => None, - Self::Skylake => todo!(), - Self::SapphireRapids => todo!(), + Self::Skylake => Some( + serde_json::from_slice(include_bytes!("cpu_profiles/skylake.json")) + .inspect_err(|e| { + error!("BUG: could not deserialize CPU profile. Got error: {:?}", e) + }) + .expect("should be able to deserialize pre-generated data"), + ), + Self::SapphireRapids => Some( + serde_json::from_slice(include_bytes!("cpu_profiles/sapphire-rapids.json")) + .inspect_err(|e| { + error!("BUG: could not deserialize CPU profile. Got error: {:?}", e) + }) + .expect("should be able to deserialize pre-generated data"), + ), }?; if !amx { // In this case we will need to wipe out the AMX tile state components (if they are included in the profile) for adj in data.adjustments.iter_mut() { if adj.0.sub_leaf.start() != adj.0.sub_leaf.end() { - // The generated profiles produce as many sub-leaf entries as possible, and only use ranges for - // values not found. continue; } let sub_leaf = *adj.0.sub_leaf.start(); @@ -73,7 +85,7 @@ impl CpuProfile { } // This will need to be addressed before upstreaming. // We will probably need one profile per hypervisor. - unimplemented!() + unreachable!() } } diff --git a/arch/src/x86_64/cpu_profiles/sapphire-rapids.json b/arch/src/x86_64/cpu_profiles/sapphire-rapids.json new file mode 100644 index 0000000000..c37a7648e7 --- /dev/null +++ b/arch/src/x86_64/cpu_profiles/sapphire-rapids.json @@ -0,0 +1,3016 @@ +{ + "hypervisor": "Kvm", + "cpu_vendor": "Intel", + "adjustments": [ + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000020", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x756e6547", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x6c65746e", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x49656e69", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x000806f8", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ff00" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x76fa3223", + "mask": "0x80000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x078bfbff", + "mask": "0x08000000" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000004", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000002", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0xf1bf07ab", + "mask": "0x00002040" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x1b415f6e", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0xa7c04010", + "mask": "0x18000400" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00001c30", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000017", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000009", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x000602e7", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x0000001f", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000100", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000240", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 4 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 4 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 4 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000040", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "EAX" + }, + { + "replacements": "0x00000200", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "EAX" + }, + { + "replacements": "0x00000400", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "EAX" + }, + { + "replacements": "0x00000008", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 16 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 17, + "end": 17 + }, + "register": "EAX" + }, + { + "replacements": "0x00000040", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 18, + "end": 18 + }, + "register": "EAX" + }, + { + "replacements": "0x00002000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 19, + "end": 63 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EBX" + }, + { + "replacements": "0x00000440", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "EBX" + }, + { + "replacements": "0x00000480", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "EBX" + }, + { + "replacements": "0x00000680", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "EBX" + }, + { + "replacements": "0x00000a80", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 16 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 17, + "end": 17 + }, + "register": "EBX" + }, + { + "replacements": "0x00000ac0", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 18, + "end": 18 + }, + "register": "EBX" + }, + { + "replacements": "0x00000b00", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 19, + "end": 63 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 16 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 17, + "end": 17 + }, + "register": "ECX" + }, + { + "replacements": "0x00000002", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 18, + "end": 18 + }, + "register": "ECX" + }, + { + "replacements": "0x00000006", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 19, + "end": 63 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000017", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffff070f" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffff070f" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x03ffc1ff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x03ffc1ff" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000001", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x04002000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00080040", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000010", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00004010", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000020", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000020", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000024", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000024", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x80000008", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0fff3fff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xf000ffff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000121", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x2c100800", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x65746e49", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x6153206c", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x69687070", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x72206572", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x64697061", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000073", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000100", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000008", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00ffffff" + } + ], + [ + { + "leaf": "0x80000008", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0103feff" + } + ], + [ + { + "leaf": "0x40000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000001" + } + ] + ] +} \ No newline at end of file diff --git a/arch/src/x86_64/cpu_profiles/skylake.json b/arch/src/x86_64/cpu_profiles/skylake.json new file mode 100644 index 0000000000..0e17aeb7b9 --- /dev/null +++ b/arch/src/x86_64/cpu_profiles/skylake.json @@ -0,0 +1,2848 @@ +{ + "hypervisor": "Kvm", + "cpu_vendor": "Intel", + "adjustments": [ + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000016", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x756e6547", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x6c65746e", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x49656e69", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00050654", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ff00" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x76fa3223", + "mask": "0x80000000" + } + ], + [ + { + "leaf": "0x00000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x078bfbff", + "mask": "0x08000000" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffc3ff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x7fffffff" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000004", + "sub_leaf": { + "start": 5, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000007" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000005", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000004", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0xd19f07ab", + "mask": "0x00002040" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x0000000c", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0xa4000000", + "mask": "0x18000400" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000007", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000009", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000a", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000b", + "sub_leaf": { + "start": 1, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x000002e7", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x0000000f", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000100", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000240", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000040", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "EAX" + }, + { + "replacements": "0x00000200", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "EAX" + }, + { + "replacements": "0x00000400", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "EAX" + }, + { + "replacements": "0x00000008", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 63 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EBX" + }, + { + "replacements": "0x00000440", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "EBX" + }, + { + "replacements": "0x00000480", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "EBX" + }, + { + "replacements": "0x00000680", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "EBX" + }, + { + "replacements": "0x00000a80", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 63 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 6, + "end": 6 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 7, + "end": 7 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 8, + "end": 8 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 9, + "end": 9 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000d", + "sub_leaf": { + "start": 10, + "end": 63 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000000f", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000010", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000014", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000015", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000016", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x00000017", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffff070f" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000018", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x03ffc1ff" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001c", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001d", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001e", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000001f" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x0000ffff" + } + ], + [ + { + "leaf": "0x0000001f", + "sub_leaf": { + "start": 0, + "end": 4294967295 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x00000020", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000020", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000021", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 1, + "end": 1 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 2, + "end": 2 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 3, + "end": 3 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 4, + "end": 4 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000023", + "sub_leaf": { + "start": 5, + "end": 5 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000024", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x00000024", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x80000008", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0fff3fff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xf000ffff" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000121", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x2c100800", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x65746e49", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x6b53206c", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x6b616c79", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000002", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000065", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000003", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000004", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000006", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x80000007", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000100", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x80000008", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x00ffffff" + } + ], + [ + { + "leaf": "0x80000008", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000000" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EBX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "ECX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000000", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0xffffffff" + } + ], + [ + { + "leaf": "0x40000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EAX" + }, + { + "replacements": "0x00000000", + "mask": "0x0103feff" + } + ], + [ + { + "leaf": "0x40000001", + "sub_leaf": { + "start": 0, + "end": 0 + }, + "register": "EDX" + }, + { + "replacements": "0x00000000", + "mask": "0x00000001" + } + ] + ] +} \ No newline at end of file