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