Files
visor/pkg/cpuid/features_amd64.go
Konstantin BogomolovandgVisor bot d4afe779c0 Add cpuid features block (EAX=07H,ECX=0):EDX.
This block holds information about whether AMX is enabled or not,
which is important for CPUs that support it due to the fact that
the fpstate buffer becomes dynamically sized, and the cpuid value
reported for extended state size assumes that AMX is enabled for
any given process.

PiperOrigin-RevId: 598941137
2024-01-16 13:40:49 -08:00

665 lines
19 KiB
Go

// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build amd64
// +build amd64
package cpuid
// block is a collection of 32 Feature bits.
type block int
// blockSize is the number of bits in a single block.
const blockSize = 32
// featureID returns the feature identified by the given block and bit.
//
// Feature bits are numbered according to "blocks". Each block is 32 bits, and
// feature bits from the same source (cpuid leaf/level) are in the same block.
func featureID(b block, bit int) Feature {
return Feature(blockSize*int(b) + bit)
}
// block returns the block associated with the feature.
func (f Feature) block() block {
return block(f / blockSize)
}
// Bit returns the bit associated with the feature.
func (f Feature) bit() uint32 {
return uint32(1 << (f % blockSize))
}
// ChangeableSet is a feature set that can allows changes.
type ChangeableSet interface {
Query(in In) Out
Set(in In, out Out)
}
// Set sets the given feature.
func (f Feature) Set(s ChangeableSet) {
f.set(s, true)
}
// Unset unsets the given feature.
func (f Feature) Unset(s ChangeableSet) {
f.set(s, false)
}
// set sets the given feature.
func (f Feature) set(s ChangeableSet, on bool) {
switch f.block() {
case 0:
out := s.Query(In{Eax: uint32(featureInfo)})
if on {
out.Ecx |= f.bit()
} else {
out.Ecx &^= f.bit()
}
s.Set(In{Eax: uint32(featureInfo)}, out)
case 1:
out := s.Query(In{Eax: uint32(featureInfo)})
if on {
out.Edx |= f.bit()
} else {
out.Edx &^= f.bit()
}
s.Set(In{Eax: uint32(featureInfo)}, out)
case 2:
out := s.Query(In{Eax: uint32(extendedFeatureInfo)})
if on {
out.Ebx |= f.bit()
} else {
out.Ebx &^= f.bit()
}
s.Set(In{Eax: uint32(extendedFeatureInfo)}, out)
case 3:
out := s.Query(In{Eax: uint32(extendedFeatureInfo)})
if on {
out.Ecx |= f.bit()
} else {
out.Ecx &^= f.bit()
}
s.Set(In{Eax: uint32(extendedFeatureInfo)}, out)
case 4:
// Need to turn on the bit in block 0.
out := s.Query(In{Eax: uint32(featureInfo)})
out.Ecx |= (1 << 26)
s.Set(In{Eax: uint32(featureInfo)}, out)
out = s.Query(In{Eax: xSaveInfoSub.eax(), Ecx: xSaveInfoSub.ecx()})
if on {
out.Eax |= f.bit()
} else {
out.Eax &^= f.bit()
}
s.Set(In{Eax: xSaveInfoSub.eax(), Ecx: xSaveInfoSub.ecx()}, out)
case 5, 6:
// Need to enable extended features.
out := s.Query(In{Eax: uint32(extendedFunctionInfo)})
if out.Eax < uint32(extendedFeatures) {
out.Eax = uint32(extendedFeatures)
}
s.Set(In{Eax: uint32(extendedFunctionInfo)}, out)
out = s.Query(In{Eax: uint32(extendedFeatures)})
if f.block() == 5 {
if on {
out.Ecx |= f.bit()
} else {
out.Ecx &^= f.bit()
}
} else {
if on {
out.Edx |= f.bit()
} else {
out.Edx &^= f.bit()
}
}
s.Set(In{Eax: uint32(extendedFeatures)}, out)
case 7:
out := s.Query(In{Eax: uint32(extendedFeatureInfo)})
if on {
out.Edx |= f.bit()
} else {
out.Edx &^= f.bit()
}
s.Set(In{Eax: uint32(extendedFeatureInfo)}, out)
}
}
// check checks for the given feature.
//
//go:nosplit
func (f Feature) check(fs FeatureSet) bool {
switch f.block() {
case 0:
_, _, cx, _ := fs.query(featureInfo)
return (cx & f.bit()) != 0
case 1:
_, _, _, dx := fs.query(featureInfo)
return (dx & f.bit()) != 0
case 2:
_, bx, _, _ := fs.query(extendedFeatureInfo)
return (bx & f.bit()) != 0
case 3:
_, _, cx, _ := fs.query(extendedFeatureInfo)
return (cx & f.bit()) != 0
case 4:
// Need to check appropriate bit in block 0.
_, _, cx, _ := fs.query(featureInfo)
if (cx & (1 << 26)) == 0 {
return false
}
ax, _, _, _ := fs.query(xSaveInfoSub)
return (ax & f.bit()) != 0
case 5, 6:
// eax=0x80000000 gets supported extended levels. We use this
// to determine if there are any non-zero block 4 or block 6
// bits to find.
ax, _, _, _ := fs.query(extendedFunctionInfo)
if ax >= uint32(extendedFeatures) {
_, _, cx, dx := fs.query(extendedFeatures)
if f.block() == 5 {
return (cx & f.bit()) != 0
}
// Ignore features duplicated from block 1 on AMD.
// These bits are reserved on Intel.
return ((dx &^ block6DuplicateMask) & f.bit()) != 0
}
return false
case 7:
_, _, _, dx := fs.query(extendedFeatureInfo)
return (dx & f.bit()) != 0
default:
return false
}
}
// Block 0 constants are all of the "basic" feature bits returned by a cpuid in
// ecx with eax=1.
const (
X86FeatureSSE3 Feature = iota
X86FeaturePCLMULDQ
X86FeatureDTES64
X86FeatureMONITOR
X86FeatureDSCPL
X86FeatureVMX
X86FeatureSMX
X86FeatureEST
X86FeatureTM2
X86FeatureSSSE3 // Not a typo, "supplemental" SSE3.
X86FeatureCNXTID
X86FeatureSDBG
X86FeatureFMA
X86FeatureCX16
X86FeatureXTPR
X86FeaturePDCM
_ // ecx bit 16 is reserved.
X86FeaturePCID
X86FeatureDCA
X86FeatureSSE4_1
X86FeatureSSE4_2
X86FeatureX2APIC
X86FeatureMOVBE
X86FeaturePOPCNT
X86FeatureTSCD
X86FeatureAES
X86FeatureXSAVE
X86FeatureOSXSAVE
X86FeatureAVX
X86FeatureF16C
X86FeatureRDRAND
X86FeatureHypervisor
)
// Block 1 constants are all of the "basic" feature bits returned by a cpuid in
// edx with eax=1.
const (
X86FeatureFPU Feature = 32 + iota
X86FeatureVME
X86FeatureDE
X86FeaturePSE
X86FeatureTSC
X86FeatureMSR
X86FeaturePAE
X86FeatureMCE
X86FeatureCX8
X86FeatureAPIC
_ // edx bit 10 is reserved.
X86FeatureSEP
X86FeatureMTRR
X86FeaturePGE
X86FeatureMCA
X86FeatureCMOV
X86FeaturePAT
X86FeaturePSE36
X86FeaturePSN
X86FeatureCLFSH
_ // edx bit 20 is reserved.
X86FeatureDS
X86FeatureACPI
X86FeatureMMX
X86FeatureFXSR
X86FeatureSSE
X86FeatureSSE2
X86FeatureSS
X86FeatureHTT
X86FeatureTM
X86FeatureIA64
X86FeaturePBE
)
// Block 2 bits are the "structured extended" features returned in ebx for
// eax=7, ecx=0.
const (
X86FeatureFSGSBase Feature = 2*32 + iota
X86FeatureTSC_ADJUST
_ // ebx bit 2 is reserved.
X86FeatureBMI1
X86FeatureHLE
X86FeatureAVX2
X86FeatureFDP_EXCPTN_ONLY
X86FeatureSMEP
X86FeatureBMI2
X86FeatureERMS
X86FeatureINVPCID
X86FeatureRTM
X86FeatureCQM
X86FeatureFPCSDS
X86FeatureMPX
X86FeatureRDT
X86FeatureAVX512F
X86FeatureAVX512DQ
X86FeatureRDSEED
X86FeatureADX
X86FeatureSMAP
X86FeatureAVX512IFMA
X86FeaturePCOMMIT
X86FeatureCLFLUSHOPT
X86FeatureCLWB
X86FeatureIPT // Intel processor trace.
X86FeatureAVX512PF
X86FeatureAVX512ER
X86FeatureAVX512CD
X86FeatureSHA
X86FeatureAVX512BW
X86FeatureAVX512VL
)
// Block 3 bits are the "extended" features returned in ecx for eax=7, ecx=0.
const (
X86FeaturePREFETCHWT1 Feature = 3*32 + iota
X86FeatureAVX512VBMI
X86FeatureUMIP
X86FeaturePKU
X86FeatureOSPKE
X86FeatureWAITPKG
X86FeatureAVX512_VBMI2
X86FeatureCET_SS
X86FeatureGFNI
X86FeatureVAES
X86FeatureVPCLMULQDQ
X86FeatureAVX512_VNNI
X86FeatureAVX512_BITALG
X86FeatureTME
X86FeatureAVX512_VPOPCNTDQ
_ // ecx bit 15 is reserved
X86FeatureLA57
// ecx bits 17-21 are reserved
_
_
_
_
_
X86FeatureRDPID
// ecx bits 23-24 are reserved
_
_
X86FeatureCLDEMOTE
_ // ecx bit 26 is reserved
X86FeatureMOVDIRI
X86FeatureMOVDIR64B
)
// Block 4 constants are for xsave capabilities in CPUID.(EAX=0DH,ECX=01H):EAX.
// The CPUID leaf is available only if 'X86FeatureXSAVE' is present.
const (
X86FeatureXSAVEOPT Feature = 4*32 + iota
X86FeatureXSAVEC
X86FeatureXGETBV1
X86FeatureXSAVES
// EAX[31:4] are reserved.
)
// Block 5 constants are the extended feature bits in
// CPUID.(EAX=0x80000001):ECX.
const (
X86FeatureLAHF64 Feature = 5*32 + iota
X86FeatureCMP_LEGACY
X86FeatureSVM
X86FeatureEXTAPIC
X86FeatureCR8_LEGACY
X86FeatureLZCNT
X86FeatureSSE4A
X86FeatureMISALIGNSSE
X86FeaturePREFETCHW
X86FeatureOSVW
X86FeatureIBS
X86FeatureXOP
X86FeatureSKINIT
X86FeatureWDT
_ // ecx bit 14 is reserved.
X86FeatureLWP
X86FeatureFMA4
X86FeatureTCE
_ // ecx bit 18 is reserved.
_ // ecx bit 19 is reserved.
_ // ecx bit 20 is reserved.
X86FeatureTBM
X86FeatureTOPOLOGY
X86FeaturePERFCTR_CORE
X86FeaturePERFCTR_NB
_ // ecx bit 25 is reserved.
X86FeatureBPEXT
X86FeaturePERFCTR_TSC
X86FeaturePERFCTR_LLC
X86FeatureMWAITX
X86FeatureADMSKEXTN
_ // ecx bit 31 is reserved.
)
// Block 6 constants are the extended feature bits in
// CPUID.(EAX=0x80000001):EDX.
//
// These are sparse, and so the bit positions are assigned manually.
const (
// On AMD, EDX[24:23] | EDX[17:12] | EDX[9:0] are duplicate features
// also defined in block 1 (in identical bit positions). Those features
// are not listed here.
block6DuplicateMask = 0x183f3ff
X86FeatureSYSCALL Feature = 6*32 + 11
X86FeatureNX Feature = 6*32 + 20
X86FeatureMMXEXT Feature = 6*32 + 22
X86FeatureFXSR_OPT Feature = 6*32 + 25
X86FeatureGBPAGES Feature = 6*32 + 26
X86FeatureRDTSCP Feature = 6*32 + 27
X86FeatureLM Feature = 6*32 + 29
X86Feature3DNOWEXT Feature = 6*32 + 30
X86Feature3DNOW Feature = 6*32 + 31
)
// Block 7 constants are the extended features bits in
// CPUID.(EAX=07H,ECX=0):EDX.
const (
_ Feature = 7*32 + iota // edx bit 0 is reserved.
_ // edx bit 1 is reserved.
X86FeatureAVX512_4VNNIW
X86FeatureAVX512_4FMAPS
X86FeatureFSRM
_ // edx bit 5 is not used in Linux.
_ // edx bit 6 is reserved.
_ // edx bit 7 is reserved.
X86FeatureAVX512_VP2INTERSECT
X86FeatureSRBDS_CTRL
X86FeatureMD_CLEAR
X86FeatureRTM_ALWAYS_ABORT
_ // edx bit 12 is reserved.
X86FeatureTSX_FORCE_ABORT
X86FeatureSERIALIZE
X86FeatureHYBRID_CPU
X86FeatureTSXLDTRK
_ // edx bit 17 is reserved.
X86FeaturePCONFIG
X86FeatureARCH_LBR
X86FeatureIBT
_ // edx bit 21 is reserved.
X86FeatureAMX_BF16
X86FeatureAVX512_FP16
X86FeatureAMX_TILE
X86FeatureAMX_INT8
X86FeatureSPEC_CTRL
X86FeatureINTEL_STIBP
X86FeatureFLUSH_L1D
X86FeatureARCH_CAPABILITIES
X86FeatureCORE_CAPABILITIES
X86FeatureSPEC_CTRL_SSBD
)
// These are the extended floating point state features. They are used to
// enumerate floating point features in XCR0, XSTATE_BV, etc.
const (
XSAVEFeatureX87 = 1 << 0
XSAVEFeatureSSE = 1 << 1
XSAVEFeatureAVX = 1 << 2
XSAVEFeatureBNDREGS = 1 << 3
XSAVEFeatureBNDCSR = 1 << 4
XSAVEFeatureAVX512op = 1 << 5
XSAVEFeatureAVX512zmm0 = 1 << 6
XSAVEFeatureAVX512zmm16 = 1 << 7
XSAVEFeaturePKRU = 1 << 9
)
// allFeatures is the set of allFeatures.
//
// These match names used in arch/x86/kernel/cpu/capflags.c.
var allFeatures = map[Feature]allFeatureInfo{
// Block 0.
X86FeatureSSE3: {"pni", true},
X86FeaturePCLMULDQ: {"pclmulqdq", true},
X86FeatureDTES64: {"dtes64", true},
X86FeatureMONITOR: {"monitor", true},
X86FeatureDSCPL: {"ds_cpl", true},
X86FeatureVMX: {"vmx", true},
X86FeatureSMX: {"smx", true},
X86FeatureEST: {"est", true},
X86FeatureTM2: {"tm2", true},
X86FeatureSSSE3: {"ssse3", true},
X86FeatureCNXTID: {"cid", true},
X86FeatureSDBG: {"sdbg", true},
X86FeatureFMA: {"fma", true},
X86FeatureCX16: {"cx16", true},
X86FeatureXTPR: {"xtpr", true},
X86FeaturePDCM: {"pdcm", true},
X86FeaturePCID: {"pcid", true},
X86FeatureDCA: {"dca", true},
X86FeatureSSE4_1: {"sse4_1", true},
X86FeatureSSE4_2: {"sse4_2", true},
X86FeatureX2APIC: {"x2apic", true},
X86FeatureMOVBE: {"movbe", true},
X86FeaturePOPCNT: {"popcnt", true},
X86FeatureTSCD: {"tsc_deadline_timer", true},
X86FeatureAES: {"aes", true},
X86FeatureXSAVE: {"xsave", true},
X86FeatureAVX: {"avx", true},
X86FeatureF16C: {"f16c", true},
X86FeatureRDRAND: {"rdrand", true},
X86FeatureHypervisor: {"hypervisor", true},
X86FeatureOSXSAVE: {"osxsave", false},
// Block 1.
X86FeatureFPU: {"fpu", true},
X86FeatureVME: {"vme", true},
X86FeatureDE: {"de", true},
X86FeaturePSE: {"pse", true},
X86FeatureTSC: {"tsc", true},
X86FeatureMSR: {"msr", true},
X86FeaturePAE: {"pae", true},
X86FeatureMCE: {"mce", true},
X86FeatureCX8: {"cx8", true},
X86FeatureAPIC: {"apic", true},
X86FeatureSEP: {"sep", true},
X86FeatureMTRR: {"mtrr", true},
X86FeaturePGE: {"pge", true},
X86FeatureMCA: {"mca", true},
X86FeatureCMOV: {"cmov", true},
X86FeaturePAT: {"pat", true},
X86FeaturePSE36: {"pse36", true},
X86FeaturePSN: {"pn", true},
X86FeatureCLFSH: {"clflush", true},
X86FeatureDS: {"dts", true},
X86FeatureACPI: {"acpi", true},
X86FeatureMMX: {"mmx", true},
X86FeatureFXSR: {"fxsr", true},
X86FeatureSSE: {"sse", true},
X86FeatureSSE2: {"sse2", true},
X86FeatureSS: {"ss", true},
X86FeatureHTT: {"ht", true},
X86FeatureTM: {"tm", true},
X86FeatureIA64: {"ia64", true},
X86FeaturePBE: {"pbe", true},
// Block 2.
X86FeatureFSGSBase: {"fsgsbase", true},
X86FeatureTSC_ADJUST: {"tsc_adjust", true},
X86FeatureBMI1: {"bmi1", true},
X86FeatureHLE: {"hle", true},
X86FeatureAVX2: {"avx2", true},
X86FeatureSMEP: {"smep", true},
X86FeatureBMI2: {"bmi2", true},
X86FeatureERMS: {"erms", true},
X86FeatureINVPCID: {"invpcid", true},
X86FeatureRTM: {"rtm", true},
X86FeatureCQM: {"cqm", true},
X86FeatureMPX: {"mpx", true},
X86FeatureRDT: {"rdt_a", true},
X86FeatureAVX512F: {"avx512f", true},
X86FeatureAVX512DQ: {"avx512dq", true},
X86FeatureRDSEED: {"rdseed", true},
X86FeatureADX: {"adx", true},
X86FeatureSMAP: {"smap", true},
X86FeatureCLWB: {"clwb", true},
X86FeatureAVX512PF: {"avx512pf", true},
X86FeatureAVX512ER: {"avx512er", true},
X86FeatureAVX512CD: {"avx512cd", true},
X86FeatureSHA: {"sha_ni", true},
X86FeatureAVX512BW: {"avx512bw", true},
X86FeatureAVX512VL: {"avx512vl", true},
X86FeatureFDP_EXCPTN_ONLY: {"fdp_excptn_only", false},
X86FeatureFPCSDS: {"fpcsds", false},
X86FeatureIPT: {"ipt", false},
X86FeatureCLFLUSHOPT: {"clfushopt", false},
// Block 3.
X86FeatureAVX512VBMI: {"avx512vbmi", true},
X86FeatureUMIP: {"umip", true},
X86FeaturePKU: {"pku", true},
X86FeatureOSPKE: {"ospke", true},
X86FeatureWAITPKG: {"waitpkg", true},
X86FeatureAVX512_VBMI2: {"avx512_vbmi2", true},
X86FeatureGFNI: {"gfni", true},
X86FeatureCET_SS: {"cet_ss", false},
X86FeatureVAES: {"vaes", true},
X86FeatureVPCLMULQDQ: {"vpclmulqdq", true},
X86FeatureAVX512_VNNI: {"avx512_vnni", true},
X86FeatureAVX512_BITALG: {"avx512_bitalg", true},
X86FeatureTME: {"tme", true},
X86FeatureAVX512_VPOPCNTDQ: {"avx512_vpopcntdq", true},
X86FeatureLA57: {"la57", true},
X86FeatureRDPID: {"rdpid", true},
X86FeatureCLDEMOTE: {"cldemote", true},
X86FeatureMOVDIRI: {"movdiri", true},
X86FeatureMOVDIR64B: {"movdir64b", true},
X86FeaturePREFETCHWT1: {"prefetchwt1", false},
// Block 4.
X86FeatureXSAVEOPT: {"xsaveopt", true},
X86FeatureXSAVEC: {"xsavec", true},
X86FeatureXGETBV1: {"xgetbv1", true},
X86FeatureXSAVES: {"xsaves", true},
// Block 5.
X86FeatureLAHF64: {"lahf_lm", true}, // LAHF/SAHF in long mode.
X86FeatureCMP_LEGACY: {"cmp_legacy", true},
X86FeatureSVM: {"svm", true},
X86FeatureEXTAPIC: {"extapic", true},
X86FeatureCR8_LEGACY: {"cr8_legacy", true},
X86FeatureLZCNT: {"abm", true}, // Advanced bit manipulation.
X86FeatureSSE4A: {"sse4a", true},
X86FeatureMISALIGNSSE: {"misalignsse", true},
X86FeaturePREFETCHW: {"3dnowprefetch", true},
X86FeatureOSVW: {"osvw", true},
X86FeatureIBS: {"ibs", true},
X86FeatureXOP: {"xop", true},
X86FeatureSKINIT: {"skinit", true},
X86FeatureWDT: {"wdt", true},
X86FeatureLWP: {"lwp", true},
X86FeatureFMA4: {"fma4", true},
X86FeatureTCE: {"tce", true},
X86FeatureTBM: {"tbm", true},
X86FeatureTOPOLOGY: {"topoext", true},
X86FeaturePERFCTR_CORE: {"perfctr_core", true},
X86FeaturePERFCTR_NB: {"perfctr_nb", true},
X86FeatureBPEXT: {"bpext", true},
X86FeaturePERFCTR_TSC: {"ptsc", true},
X86FeaturePERFCTR_LLC: {"perfctr_llc", true},
X86FeatureMWAITX: {"mwaitx", true},
X86FeatureADMSKEXTN: {"ad_mask_extn", false},
// Block 6.
X86FeatureSYSCALL: {"syscall", true},
X86FeatureNX: {"nx", true},
X86FeatureMMXEXT: {"mmxext", true},
X86FeatureFXSR_OPT: {"fxsr_opt", true},
X86FeatureGBPAGES: {"pdpe1gb", true},
X86FeatureRDTSCP: {"rdtscp", true},
X86FeatureLM: {"lm", true},
X86Feature3DNOWEXT: {"3dnowext", true},
X86Feature3DNOW: {"3dnow", true},
// Block 7.
X86FeatureAVX512_4VNNIW: {"avx512_4vnniw", true},
X86FeatureAVX512_4FMAPS: {"avx512_4fmaps", true},
X86FeatureFSRM: {"fsrm", true},
X86FeatureAVX512_VP2INTERSECT: {"avx512_vp2intersect", true},
X86FeatureSRBDS_CTRL: {"srbds_ctrl", false},
X86FeatureMD_CLEAR: {"md_clear", true},
X86FeatureRTM_ALWAYS_ABORT: {"rtm_always_abort", false},
X86FeatureTSX_FORCE_ABORT: {"tsx_force_abort", false},
X86FeatureSERIALIZE: {"serialize", true},
X86FeatureHYBRID_CPU: {"hybrid_cpu", false},
X86FeatureTSXLDTRK: {"tsxldtrk", true},
X86FeaturePCONFIG: {"pconfig", true},
X86FeatureARCH_LBR: {"arch_lbr", true},
X86FeatureIBT: {"ibt", true},
X86FeatureAMX_BF16: {"amx_bf16", true},
X86FeatureAVX512_FP16: {"avx512_fp16", true},
X86FeatureAMX_TILE: {"amx_tile", true},
X86FeatureAMX_INT8: {"amx_int8", true},
X86FeatureSPEC_CTRL: {"spec_ctrl", false},
X86FeatureINTEL_STIBP: {"intel_stibp", false},
X86FeatureFLUSH_L1D: {"flush_l1d", true},
X86FeatureARCH_CAPABILITIES: {"arch_capabilities", true},
X86FeatureCORE_CAPABILITIES: {"core_capabilities", false},
X86FeatureSPEC_CTRL_SSBD: {"spec_ctrl_ssbd", false},
}
// linuxBlockOrder defines the order in which linux organizes the feature
// blocks. Linux also tracks feature bits in 32-bit blocks, but in an order
// which doesn't match well here, so for the /proc/cpuinfo generation we simply
// re-map the blocks to Linux's ordering and then go through the bits in each
// block.
var linuxBlockOrder = []block{1, 6, 0, 5, 2, 4, 3, 7}
func archFlagOrder(fn func(Feature)) {
for _, b := range linuxBlockOrder {
for i := 0; i < blockSize; i++ {
f := featureID(b, i)
if _, ok := allFeatures[f]; ok {
fn(f)
}
}
}
}