aboutsummaryrefslogtreecommitdiff
path: root/src/long_mode/isa_settings.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-08-16 21:21:16 -0700
committeriximeow <me@iximeow.net>2025-06-01 09:21:37 +0000
commit08eed360fea81ab9328fd0859b813ee01937b5b1 (patch)
treec379847e969d479c13c29f46864465cf2969d9cb /src/long_mode/isa_settings.rs
parent681262f4472ba4f452446e86012ce629b849d8d9 (diff)
expand isa feature selection to more bits
this is backed by the new IsaSettings trait. the existing InstDecoders are unchanged, except that they implement this new trait. also add new `DecodeEverything` structs with `IsaSettings` impls that are unconditionally set to permit anything the decoder can be configured to conditionally accept or reject. in the process, add new `_3dnow` flag and stop accepting 3dnow instructions in uarch-specific decoder settings that would not have 3dnow instructions. update AMD microarchitectures and cross-ref chip directory
Diffstat (limited to 'src/long_mode/isa_settings.rs')
-rw-r--r--src/long_mode/isa_settings.rs977
1 files changed, 977 insertions, 0 deletions
diff --git a/src/long_mode/isa_settings.rs b/src/long_mode/isa_settings.rs
new file mode 100644
index 0000000..de3d6e7
--- /dev/null
+++ b/src/long_mode/isa_settings.rs
@@ -0,0 +1,977 @@
+use super::{BMI1, BMI2, DecodeError, DecodeEverything, InstDecoder, Instruction, Opcode};
+
+macro_rules! gen_isa_settings {
+ (
+ $(
+ $(#[$doc:meta])*
+ $feature:ident,
+ $(#[$set_doc:item])*
+ $set_feature:ident = $idx:expr;
+ )+
+
+ {
+ $(
+ $(#[$composite_doc:meta])*
+ $composite_feature:ident = {
+ $first_inner_feature:ident
+ $(,$($inner_feature:ident$(,)?)+)?
+ }$(,)?
+ )*
+ }
+
+ {
+ $(
+ $(#[$composite_set_doc:meta])*
+ $composite_set_feature:ident = {
+ $set_first_inner_feature:ident
+ $(,$($set_inner_feature:ident$(,)?)+)?
+ }$(,)?
+ )*
+ }
+ ) => {
+ /// specific decode settings controlling how an x86 byte sequence is interpreted.
+ ///
+ /// this currently exists to specify which extensions are to be accepted or rejected. the two
+ /// implementations provided by `yaxpeax-x86` are:
+ /// * [`InstDecoder`], providing configurable enablement or disablement per-extension
+ /// * [`DecodeEverything`], which allows all extensions supported by `yaxpeax-x86`
+ ///
+ /// notably, `InstDecoder::default()` and `DecodeEverything` are functionally equivalent in that
+ /// they accept all extensions supported by the decoder.
+ ///
+ /// TODO: many additional extension support flags.
+ /// * extended MMX (see `sha256:daee4e23dac983f1744126352d40cc71d47b4a9283a2a1e473837728ca9c51ac`)
+ /// * lots of others... tile extensions...
+ pub trait IsaSettings {
+ $(
+ $(#[$doc])*
+ fn $feature(&self) -> bool;
+ )+
+
+ $(
+ $(#[$composite_doc])*
+ fn $composite_feature(&self) -> bool {
+ self.$first_inner_feature()
+ $($(&& self.$inner_feature())+)?
+ }
+ )*
+
+ fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> {
+ revise_instruction(self, inst)
+ }
+ }
+
+ impl IsaSettings for DecodeEverything {
+ $(fn $feature(&self) -> bool { true })+
+
+ fn revise_instruction(&self, _inst: &mut Instruction) -> Result<(), DecodeError> {
+ Ok(())
+ }
+ }
+
+ impl IsaSettings for InstDecoder {
+ $(
+ fn $feature(&self) -> bool {
+ let i = $idx as usize;
+ self.flags[i / 64] & (1 << (i % 64)) != 0
+ }
+ )+
+ }
+
+ impl InstDecoder {
+ $(
+ $(#[$set_doc])*
+ pub fn $set_feature(mut self) -> Self {
+ let i = $idx as usize;
+ self.flags[i / 64] |= 1 << (i % 64);
+ self
+ }
+ )+
+
+ $(
+ $(#[$composite_set_doc])*
+ pub fn $composite_set_feature(&self) -> Self {
+ self.$set_first_inner_feature()
+ $($(.$set_inner_feature())+)?
+ }
+ )*
+
+ $(
+ $(#[$doc])*
+ pub fn $feature(&self) -> bool {
+ <Self as IsaSettings>::$feature(self)
+ }
+ )+
+
+ $(
+ $(#[$composite_doc])*
+ pub fn $composite_feature(&self) -> bool {
+ <Self as IsaSettings>::$composite_feature(self)
+ }
+ )*
+ }
+ }
+}
+gen_isa_settings!(
+ _3dnow, with_3dnow = 1;
+ _3dnowprefetch, with_3dnowprefetch = 2;
+ abm, with_abm = 3;
+ adx, with_adx = 4;
+ aesni, with_aesni = 5;
+ amd_quirks, with_amd_quirks = 6;
+ avx, with_avx = 7;
+ avx2, with_avx2 = 8;
+ avx512_4fmaps, with_avx512_4fmaps = 10;
+ avx512_4vnniw, with_avx512_4vnniw = 11;
+ avx512_bitalg, with_avx512_bitalg = 12;
+ avx512_bw, with_avx512_bw = 13;
+ avx512_cd, with_avx512_cd = 14;
+ avx512_dq, with_avx512_dq = 15;
+ avx512_er, with_avx512_er = 16;
+ avx512_f, with_avx512_f = 17;
+ avx512_fma, with_avx512_fma = 18;
+ avx512_pf, with_avx512_pf = 19;
+ avx512_vbmi, with_avx512_vbmi = 20;
+ avx512_vbmi2, with_avx512_vbmi2 = 21;
+ avx512_vl, with_avx512_vl = 22;
+ avx512_vpopcntdq, with_avx512_vpopcntdq = 23;
+ avx_vnni, with_avx_vnni = 24;
+ bmi1, with_bmi1 = 25;
+ #[doc="`bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`, "]
+ #[doc="and `SHLX` instructions. `bmi2` is implemented in all x86_64 chips that implement `bmi`, "]
+ #[doc="except the amd `piledriver` and `steamroller` microarchitectures."]
+ bmi2, with_bmi2 = 26;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EBX_x0`: \"CLFLUSHOPT instruction support.\""]
+ clflushopt, with_clflushopt = 27;
+ clwb, with_clwb = 28;
+ cmov, with_cmov = 29;
+ cmpxchg16b, with_cmpxchg16b = 30;
+ cx8, with_cx8 = 31;
+ f16c, with_f16c = 32;
+ fma3, with_fma3 = 33;
+ fma4, with_fma4 = 34;
+ gfni, with_gfni = 35;
+ intel_quirks, with_intel_quirks = 36;
+ invpcid, with_invpcid = 37;
+ #[doc="`lahfsahf` is only unset for early revisions of 64-bit amd and intel chips. unfortunately"]
+ #[doc="the clearest documentation on when these instructions were reintroduced into 64-bit"]
+ #[doc="architectures seems to be"]
+ #[doc="[wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations):"]
+ #[doc="```text"]
+ #[doc="Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD"]
+ #[doc="introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and"]
+ #[doc="Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the"]
+ #[doc="instructions with the Pentium 4 G1 stepping in December 2005. The 64-bit version of Windows"]
+ #[doc="8.1 requires this feature.[47]"]
+ #[doc="```"]
+ #[doc=""]
+ #[doc="this puts reintroduction of these instructions somewhere in the middle of prescott and k8"]
+ #[doc="lifecycles, for intel and amd respectively. because there is no specific uarch where these"]
+ #[doc="features become enabled, prescott and k8 default to not supporting these instructions,"]
+ #[doc="where later uarches support these instructions."]
+ lahfsahf, with_lahfsahf = 38;
+ lzcnt, with_lzcnt = 39;
+ monitor, with_monitor = 40;
+ movbe, with_movbe = 41;
+ mpx, with_mpx = 42;
+ pclmulqdq, with_pclmulqdq = 43;
+ pcommit, with_pcommit = 44;
+ popcnt, with_popcnt = 45;
+ prefetchw, with_prefetchw = 46;
+ prefetchwt1, with_prefetchwt1 = 47;
+ rdrand, with_rdrand = 48;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EBX_x0`: \"RDSEED instruction support.\""]
+ rdseed, with_rdseed = 49;
+ rdtscp, with_rdtscp = 50;
+ sgx, with_sgx = 51;
+ sha, with_sha = 52;
+ skinit, with_skinit = 53;
+ sse3, with_sse3 = 54;
+ sse4_1, with_sse4_1 = 55;
+ sse4_2, with_sse4_2 = 56;
+ sse4a, with_sse4a = 57;
+ ssse3, with_ssse3 = 58;
+ svm, with_svm = 59;
+ syscall, with_syscall = 60;
+ tbm, with_tbm = 61;
+ tsx, with_tsx = 62;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"VAES 256-bit instruction support.\""]
+ vaes, with_vaes = 63;
+ vmx, with_vmx = 64;
+ xop, with_xop = 65;
+ xsave, with_xsave = 66;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVEC and compact XRSTOR supported.\""]
+ xsavec, with_xsavec = 67;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVES, XRSTOR, and XSS are supported.\""]
+ xsaves, with_xsaves = 68;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVEOPT is available.\""]
+ xsaveopt, with_xsaveopt = 69;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EAX_x0`: \"FS and GS base read/write instruction support.\""]
+ fsgsbase, with_fsgsbase = 70;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0001_ECX`: \"Support for MWAITX and MONITORX instructions.\""]
+ monitorx, with_monitorx = 71;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0008_EBX`: \"WBNOINVD instruction supported.\""]
+ wbnoinvd, with_wbnoinvd = 72;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0008_EBX`: \"CLZERO instruction supported.\""]
+ clzero, with_clzero = 72;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"RDPID instruction and TSC_AUX MSR support.\""]
+ rdpid, with_rdpid = 73;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"VPCLMULQDQ 256-bit instruction support.\""]
+ vpclmulqdq, with_vpclmulqdq = 74;
+ #[doc="supported in Zen 5, but not mentioned in the AMD APM as of revision 3.36."]
+ movdir64b, with_movdir64b = 75;
+ #[doc="supported in Zen 5, but not mentioned in the AMD APM as of revision 3.36."]
+ enqcmd, with_enqcmd = 76;
+
+ {
+ sse4 = {
+ sse4_1,
+ sse4_2,
+ }
+
+ #[doc = "returns `true` if this `InstDecoder` has **all** `avx512` features enabled."]
+ avx512 = {
+ avx512_4fmaps,
+ avx512_4vnniw,
+ avx512_bitalg,
+ avx512_bw,
+ avx512_cd,
+ avx512_dq,
+ avx512_er,
+ avx512_f,
+ avx512_fma,
+ avx512_pf,
+ avx512_vbmi,
+ avx512_vbmi2,
+ avx512_vl,
+ avx512_vpopcntdq,
+ },
+ }
+
+ {
+ with_sse4 = {
+ with_sse4_1,
+ with_sse4_2,
+ }
+
+ with_avx512 = {
+ with_avx512_4fmaps,
+ with_avx512_4vnniw,
+ with_avx512_bitalg,
+ with_avx512_bw,
+ with_avx512_cd,
+ with_avx512_dq,
+ with_avx512_er,
+ with_avx512_f,
+ with_avx512_fma,
+ with_avx512_pf,
+ with_avx512_vbmi,
+ with_avx512_vbmi2,
+ with_avx512_vl,
+ with_avx512_vpopcntdq,
+ }
+ }
+);
+
+/// optionally reject or reinterpret instruction according to settings for this decode
+/// operation.
+fn revise_instruction<D: IsaSettings + ?Sized>(settings: &D, inst: &mut Instruction) -> Result<(), DecodeError> {
+ if inst.prefixes.evex().is_some() {
+ if !settings.avx512() {
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ return Ok(());
+ }
+ }
+ match inst.opcode {
+ // original 3dnow instructions. see also
+ // `3DNow-Technology-Manual.pdf`
+ // * sha256: daee4e23dac983f1744126352d40cc71d47b4a9283a2a1e473837728ca9c51ac
+ // * ref: https://www.amd.com/content/dam/amd/en/documents/archived-tech-docs/programmer-references/21928.pdf
+ // * order# 21928
+ Opcode::FEMMS |
+ Opcode::PAVGUSB |
+ Opcode::PFADD |
+ Opcode::PFSUB |
+ Opcode::PFSUBR |
+ Opcode::PFACC |
+ Opcode::PFCMPGE |
+ Opcode::PFCMPGT |
+ Opcode::PFCMPEQ |
+ Opcode::PFMAX |
+ Opcode::PFMIN |
+ Opcode::PI2FD |
+ Opcode::PF2ID |
+ Opcode::PFRCP |
+ Opcode::PFRSQRT |
+ Opcode::PFMUL |
+ Opcode::PFRCPIT1 |
+ Opcode::PFRCPIT2 |
+ Opcode::PFRSQIT1 |
+ Opcode::PMULHRW => {
+ if !settings._3dnow() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // later extension to 3dnow. see also
+ // `AMD-Extensions-to-the-3DNow-and-MMX-Instruction-Sets.pdf`
+ // * sha256: ad847bd6877a682296fc584b4bbee354bf84c57bb97ba57e9c9adfc63cc5f465
+ // * ref: https://refspecs.linuxfoundation.org/AMD-extensions.pdf
+ // * order# 22466
+ Opcode::PF2IW |
+ Opcode::PFNACC |
+ Opcode::PFPNACC |
+ Opcode::PI2FW |
+ Opcode::PSWAPD => {
+ if !settings._3dnow() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::TZCNT => {
+ if !settings.bmi1() {
+ // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as
+ // bsf.
+ inst.opcode = Opcode::BSF;
+ }
+ }
+ Opcode::LDDQU |
+ Opcode::ADDSUBPS |
+ Opcode::ADDSUBPD |
+ Opcode::HADDPS |
+ Opcode::HSUBPS |
+ Opcode::HADDPD |
+ Opcode::HSUBPD |
+ Opcode::MOVSHDUP |
+ Opcode::MOVSLDUP |
+ Opcode::MOVDDUP |
+ Opcode::MONITOR |
+ Opcode::MWAIT => {
+ // via Intel section 5.7, SSE3 Instructions
+ if !settings.sse3() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PHADDW |
+ Opcode::PHADDSW |
+ Opcode::PHADDD |
+ Opcode::PHSUBW |
+ Opcode::PHSUBSW |
+ Opcode::PHSUBD |
+ Opcode::PABSB |
+ Opcode::PABSW |
+ Opcode::PABSD |
+ Opcode::PMADDUBSW |
+ Opcode::PMULHRSW |
+ Opcode::PSHUFB |
+ Opcode::PSIGNB |
+ Opcode::PSIGNW |
+ Opcode::PSIGND |
+ Opcode::PALIGNR => {
+ // via Intel section 5.8, SSSE3 Instructions
+ if !settings.ssse3() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PMULLD |
+ Opcode::PMULDQ |
+ Opcode::MOVNTDQA |
+ Opcode::BLENDPD |
+ Opcode::BLENDPS |
+ Opcode::BLENDVPD |
+ Opcode::BLENDVPS |
+ Opcode::PBLENDVB |
+ Opcode::BLENDW |
+ Opcode::PMINUW |
+ Opcode::PMINUD |
+ Opcode::PMINSB |
+ Opcode::PMINSD |
+ Opcode::PMAXUW |
+ Opcode::PMAXUD |
+ Opcode::PMAXSB |
+ Opcode::PMAXSD |
+ Opcode::ROUNDPS |
+ Opcode::ROUNDPD |
+ Opcode::ROUNDSS |
+ Opcode::ROUNDSD |
+ Opcode::PBLENDW |
+ Opcode::EXTRACTPS |
+ Opcode::INSERTPS |
+ Opcode::PINSRB |
+ Opcode::PINSRD |
+ Opcode::PINSRQ |
+ Opcode::PMOVSXBW |
+ Opcode::PMOVZXBW |
+ Opcode::PMOVSXBD |
+ Opcode::PMOVZXBD |
+ Opcode::PMOVSXWD |
+ Opcode::PMOVZXWD |
+ Opcode::PMOVSXBQ |
+ Opcode::PMOVZXBQ |
+ Opcode::PMOVSXWQ |
+ Opcode::PMOVZXWQ |
+ Opcode::PMOVSXDQ |
+ Opcode::PMOVZXDQ |
+ Opcode::DPPS |
+ Opcode::DPPD |
+ Opcode::MPSADBW |
+ Opcode::PHMINPOSUW |
+ Opcode::PTEST |
+ Opcode::PCMPEQQ |
+ Opcode::PEXTRB |
+ Opcode::PEXTRW |
+ Opcode::PEXTRD |
+ Opcode::PEXTRQ |
+ Opcode::PACKUSDW => {
+ // via Intel section 5.10, SSE4.1 Instructions
+ if !settings.sse4_1() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::EXTRQ |
+ Opcode::INSERTQ |
+ Opcode::MOVNTSS |
+ Opcode::MOVNTSD => {
+ if !settings.sse4a() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::CRC32 |
+ Opcode::PCMPESTRI |
+ Opcode::PCMPESTRM |
+ Opcode::PCMPISTRI |
+ Opcode::PCMPISTRM |
+ Opcode::PCMPGTQ => {
+ // via Intel section 5.11, SSE4.2 Instructions
+ if !settings.sse4_2() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::AESDEC |
+ Opcode::AESDECLAST |
+ Opcode::AESENC |
+ Opcode::AESENCLAST |
+ Opcode::AESIMC |
+ Opcode::AESKEYGENASSIST => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !settings.aesni() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PCLMULQDQ => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !settings.pclmulqdq() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::XABORT |
+ Opcode::XBEGIN |
+ Opcode::XEND |
+ Opcode::XTEST => {
+ if !settings.tsx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::SHA1MSG1 |
+ Opcode::SHA1MSG2 |
+ Opcode::SHA1NEXTE |
+ Opcode::SHA1RNDS4 |
+ Opcode::SHA256MSG1 |
+ Opcode::SHA256MSG2 |
+ Opcode::SHA256RNDS2 => {
+ if !settings.sha() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::ENCLV |
+ Opcode::ENCLS |
+ Opcode::ENCLU => {
+ if !settings.sgx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // AVX...
+ Opcode::VMOVDDUP |
+ Opcode::VPSHUFLW |
+ Opcode::VPSHUFHW |
+ Opcode::VHADDPS |
+ Opcode::VHSUBPS |
+ Opcode::VADDSUBPS |
+ Opcode::VCVTPD2DQ |
+ Opcode::VLDDQU |
+ Opcode::VCOMISD |
+ Opcode::VCOMISS |
+ Opcode::VUCOMISD |
+ Opcode::VUCOMISS |
+ Opcode::VADDPD |
+ Opcode::VADDPS |
+ Opcode::VADDSD |
+ Opcode::VADDSS |
+ Opcode::VADDSUBPD |
+ Opcode::VBLENDPD |
+ Opcode::VBLENDPS |
+ Opcode::VBLENDVPD |
+ Opcode::VBLENDVPS |
+ Opcode::VBROADCASTF128 |
+ Opcode::VBROADCASTI128 |
+ Opcode::VBROADCASTSD |
+ Opcode::VBROADCASTSS |
+ Opcode::VCMPSD |
+ Opcode::VCMPSS |
+ Opcode::VCMPPD |
+ Opcode::VCMPPS |
+ Opcode::VCVTDQ2PD |
+ Opcode::VCVTDQ2PS |
+ Opcode::VCVTPD2PS |
+ Opcode::VCVTPS2DQ |
+ Opcode::VCVTPS2PD |
+ Opcode::VCVTSS2SD |
+ Opcode::VCVTSI2SS |
+ Opcode::VCVTSI2SD |
+ Opcode::VCVTSD2SI |
+ Opcode::VCVTSD2SS |
+ Opcode::VCVTSS2SI |
+ Opcode::VCVTTPD2DQ |
+ Opcode::VCVTTPS2DQ |
+ Opcode::VCVTTSS2SI |
+ Opcode::VCVTTSD2SI |
+ Opcode::VDIVPD |
+ Opcode::VDIVPS |
+ Opcode::VDIVSD |
+ Opcode::VDIVSS |
+ Opcode::VDPPD |
+ Opcode::VDPPS |
+ Opcode::VEXTRACTF128 |
+ Opcode::VEXTRACTI128 |
+ Opcode::VEXTRACTPS |
+ Opcode::VFMADD132PD |
+ Opcode::VFMADD132PS |
+ Opcode::VFMADD132SD |
+ Opcode::VFMADD132SS |
+ Opcode::VFMADD213PD |
+ Opcode::VFMADD213PS |
+ Opcode::VFMADD213SD |
+ Opcode::VFMADD213SS |
+ Opcode::VFMADD231PD |
+ Opcode::VFMADD231PS |
+ Opcode::VFMADD231SD |
+ Opcode::VFMADD231SS |
+ Opcode::VFMADDSUB132PD |
+ Opcode::VFMADDSUB132PS |
+ Opcode::VFMADDSUB213PD |
+ Opcode::VFMADDSUB213PS |
+ Opcode::VFMADDSUB231PD |
+ Opcode::VFMADDSUB231PS |
+ Opcode::VFMSUB132PD |
+ Opcode::VFMSUB132PS |
+ Opcode::VFMSUB132SD |
+ Opcode::VFMSUB132SS |
+ Opcode::VFMSUB213PD |
+ Opcode::VFMSUB213PS |
+ Opcode::VFMSUB213SD |
+ Opcode::VFMSUB213SS |
+ Opcode::VFMSUB231PD |
+ Opcode::VFMSUB231PS |
+ Opcode::VFMSUB231SD |
+ Opcode::VFMSUB231SS |
+ Opcode::VFMSUBADD132PD |
+ Opcode::VFMSUBADD132PS |
+ Opcode::VFMSUBADD213PD |
+ Opcode::VFMSUBADD213PS |
+ Opcode::VFMSUBADD231PD |
+ Opcode::VFMSUBADD231PS |
+ Opcode::VFNMADD132PD |
+ Opcode::VFNMADD132PS |
+ Opcode::VFNMADD132SD |
+ Opcode::VFNMADD132SS |
+ Opcode::VFNMADD213PD |
+ Opcode::VFNMADD213PS |
+ Opcode::VFNMADD213SD |
+ Opcode::VFNMADD213SS |
+ Opcode::VFNMADD231PD |
+ Opcode::VFNMADD231PS |
+ Opcode::VFNMADD231SD |
+ Opcode::VFNMADD231SS |
+ Opcode::VFNMSUB132PD |
+ Opcode::VFNMSUB132PS |
+ Opcode::VFNMSUB132SD |
+ Opcode::VFNMSUB132SS |
+ Opcode::VFNMSUB213PD |
+ Opcode::VFNMSUB213PS |
+ Opcode::VFNMSUB213SD |
+ Opcode::VFNMSUB213SS |
+ Opcode::VFNMSUB231PD |
+ Opcode::VFNMSUB231PS |
+ Opcode::VFNMSUB231SD |
+ Opcode::VFNMSUB231SS |
+ Opcode::VGATHERDPD |
+ Opcode::VGATHERDPS |
+ Opcode::VGATHERQPD |
+ Opcode::VGATHERQPS |
+ Opcode::VHADDPD |
+ Opcode::VHSUBPD |
+ Opcode::VINSERTF128 |
+ Opcode::VINSERTI128 |
+ Opcode::VINSERTPS |
+ Opcode::VMASKMOVDQU |
+ Opcode::VMASKMOVPD |
+ Opcode::VMASKMOVPS |
+ Opcode::VMAXPD |
+ Opcode::VMAXPS |
+ Opcode::VMAXSD |
+ Opcode::VMAXSS |
+ Opcode::VMINPD |
+ Opcode::VMINPS |
+ Opcode::VMINSD |
+ Opcode::VMINSS |
+ Opcode::VMOVAPD |
+ Opcode::VMOVAPS |
+ Opcode::VMOVD |
+ Opcode::VMOVDQA |
+ Opcode::VMOVDQU |
+ Opcode::VMOVHLPS |
+ Opcode::VMOVHPD |
+ Opcode::VMOVHPS |
+ Opcode::VMOVLHPS |
+ Opcode::VMOVLPD |
+ Opcode::VMOVLPS |
+ Opcode::VMOVMSKPD |
+ Opcode::VMOVMSKPS |
+ Opcode::VMOVNTDQ |
+ Opcode::VMOVNTDQA |
+ Opcode::VMOVNTPD |
+ Opcode::VMOVNTPS |
+ Opcode::VMOVQ |
+ Opcode::VMOVSS |
+ Opcode::VMOVSD |
+ Opcode::VMOVSHDUP |
+ Opcode::VMOVSLDUP |
+ Opcode::VMOVUPD |
+ Opcode::VMOVUPS |
+ Opcode::VMPSADBW |
+ Opcode::VMULPD |
+ Opcode::VMULPS |
+ Opcode::VMULSD |
+ Opcode::VMULSS |
+ Opcode::VPABSB |
+ Opcode::VPABSD |
+ Opcode::VPABSW |
+ Opcode::VPACKSSDW |
+ Opcode::VPACKUSDW |
+ Opcode::VPACKSSWB |
+ Opcode::VPACKUSWB |
+ Opcode::VPADDB |
+ Opcode::VPADDD |
+ Opcode::VPADDQ |
+ Opcode::VPADDSB |
+ Opcode::VPADDSW |
+ Opcode::VPADDUSB |
+ Opcode::VPADDUSW |
+ Opcode::VPADDW |
+ Opcode::VPALIGNR |
+ Opcode::VPAND |
+ Opcode::VANDPD |
+ Opcode::VANDPS |
+ Opcode::VANDNPD |
+ Opcode::VANDNPS |
+ Opcode::VORPD |
+ Opcode::VORPS |
+ Opcode::VPANDN |
+ Opcode::VPAVGB |
+ Opcode::VPAVGW |
+ Opcode::VPBLENDD |
+ Opcode::VPBLENDVB |
+ Opcode::VPBLENDW |
+ Opcode::VPBROADCASTB |
+ Opcode::VPBROADCASTD |
+ Opcode::VPBROADCASTQ |
+ Opcode::VPBROADCASTW |
+ Opcode::VPCLMULQDQ |
+ Opcode::VPCMPEQB |
+ Opcode::VPCMPEQD |
+ Opcode::VPCMPEQQ |
+ Opcode::VPCMPEQW |
+ Opcode::VPCMPGTB |
+ Opcode::VPCMPGTD |
+ Opcode::VPCMPGTQ |
+ Opcode::VPCMPGTW |
+ Opcode::VPCMPESTRI |
+ Opcode::VPCMPESTRM |
+ Opcode::VPCMPISTRI |
+ Opcode::VPCMPISTRM |
+ Opcode::VPERM2F128 |
+ Opcode::VPERM2I128 |
+ Opcode::VPERMD |
+ Opcode::VPERMILPD |
+ Opcode::VPERMILPS |
+ Opcode::VPERMPD |
+ Opcode::VPERMPS |
+ Opcode::VPERMQ |
+ Opcode::VPEXTRB |
+ Opcode::VPEXTRD |
+ Opcode::VPEXTRQ |
+ Opcode::VPEXTRW |
+ Opcode::VPGATHERDD |
+ Opcode::VPGATHERDQ |
+ Opcode::VPGATHERQD |
+ Opcode::VPGATHERQQ |
+ Opcode::VPHADDD |
+ Opcode::VPHADDSW |
+ Opcode::VPHADDW |
+ Opcode::VPMADDUBSW |
+ Opcode::VPHMINPOSUW |
+ Opcode::VPHSUBD |
+ Opcode::VPHSUBSW |
+ Opcode::VPHSUBW |
+ Opcode::VPINSRB |
+ Opcode::VPINSRD |
+ Opcode::VPINSRQ |
+ Opcode::VPINSRW |
+ Opcode::VPMADDWD |
+ Opcode::VPMASKMOVD |
+ Opcode::VPMASKMOVQ |
+ Opcode::VPMAXSB |
+ Opcode::VPMAXSD |
+ Opcode::VPMAXSW |
+ Opcode::VPMAXUB |
+ Opcode::VPMAXUW |
+ Opcode::VPMAXUD |
+ Opcode::VPMINSB |
+ Opcode::VPMINSW |
+ Opcode::VPMINSD |
+ Opcode::VPMINUB |
+ Opcode::VPMINUW |
+ Opcode::VPMINUD |
+ Opcode::VPMOVMSKB |
+ Opcode::VPMOVSXBD |
+ Opcode::VPMOVSXBQ |
+ Opcode::VPMOVSXBW |
+ Opcode::VPMOVSXDQ |
+ Opcode::VPMOVSXWD |
+ Opcode::VPMOVSXWQ |
+ Opcode::VPMOVZXBD |
+ Opcode::VPMOVZXBQ |
+ Opcode::VPMOVZXBW |
+ Opcode::VPMOVZXDQ |
+ Opcode::VPMOVZXWD |
+ Opcode::VPMOVZXWQ |
+ Opcode::VPMULDQ |
+ Opcode::VPMULHRSW |
+ Opcode::VPMULHUW |
+ Opcode::VPMULHW |
+ Opcode::VPMULLQ |
+ Opcode::VPMULLD |
+ Opcode::VPMULLW |
+ Opcode::VPMULUDQ |
+ Opcode::VPOR |
+ Opcode::VPSADBW |
+ Opcode::VPSHUFB |
+ Opcode::VPSHUFD |
+ Opcode::VPSIGNB |
+ Opcode::VPSIGND |
+ Opcode::VPSIGNW |
+ Opcode::VPSLLD |
+ Opcode::VPSLLDQ |
+ Opcode::VPSLLQ |
+ Opcode::VPSLLVD |
+ Opcode::VPSLLVQ |
+ Opcode::VPSLLW |
+ Opcode::VPSRAD |
+ Opcode::VPSRAVD |
+ Opcode::VPSRAW |
+ Opcode::VPSRLD |
+ Opcode::VPSRLDQ |
+ Opcode::VPSRLQ |
+ Opcode::VPSRLVD |
+ Opcode::VPSRLVQ |
+ Opcode::VPSRLW |
+ Opcode::VPSUBB |
+ Opcode::VPSUBD |
+ Opcode::VPSUBQ |
+ Opcode::VPSUBSB |
+ Opcode::VPSUBSW |
+ Opcode::VPSUBUSB |
+ Opcode::VPSUBUSW |
+ Opcode::VPSUBW |
+ Opcode::VPTEST |
+ Opcode::VPUNPCKHBW |
+ Opcode::VPUNPCKHDQ |
+ Opcode::VPUNPCKHQDQ |
+ Opcode::VPUNPCKHWD |
+ Opcode::VPUNPCKLBW |
+ Opcode::VPUNPCKLDQ |
+ Opcode::VPUNPCKLQDQ |
+ Opcode::VPUNPCKLWD |
+ Opcode::VPXOR |
+ Opcode::VRCPPS |
+ Opcode::VROUNDPD |
+ Opcode::VROUNDPS |
+ Opcode::VROUNDSD |
+ Opcode::VROUNDSS |
+ Opcode::VRSQRTPS |
+ Opcode::VRSQRTSS |
+ Opcode::VRCPSS |
+ Opcode::VSHUFPD |
+ Opcode::VSHUFPS |
+ Opcode::VSQRTPD |
+ Opcode::VSQRTPS |
+ Opcode::VSQRTSS |
+ Opcode::VSQRTSD |
+ Opcode::VSUBPD |
+ Opcode::VSUBPS |
+ Opcode::VSUBSD |
+ Opcode::VSUBSS |
+ Opcode::VTESTPD |
+ Opcode::VTESTPS |
+ Opcode::VUNPCKHPD |
+ Opcode::VUNPCKHPS |
+ Opcode::VUNPCKLPD |
+ Opcode::VUNPCKLPS |
+ Opcode::VXORPD |
+ Opcode::VXORPS |
+ Opcode::VZEROUPPER |
+ Opcode::VZEROALL |
+ Opcode::VLDMXCSR |
+ Opcode::VSTMXCSR => {
+ // TODO: check a table for these
+ if !settings.avx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VAESDEC |
+ Opcode::VAESDECLAST |
+ Opcode::VAESENC |
+ Opcode::VAESENCLAST |
+ Opcode::VAESIMC |
+ Opcode::VAESKEYGENASSIST => {
+ // TODO: check a table for these
+ if !settings.avx() || !settings.aesni() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::MOVBE => {
+ if !settings.movbe() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::POPCNT => {
+ /*
+ * from the intel SDM:
+ * ```
+ * Before an application attempts to use the POPCNT instruction, it must check that
+ * the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT
+ * (if CPUID.01H:ECX.POPCNT[bit 23] = 1).
+ * ```
+ */
+ if settings.intel_quirks() && (settings.sse4_2() || settings.popcnt()) {
+ return Ok(());
+ } else if !settings.popcnt() {
+ /*
+ * elsewhere from the amd APM:
+ * `Instruction Subsets and CPUID Feature Flags` on page 507 indicates that
+ * popcnt is present when the popcnt bit is reported by cpuid. this seems to be
+ * the less quirky default, so `intel_quirks` is considered the outlier, and
+ * before this default.
+ * */
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::LZCNT => {
+ /*
+ * amd APM, `LZCNT` page 212:
+ * LZCNT is an Advanced Bit Manipulation (ABM) instruction. Support for the LZCNT
+ * instruction is indicated by CPUID Fn8000_0001_ECX[ABM] = 1.
+ *
+ * meanwhile the intel SDM simply states:
+ * ```
+ * CPUID.EAX=80000001H:ECX.LZCNT[bit 5]: if 1 indicates the processor supports the
+ * LZCNT instruction.
+ * ```
+ *
+ * so that's considered the less-quirky (default) case here.
+ * */
+ if settings.amd_quirks() && !settings.abm() {
+ return Err(DecodeError::InvalidOpcode);
+ } else if !settings.lzcnt() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::ADCX |
+ Opcode::ADOX => {
+ if !settings.adx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VMRUN |
+ Opcode::VMLOAD |
+ Opcode::VMSAVE |
+ Opcode::CLGI |
+ Opcode::VMMCALL |
+ Opcode::INVLPGA => {
+ if !settings.svm() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::STGI |
+ Opcode::SKINIT => {
+ if !settings.svm() || !settings.skinit() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::LAHF |
+ Opcode::SAHF => {
+ if !settings.lahfsahf() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VCVTPS2PH |
+ Opcode::VCVTPH2PS => {
+ /*
+ * from intel SDM:
+ * ```
+ * 14.4.1 Detection of F16C Instructions Application using float 16 instruction
+ * must follow a detection sequence similar to AVX to ensure: • The OS has
+ * enabled YMM state management support, • The processor support AVX as
+ * indicated by the CPUID feature flag, i.e. CPUID.01H:ECX.AVX[bit 28] = 1. •
+ * The processor support 16-bit floating-point conversion instructions via a
+ * CPUID feature flag (CPUID.01H:ECX.F16C[bit 29] = 1).
+ * ```
+ *
+ * TODO: only the VEX-coded variant of this instruction should be gated on `f16c`.
+ * the EVEX-coded variant should be gated on `avx512f` or `avx512vl` if not
+ * EVEX.512-coded.
+ */
+ if !settings.avx() || !settings.f16c() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::RDRAND => {
+ if !settings.rdrand() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::RDSEED => {
+ if !settings.rdseed() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::MONITORX | Opcode::MWAITX | // these are gated on the `monitorx` and `mwaitx` cpuid bits, but are AMD-only.
+ Opcode::CLZERO | Opcode::RDPRU => { // again, gated on specific cpuid bits, but AMD-only.
+ if !settings.amd_quirks() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ other => {
+ if !settings.bmi1() {
+ if BMI1.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ if !settings.bmi2() {
+ if BMI2.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ }
+ Ok(())
+}