github.com/iDigitalFlame/xmt@v0.5.4/device/cpu.go (about)

     1  //go:build amd64 || 386
     2  // +build amd64 386
     3  
     4  // Copyright (C) 2020 - 2023 iDigitalFlame
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    18  //
    19  
    20  package device
    21  
    22  // IsVirtual attempts to determine if the underlying device is inside a container
    23  // or is running in a virtual machine.
    24  //
    25  // If this returns true, it is suspected that a non-physical device is present.
    26  //
    27  // Different versions of this function are used depending on CPU type.
    28  //   - For x86/x64/amd64 this function uses the CPUID instruction.
    29  //     See https://en.wikipedia.org/wiki/CPUID for more info.
    30  func IsVirtual() bool {
    31  	_, _, c, d := cpuid(0x1, 0) // CPU Features
    32  	if c&(1<<31) != 0 {         // Hypervisor flag
    33  		return true
    34  	}
    35  	t := d&(1<<29) == 0 // Thermal monitor
    36  	// Save this one for later, most VMs /don't/ have thermal monitoring but we
    37  	// will check all other options first.
    38  	_, b, c, d := cpuid(0x40000000, 0) // Hypervisor CPUID
    39  	if d == 0 || b == 0 || c == 0 {
    40  		if !t {
    41  			// Fall back to thermal if CPUID returns '0' as this can be overridden
    42  			// in some hypervisors.
    43  			a, b, c, _ := cpuid(0x6, 0) // Thermal and power management
    44  			if t = a <= 4 && (b == 0 || c == 0); !t {
    45  				return false
    46  			}
    47  		}
    48  	}
    49  	// We don't need to check the name /but/ we're just making sure that the
    50  	// name is not all zero's first.
    51  	n := [16]byte{
    52  		byte((b >> 0)), byte((b >> 8)), byte((b >> 16)), byte((b >> 24)),
    53  		byte((c >> 0)), byte((c >> 8)), byte((c >> 16)), byte((c >> 24)),
    54  		byte((d >> 0)), byte((d >> 8)), byte((d >> 16)), byte((d >> 24)),
    55  	}
    56  	var z int
    57  	for i := range n {
    58  		if n[i] > 0 {
    59  			continue
    60  		}
    61  		z++
    62  	}
    63  	// Less than 10 chars are zeros.
    64  	if z < 10 {
    65  		return true
    66  	}
    67  	// Fallback to temp.
    68  	return t
    69  }
    70  
    71  // cpuid is implemented in ASM file "cpu.s"
    72  func cpuid(arg1 uint32, arg2 uint32) (uint32, uint32, uint32, uint32)