summaryrefslogtreecommitdiff
path: root/bin
diff options
authorJeff Lane <jeffrey.lane@canonical.com>2019-05-21 12:31:37 -0400
committerJeff Lane <jeffrey.lane@canonical.com>2019-05-21 12:31:37 -0400
commit4026ffa493af2479ae842b6efbaeffb29968f87d (patch)
tree01e3753c5cf6b2ef1502dd886c2b7fe4ac63da6a /bin
parentc21c401222f959570815b6863edfa470072b806a (diff)
Added CPUID script and jobs for server cert to attempt to identify CPU families
Diffstat (limited to 'bin')
-rwxr-xr-xbin/cpuid.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/bin/cpuid.py b/bin/cpuid.py
new file mode 100755
index 0000000..de7dce3
--- /dev/null
+++ b/bin/cpuid.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+
+# The MIT License (MIT)
+#
+# Copyright (c) 2014 Anders Høst
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Modifications: 2019 Jeffrey Lane (jeffrey.lane@canonical.com)
+
+import platform
+import os
+import ctypes
+from ctypes import c_uint32, c_int, c_long, c_ulong, c_size_t, c_void_p, POINTER, CFUNCTYPE
+from subprocess import check_output
+
+# Posix x86_64:
+# Three first call registers : RDI, RSI, RDX
+# Volatile registers : RAX, RCX, RDX, RSI, RDI, R8-11
+
+# Windows x86_64:
+# Three first call registers : RCX, RDX, R8
+# Volatile registers : RAX, RCX, RDX, R8-11
+
+# cdecl 32 bit:
+# Three first call registers : Stack (%esp)
+# Volatile registers : EAX, ECX, EDX
+
+_POSIX_64_OPC = [
+ 0x53, # push %rbx
+ 0x89, 0xf0, # mov %esi,%eax
+ 0x89, 0xd1, # mov %edx,%ecx
+ 0x0f, 0xa2, # cpuid
+ 0x89, 0x07, # mov %eax,(%rdi)
+ 0x89, 0x5f, 0x04, # mov %ebx,0x4(%rdi)
+ 0x89, 0x4f, 0x08, # mov %ecx,0x8(%rdi)
+ 0x89, 0x57, 0x0c, # mov %edx,0xc(%rdi)
+ 0x5b, # pop %rbx
+ 0xc3 # retq
+]
+
+_CDECL_32_OPC = [
+ 0x53, # push %ebx
+ 0x57, # push %edi
+ 0x8b, 0x7c, 0x24, 0x0c, # mov 0xc(%esp),%edi
+ 0x8b, 0x44, 0x24, 0x10, # mov 0x10(%esp),%eax
+ 0x8b, 0x4c, 0x24, 0x14, # mov 0x14(%esp),%ecx
+ 0x0f, 0xa2, # cpuid
+ 0x89, 0x07, # mov %eax,(%edi)
+ 0x89, 0x5f, 0x04, # mov %ebx,0x4(%edi)
+ 0x89, 0x4f, 0x08, # mov %ecx,0x8(%edi)
+ 0x89, 0x57, 0x0c, # mov %edx,0xc(%edi)
+ 0x5f, # pop %edi
+ 0x5b, # pop %ebx
+ 0xc3 # ret
+]
+
+is_64bit = ctypes.sizeof(ctypes.c_voidp) == 8
+
+CPUIDS = {
+ "Amber Lake": ['0x806e9'],
+ "AMD Opteron 6100":['0x100f91'],
+ "Broadwell": ['0x4067', '0x306d4', '0x5066', '0x406f'],
+ "Canon Lake": ['0x6066'],
+ "Cascade Lake": ['0x50655', '0x50656', '0x50657'],
+ "Coffee Lake": ['0x806ea', '0x906ea', '0x906eb', '0x906ec'],
+ "Haswell": ['0x306c', '0x4065', '0x4066', '0x306f'],
+ "Ice Lake": ['0x706e'],
+ "Ivy Bridge": ['0x306a', '0x306e'],
+ "Kaby Lake": ['0x806e9', '0x906e9'],
+ "Knights Landing": ['0x5067'],
+ "Knights Mill": ['0x8065'],
+ "Nehalem": ['0x106a', '0x106e5', '0x206e'],
+ "Pineview": ['0x106ca'],
+ "Penryn": ['0x1067a'],
+ "Sandy Bridge": ['0x206a', '0x206d'],
+ "Skylake": ['0x406e3', '0x506e3', '0x50654', '0x50652'],
+ "Westmere": ['0x2065', '0x206c', '0x206f'],
+ "Whisky Lake": ['0x806eb', '0x806ec'],
+ }
+
+class CPUID_struct(ctypes.Structure):
+ _fields_ = [(r, c_uint32) for r in ("eax", "ebx", "ecx", "edx")]
+
+class CPUID(object):
+ def __init__(self):
+ if platform.machine() not in ("AMD64", "x86_64", "x86", "i686"):
+ raise SystemError("Only available for x86")
+
+ opc = _POSIX_64_OPC if is_64bit else _CDECL_32_OPC
+
+ size = len(opc)
+ code = (ctypes.c_ubyte * size)(*opc)
+
+ self.libc = ctypes.cdll.LoadLibrary(None)
+ self.libc.valloc.restype = ctypes.c_void_p
+ self.libc.valloc.argtypes = [ctypes.c_size_t]
+ self.addr = self.libc.valloc(size)
+ if not self.addr:
+ raise MemoryError("Could not allocate memory")
+
+ self.libc.mprotect.restype = c_int
+ self.libc.mprotect.argtypes = [c_void_p, c_size_t, c_int]
+ ret = self.libc.mprotect(self.addr, size, 1 | 2 | 4)
+ if ret != 0:
+ raise OSError("Failed to set RWX")
+
+
+ ctypes.memmove(self.addr, code, size)
+
+ func_type = CFUNCTYPE(None, POINTER(CPUID_struct), c_uint32, c_uint32)
+ self.func_ptr = func_type(self.addr)
+
+ def __call__(self, eax, ecx=0):
+ struct = CPUID_struct()
+ self.func_ptr(struct, eax, ecx)
+ return struct.eax, struct.ebx, struct.ecx, struct.edx
+
+ def __del__(self):
+ # Seems to throw exception when the program ends and
+ # libc is cleaned up before the object?
+ self.libc.free.restype = None
+ self.libc.free.argtypes = [c_void_p]
+ self.libc.free(self.addr)
+
+if __name__ == "__main__":
+ cpuid = CPUID()
+ cpu = cpuid(1)
+ ## Lets play Guess The CPU!
+
+ # First lets get the name from /proc/cpuinfo
+ cpu_data = check_output('lscpu', universal_newlines=True).split('\n')
+ for line in cpu_data:
+ if line.startswith('Model name:'):
+ print("CPU Model: %s" % line.split(':')[1].lstrip())
+
+
+ my_id = (hex(cpu[0]))
+ complete = False
+ for key in CPUIDS.keys():
+ for value in CPUIDS[key]:
+ if value in my_id:
+ print("CPUID: %s which appears to be a %s processor" %
+ (my_id,key))
+ complete = True
+
+ if not complete:
+ print("Unable to determine CPU Family for this CPUID: %s" % my_id)
+