mirror of
https://github.com/Leseratte10/acsm-calibre-plugin
synced 2024-12-26 09:58:09 +01:00
158 lines
5.7 KiB
Python
158 lines
5.7 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
#
|
||
|
# Copyright (c) 2018 Anders Høst
|
||
|
#
|
||
|
|
||
|
# Licensed under MIT
|
||
|
# See https://github.com/flababah/cpuid.py/blob/master/cpuid.py
|
||
|
|
||
|
from __future__ import print_function
|
||
|
|
||
|
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
|
||
|
|
||
|
# 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
|
||
|
]
|
||
|
|
||
|
_WINDOWS_64_OPC = [
|
||
|
0x53, # push %rbx
|
||
|
0x89, 0xd0, # mov %edx,%eax
|
||
|
0x49, 0x89, 0xc9, # mov %rcx,%r9
|
||
|
0x44, 0x89, 0xc1, # mov %r8d,%ecx
|
||
|
0x0f, 0xa2, # cpuid
|
||
|
0x41, 0x89, 0x01, # mov %eax,(%r9)
|
||
|
0x41, 0x89, 0x59, 0x04, # mov %ebx,0x4(%r9)
|
||
|
0x41, 0x89, 0x49, 0x08, # mov %ecx,0x8(%r9)
|
||
|
0x41, 0x89, 0x51, 0x0c, # mov %edx,0xc(%r9)
|
||
|
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_windows = os.name == "nt"
|
||
|
is_64bit = ctypes.sizeof(ctypes.c_voidp) == 8
|
||
|
|
||
|
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")
|
||
|
|
||
|
if is_windows:
|
||
|
if is_64bit:
|
||
|
# VirtualAlloc seems to fail under some weird
|
||
|
# circumstances when ctypes.windll.kernel32 is
|
||
|
# used under 64 bit Python. CDLL fixes this.
|
||
|
self.win = ctypes.CDLL("kernel32.dll")
|
||
|
opc = _WINDOWS_64_OPC
|
||
|
else:
|
||
|
# Here ctypes.windll.kernel32 is needed to get the
|
||
|
# right DLL. Otherwise it will fail when running
|
||
|
# 32 bit Python on 64 bit Windows.
|
||
|
self.win = ctypes.windll.kernel32
|
||
|
opc = _CDECL_32_OPC
|
||
|
else:
|
||
|
opc = _POSIX_64_OPC if is_64bit else _CDECL_32_OPC
|
||
|
|
||
|
size = len(opc)
|
||
|
code = (ctypes.c_ubyte * size)(*opc)
|
||
|
|
||
|
if is_windows:
|
||
|
self.win.VirtualAlloc.restype = c_void_p
|
||
|
self.win.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong, ctypes.c_ulong]
|
||
|
self.addr = self.win.VirtualAlloc(None, size, 0x1000, 0x40)
|
||
|
if not self.addr:
|
||
|
raise MemoryError("Could not allocate RWX memory")
|
||
|
else:
|
||
|
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):
|
||
|
if is_windows:
|
||
|
self.win.VirtualFree.restype = c_long
|
||
|
self.win.VirtualFree.argtypes = [c_void_p, c_size_t, c_ulong]
|
||
|
self.win.VirtualFree(self.addr, 0, 0x8000)
|
||
|
elif self.libc:
|
||
|
# 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__":
|
||
|
def valid_inputs():
|
||
|
cpuid = CPUID()
|
||
|
for eax in (0x0, 0x80000000):
|
||
|
highest, _, _, _ = cpuid(eax)
|
||
|
while eax <= highest:
|
||
|
regs = cpuid(eax)
|
||
|
yield (eax, regs)
|
||
|
eax += 1
|
||
|
|
||
|
print(" ".join(x.ljust(8) for x in ("CPUID", "A", "B", "C", "D")).strip())
|
||
|
for eax, regs in valid_inputs():
|
||
|
print("%08x" % eax, " ".join("%08x" % reg for reg in regs))
|
||
|
|