cpuid_arm64.go raw

   1  // Copyright 2020 The gVisor Authors.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License");
   4  // you may not use this file except in compliance with the License.
   5  // You may obtain a copy of the License at
   6  //
   7  //     http://www.apache.org/licenses/LICENSE-2.0
   8  //
   9  // Unless required by applicable law or agreed to in writing, software
  10  // distributed under the License is distributed on an "AS IS" BASIS,
  11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12  // See the License for the specific language governing permissions and
  13  // limitations under the License.
  14  
  15  //go:build arm64
  16  // +build arm64
  17  
  18  package cpuid
  19  
  20  import (
  21  	"fmt"
  22  	"io"
  23  )
  24  
  25  // FeatureSet for ARM64 is defined as a static set of bits.
  26  //
  27  // ARM64 doesn't have a CPUID equivalent, which means it has no architected
  28  // discovery mechanism for hardware features available to userspace code at
  29  // EL0. The kernel exposes the presence of these features to userspace through
  30  // a set of flags(HWCAP/HWCAP2) bits, exposed in the auxiliary vector. See
  31  // Documentation/arm64/elf_hwcaps.rst for more info.
  32  //
  33  // Currently, only the HWCAP bits are supported.
  34  //
  35  // +stateify savable
  36  type FeatureSet struct {
  37  	hwCap      hwCap
  38  	cpuFreqMHz float64
  39  	cpuImplHex uint64
  40  	cpuArchDec uint64
  41  	cpuVarHex  uint64
  42  	cpuPartHex uint64
  43  	cpuRevDec  uint64
  44  }
  45  
  46  // CPUImplementer is part of the processor signature.
  47  func (fs FeatureSet) CPUImplementer() uint8 {
  48  	return uint8(fs.cpuImplHex)
  49  }
  50  
  51  // CPUArchitecture is part of the processor signature.
  52  func (fs FeatureSet) CPUArchitecture() uint8 {
  53  	return uint8(fs.cpuArchDec)
  54  }
  55  
  56  // CPUVariant is part of the processor signature.
  57  func (fs FeatureSet) CPUVariant() uint8 {
  58  	return uint8(fs.cpuVarHex)
  59  }
  60  
  61  // CPUPartnum is part of the processor signature.
  62  func (fs FeatureSet) CPUPartnum() uint16 {
  63  	return uint16(fs.cpuPartHex)
  64  }
  65  
  66  // CPURevision is part of the processor signature.
  67  func (fs FeatureSet) CPURevision() uint8 {
  68  	return uint8(fs.cpuRevDec)
  69  }
  70  
  71  // ExtendedStateSize returns the number of bytes needed to save the "extended
  72  // state" for this processor and the boundary it must be aligned to. Extended
  73  // state includes floating point(NEON) registers, and other cpu state that's not
  74  // associated with the normal task context.
  75  func (fs FeatureSet) ExtendedStateSize() (size, align uint) {
  76  	// ARMv8 provide 32x128bits NEON registers.
  77  	//
  78  	// Ref arch/arm64/include/uapi/asm/ptrace.h
  79  	// struct user_fpsimd_state {
  80  	//        __uint128_t     vregs[32];
  81  	//        __u32           fpsr;
  82  	//        __u32           fpcr;
  83  	//        __u32           __reserved[2];
  84  	// };
  85  	return 528, 16
  86  }
  87  
  88  // HasFeature checks for the presence of a feature.
  89  func (fs FeatureSet) HasFeature(feature Feature) bool {
  90  	return fs.hwCap.hwCap1&(1<<feature) != 0
  91  }
  92  
  93  // WriteCPUInfoTo is to generate a section of one cpu in /proc/cpuinfo. This is
  94  // a minimal /proc/cpuinfo, and the bogomips field is simply made up.
  95  func (fs FeatureSet) WriteCPUInfoTo(cpu, numCPU uint, w io.Writer) {
  96  	fmt.Fprintf(w, "processor\t: %d\n", cpu)
  97  	fmt.Fprintf(w, "BogoMIPS\t: %.02f\n", fs.cpuFreqMHz) // It's bogus anyway.
  98  	fmt.Fprintf(w, "Features\t\t: %s\n", fs.FlagString())
  99  	fmt.Fprintf(w, "CPU implementer\t: 0x%x\n", fs.cpuImplHex)
 100  	fmt.Fprintf(w, "CPU architecture\t: %d\n", fs.cpuArchDec)
 101  	fmt.Fprintf(w, "CPU variant\t: 0x%x\n", fs.cpuVarHex)
 102  	fmt.Fprintf(w, "CPU part\t: 0x%x\n", fs.cpuPartHex)
 103  	fmt.Fprintf(w, "CPU revision\t: %d\n", fs.cpuRevDec)
 104  	fmt.Fprintf(w, "\n") // The /proc/cpuinfo file ends with an extra newline.
 105  }
 106  
 107  // archCheckHostCompatible is a noop on arm64.
 108  func (FeatureSet) archCheckHostCompatible(FeatureSet) error {
 109  	return nil
 110  }
 111  
 112  // AllowedHWCap1 returns the HWCAP1 bits that the guest is allowed to depend
 113  // on.
 114  func (fs FeatureSet) AllowedHWCap1() uint64 {
 115  	// Pick a set of safe HWCAPS to expose. These do not rely on cpu state
 116  	// that gvisor does not restore after a context switch.
 117  	allowed := HWCAP_AES |
 118  		HWCAP_ASIMD |
 119  		HWCAP_ASIMDDP |
 120  		HWCAP_ASIMDFHM |
 121  		HWCAP_ASIMDHP |
 122  		HWCAP_ASIMDRDM |
 123  		HWCAP_ATOMICS |
 124  		HWCAP_CRC32 |
 125  		HWCAP_DCPOP |
 126  		HWCAP_DIT |
 127  		HWCAP_EVTSTRM |
 128  		HWCAP_FCMA |
 129  		HWCAP_FLAGM |
 130  		HWCAP_FP |
 131  		HWCAP_FPHP |
 132  		HWCAP_ILRCPC |
 133  		HWCAP_JSCVT |
 134  		HWCAP_LRCPC |
 135  		HWCAP_PMULL |
 136  		HWCAP_SHA1 |
 137  		HWCAP_SHA2 |
 138  		HWCAP_SHA3 |
 139  		HWCAP_SHA512 |
 140  		HWCAP_SM3 |
 141  		HWCAP_SM4 |
 142  		HWCAP_USCAT
 143  	return fs.hwCap.hwCap1 & uint64(allowed)
 144  }
 145  
 146  // AllowedHWCap2 returns the HWCAP2 bits that the guest is allowed to depend
 147  // on.
 148  func (fs FeatureSet) AllowedHWCap2() uint64 {
 149  	// We don't expose anything here yet, but this could be expanded to
 150  	// include features do not rely on cpu state that is not restored after
 151  	// a context switch.
 152  	allowed := 0
 153  	return fs.hwCap.hwCap2 & uint64(allowed)
 154  }
 155