diff --git a/libcpuid/Makefile.am b/libcpuid/Makefile.am index 7fc44bf..df0b7f9 100644 --- a/libcpuid/Makefile.am +++ b/libcpuid/Makefile.am @@ -12,7 +12,8 @@ libcpuid_la_SOURCES = \ recog_amd.c \ rdtsc.c \ asm-bits.c \ - libcpuid_util.c + libcpuid_util.c \ + rdmsr.c libcpuid_la_DEPENDENCIES = \ $(srcdir)/libcpuid.sym diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index fa1ac15..0791bc3 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -343,11 +343,12 @@ typedef enum { ERR_BADFMT = -5, /*!< "Bad file format" */ ERR_NOT_IMP = -6, /*!< "Not implemented" */ ERR_CPU_UNKN = -7, /*!< "Unsupported processor" */ - ERR_NO_RDMSR = -8, /*!< "RDMSR instruction is not supported" */ - ERR_NO_DRIVER= -9, /*!< "RDMSR driver error (generic)" */ - ERR_NO_PERMS = -10, /*!< "No permissions to install RDMSR driver" */ - ERR_EXTRACT = -11, /*!< "Cannot extract RDMSR driver (read only media?)" */ - ERR_HANDLE = -12, /*!< "Bad handle" */ + ERR_NO_RDMSR = -8, /*!< "RDMSR instruction is not supported" */ + ERR_NO_DRIVER= -9, /*!< "RDMSR driver error (generic)" */ + ERR_NO_PERMS = -10, /*!< "No permissions to install RDMSR driver" */ + ERR_EXTRACT = -11, /*!< "Cannot extract RDMSR driver (read only media?)" */ + ERR_HANDLE = -12, /*!< "Bad handle" */ + ERR_INVMSR = -13, /*!< "Invalid MSR" */ } cpu_error_t; /** diff --git a/libcpuid/libcpuid.sym b/libcpuid/libcpuid.sym index 5b6af40..7375ba4 100644 --- a/libcpuid/libcpuid.sym +++ b/libcpuid/libcpuid.sym @@ -19,3 +19,7 @@ cpuid_set_warn_function cpuid_set_verbosiness_level cpuid_get_cpu_list cpuid_free_cpu_list +cpu_msr_driver_open +cpu_rdmsr +cpu_msrinfo +cpu_msr_driver_close diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 918b970..3e7ec6f 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -23,6 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _XOPEN_SOURCE 500 #include #include #include "libcpuid.h" @@ -30,25 +31,81 @@ #include "libcpuid_util.h" #ifndef _WIN32 -/* On Linux and Apple, we still do not support RDMSR, so supply dummy struct +# ifdef __APPLE__ +/* On Darwin, we still do not support RDMSR, so supply dummy struct and functions */ -struct msr_driver_t { int dummy; } +struct msr_driver_t { int dummy; }; struct msr_driver_t* cpu_msr_driver_open(void) { - set_error(ERR_NOT_IMPL); + set_error(ERR_NOT_IMP); return NULL; } int cpu_rdmsr(struct msr_driver_t* driver, int msr_index, uint64_t* result) { - return set_error(ERR_NOT_IMPL); + return set_error(ERR_NOT_IMP); } int cpu_msr_driver_close(struct msr_driver_t* driver) { - return set_error(ERR_NOT_IMPL); + return set_error(ERR_NOT_IMP); } +int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) +{ + return set_error(ERR_NOT_IMP); +} +# else /* __APPLE__ */ +/* Assuming linux with /dev/cpu/x/msr: */ +#include +#include +#include +#include +#include +#include +struct msr_driver_t { int fd; }; +static int rdmsr_supported(void); +struct msr_driver_t* cpu_msr_driver_open(void) +{ + struct msr_driver_t* handle; + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + int fd = open("/dev/cpu/0/msr", O_RDONLY); + if (fd < 0) { + if (errno == EIO) { + set_error(ERR_NO_RDMSR); + return NULL; + } + set_error(ERR_NO_DRIVER); + return NULL; + } + handle = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + handle->fd = fd; + return handle; +} +int cpu_rdmsr(struct msr_driver_t* driver, int msr_index, uint64_t* result) +{ + ssize_t ret; + + if (!driver || driver->fd < 0) + return set_error(ERR_HANDLE); + ret = pread(driver->fd, result, 8, msr_index * 8); + if (ret != 8) + return set_error(ERR_INVMSR); + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + if (drv && drv->fd >= 0) { + close(drv->fd); + free(drv); + } + return 0; +} +# endif /* __APPLE__ */ #else /* _WIN32 */ #include @@ -60,9 +117,9 @@ extern int cc_x64driver_code_size; struct msr_driver_t { char driver_path[MAX_PATH + 1]; SC_HANDLE scManager; - volatile SC_HANDLE scDriver; - HANDLE hhDriver; - OVERLAPPED ovl; + volatile SC_HANDLE scDriver; + HANDLE hhDriver; + OVERLAPPED ovl; int errorcode; }; @@ -93,7 +150,7 @@ struct msr_driver_t* cpu_msr_driver_open(void) } status = load_driver(drv); - if (!DeleteFile(drv->driver_path)) + if (!DeleteFile(drv->driver_path)) debugf(1, "Deleting temporary driver file failed.\n"); if (!status) { set_error(drv->errorcode ? drv->errorcode : ERR_NO_DRIVER); @@ -103,22 +160,16 @@ struct msr_driver_t* cpu_msr_driver_open(void) return drv; } -static int rdmsr_supported(void) +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +static BOOL is_running_x64(void) { - struct cpu_id_t* id = get_cached_cpuid(); - return id->flags[CPU_FEATURE_MSR]; -} + BOOL bIsWow64 = FALSE; -typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); -static BOOL is_running_x64(void) -{ - BOOL bIsWow64 = FALSE; - - LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(__TEXT("kernel32")), "IsWow64Process"); - if(NULL != fnIsWow64Process) - fnIsWow64Process(GetCurrentProcess(), &bIsWow64); - return bIsWow64; -} + LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(__TEXT("kernel32")), "IsWow64Process"); + if(NULL != fnIsWow64Process) + fnIsWow64Process(GetCurrentProcess(), &bIsWow64); + return bIsWow64; +} static int extract_driver(struct msr_driver_t* driver) @@ -137,149 +188,149 @@ static int extract_driver(struct msr_driver_t* driver) return 1; } -static BOOL wait_for_service_state(SC_HANDLE hService, DWORD dwDesiredState, SERVICE_STATUS *lpsrvStatus){ - BOOL fOK = FALSE; - DWORD dwWaitHint; - - if(hService != NULL){ - while(TRUE){ - fOK = QueryServiceStatus(hService, lpsrvStatus); - if(!fOK) - break; - if(lpsrvStatus->dwCurrentState == dwDesiredState) - break; - - dwWaitHint = lpsrvStatus->dwWaitHint / 10; // Poll 1/10 of the wait hint - if (dwWaitHint < 1000) - dwWaitHint = 1000; // At most once per second - if (dwWaitHint > 10000) - dwWaitHint = 10000; // At least every 10 seconds - Sleep(dwWaitHint); - } - } - - return fOK; -} +static BOOL wait_for_service_state(SC_HANDLE hService, DWORD dwDesiredState, SERVICE_STATUS *lpsrvStatus){ + BOOL fOK = FALSE; + DWORD dwWaitHint; + + if(hService != NULL){ + while(TRUE){ + fOK = QueryServiceStatus(hService, lpsrvStatus); + if(!fOK) + break; + if(lpsrvStatus->dwCurrentState == dwDesiredState) + break; + + dwWaitHint = lpsrvStatus->dwWaitHint / 10; // Poll 1/10 of the wait hint + if (dwWaitHint < 1000) + dwWaitHint = 1000; // At most once per second + if (dwWaitHint > 10000) + dwWaitHint = 10000; // At least every 10 seconds + Sleep(dwWaitHint); + } + } + + return fOK; +} static int load_driver(struct msr_driver_t* drv) { - LPTSTR lpszInfo = __TEXT("RDMSR Executor Driver"); - USHORT uLen = 0; - SERVICE_STATUS srvStatus = {0}; - BOOL fRunning = FALSE; - DWORD dwLastError; - LPTSTR lpszDriverServiceName = __TEXT("TmpRdr"); - TCHAR lpszDriverName[] = __TEXT("\\\\.\\Global\\TmpRdr"); - - if((LPVOID)(drv->scManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL) { - drv->scDriver = CreateService(drv->scManager, lpszDriverServiceName, lpszInfo, SERVICE_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, - drv->driver_path, NULL, NULL, NULL, NULL, NULL); - if(drv->scDriver == NULL){ - switch(dwLastError = GetLastError()){ - case ERROR_SERVICE_EXISTS: - case ERROR_SERVICE_MARKED_FOR_DELETE:{ - LPQUERY_SERVICE_CONFIG lpqsc; - DWORD dwBytesNeeded; - - drv->scDriver = OpenService(drv->scManager, lpszDriverServiceName, SERVICE_ALL_ACCESS); - if(drv->scDriver == NULL){ - debugf(1, "Error opening service: %d\n", GetLastError()); - break; - } - - QueryServiceConfig(drv->scDriver, NULL, 0, &dwBytesNeeded); - if((dwLastError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER){ - lpqsc = calloc(1, dwBytesNeeded); - if(!QueryServiceConfig(drv->scDriver, lpqsc, dwBytesNeeded, &dwBytesNeeded)){ - free(lpqsc); - debugf(1, "Error query service config(adjusted buffer): %d\n", GetLastError()); - goto clean_up; - } - else{ - free(lpqsc); - } - } - else{ - debugf(1, "Error query service config: %d\n", dwLastError); - goto clean_up; - } - - break; - } - case ERROR_ACCESS_DENIED: - drv->errorcode = ERR_NO_PERMS; - break; - default: - debugf(1, "Create driver service failed: %d\n", dwLastError); - break; - } - } - if(drv->scDriver != NULL){ - if(StartService(drv->scDriver, 0, NULL)){ - if(!wait_for_service_state(drv->scDriver, SERVICE_RUNNING, &srvStatus)){ - debugf(1, "Driver load failed.\n"); - DeleteService(drv->scDriver); - CloseServiceHandle(drv->scManager); - drv->scDriver = NULL; - goto clean_up; - } else { - fRunning = TRUE; - } - } else{ - if((dwLastError = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING) - fRunning = TRUE; - else{ - debugf(1, "Driver start failed.\n"); - DeleteService(drv->scDriver); - CloseServiceHandle(drv->scManager); - drv->scDriver = NULL; - goto clean_up; - } - - } - if(fRunning) - debugf(1, "Driver already running.\n"); - else - debugf(1, "Driver loaded.\n"); - CloseServiceHandle(drv->scManager); - drv->hhDriver = CreateFile(lpszDriverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - drv->ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - return 1; - } - } else { - debugf(1, "Open SCM failed: %d\n", GetLastError()); - } - -clean_up: - if(drv->scManager != NULL){ - CloseServiceHandle(drv->scManager); - drv->scManager = 0; // pointless - } - if(drv->scDriver != NULL){ - if(!DeleteService(drv->scDriver)) - debugf(1, "Delete driver service failed: %d\n", GetLastError()); - CloseServiceHandle(drv->scDriver); - drv->scDriver = 0; - } - - return 0; + LPTSTR lpszInfo = __TEXT("RDMSR Executor Driver"); + USHORT uLen = 0; + SERVICE_STATUS srvStatus = {0}; + BOOL fRunning = FALSE; + DWORD dwLastError; + LPTSTR lpszDriverServiceName = __TEXT("TmpRdr"); + TCHAR lpszDriverName[] = __TEXT("\\\\.\\Global\\TmpRdr"); + + if((LPVOID)(drv->scManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL) { + drv->scDriver = CreateService(drv->scManager, lpszDriverServiceName, lpszInfo, SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, + drv->driver_path, NULL, NULL, NULL, NULL, NULL); + if(drv->scDriver == NULL){ + switch(dwLastError = GetLastError()){ + case ERROR_SERVICE_EXISTS: + case ERROR_SERVICE_MARKED_FOR_DELETE:{ + LPQUERY_SERVICE_CONFIG lpqsc; + DWORD dwBytesNeeded; + + drv->scDriver = OpenService(drv->scManager, lpszDriverServiceName, SERVICE_ALL_ACCESS); + if(drv->scDriver == NULL){ + debugf(1, "Error opening service: %d\n", GetLastError()); + break; + } + + QueryServiceConfig(drv->scDriver, NULL, 0, &dwBytesNeeded); + if((dwLastError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER){ + lpqsc = calloc(1, dwBytesNeeded); + if(!QueryServiceConfig(drv->scDriver, lpqsc, dwBytesNeeded, &dwBytesNeeded)){ + free(lpqsc); + debugf(1, "Error query service config(adjusted buffer): %d\n", GetLastError()); + goto clean_up; + } + else{ + free(lpqsc); + } + } + else{ + debugf(1, "Error query service config: %d\n", dwLastError); + goto clean_up; + } + + break; + } + case ERROR_ACCESS_DENIED: + drv->errorcode = ERR_NO_PERMS; + break; + default: + debugf(1, "Create driver service failed: %d\n", dwLastError); + break; + } + } + if(drv->scDriver != NULL){ + if(StartService(drv->scDriver, 0, NULL)){ + if(!wait_for_service_state(drv->scDriver, SERVICE_RUNNING, &srvStatus)){ + debugf(1, "Driver load failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } else { + fRunning = TRUE; + } + } else{ + if((dwLastError = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING) + fRunning = TRUE; + else{ + debugf(1, "Driver start failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } + + } + if(fRunning) + debugf(1, "Driver already running.\n"); + else + debugf(1, "Driver loaded.\n"); + CloseServiceHandle(drv->scManager); + drv->hhDriver = CreateFile(lpszDriverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + drv->ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return 1; + } + } else { + debugf(1, "Open SCM failed: %d\n", GetLastError()); + } + +clean_up: + if(drv->scManager != NULL){ + CloseServiceHandle(drv->scManager); + drv->scManager = 0; // pointless + } + if(drv->scDriver != NULL){ + if(!DeleteService(drv->scDriver)) + debugf(1, "Delete driver service failed: %d\n", GetLastError()); + CloseServiceHandle(drv->scDriver); + drv->scDriver = 0; + } + + return 0; } -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN -#define IOCTL_PROCVIEW_RDMSR CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN +#define IOCTL_PROCVIEW_RDMSR CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) int cpu_rdmsr(struct msr_driver_t* driver, int msr_index, uint64_t* result) { DWORD dwBytesReturned; __int64 msrdata; - SERVICE_STATUS srvStatus = {0}; + SERVICE_STATUS srvStatus = {0}; if (!driver) return set_error(ERR_HANDLE); - DeviceIoControl(driver->hhDriver, IOCTL_PROCVIEW_RDMSR, &msr_index, sizeof(int), &msrdata, sizeof(__int64), &dwBytesReturned, &driver->ovl); + DeviceIoControl(driver->hhDriver, IOCTL_PROCVIEW_RDMSR, &msr_index, sizeof(int), &msrdata, sizeof(__int64), &dwBytesReturned, &driver->ovl); GetOverlappedResult(driver->hhDriver, &driver->ovl, &dwBytesReturned, TRUE); *result = msrdata; return 0; @@ -287,24 +338,33 @@ int cpu_rdmsr(struct msr_driver_t* driver, int msr_index, uint64_t* result) int cpu_msr_driver_close(struct msr_driver_t* drv) { - SERVICE_STATUS srvStatus = {0}; + SERVICE_STATUS srvStatus = {0}; if (drv == NULL) return 0; - if(drv->scDriver != NULL){ - if (drv->hhDriver) CancelIo(drv->hhDriver); - if(drv->ovl.hEvent != NULL) - CloseHandle(drv->ovl.hEvent); - if (drv->hhDriver) CloseHandle(drv->hhDriver); - drv->hhDriver = NULL; - drv->ovl.hEvent = NULL; - if (ControlService(drv->scDriver, SERVICE_CONTROL_STOP, &srvStatus)){ - if (wait_for_service_state(drv->scDriver, SERVICE_STOPPED, &srvStatus)){ - DeleteService(drv->scDriver); - } - } - } + if(drv->scDriver != NULL){ + if (drv->hhDriver) CancelIo(drv->hhDriver); + if(drv->ovl.hEvent != NULL) + CloseHandle(drv->ovl.hEvent); + if (drv->hhDriver) CloseHandle(drv->hhDriver); + drv->hhDriver = NULL; + drv->ovl.hEvent = NULL; + if (ControlService(drv->scDriver, SERVICE_CONTROL_STOP, &srvStatus)){ + if (wait_for_service_state(drv->scDriver, SERVICE_STOPPED, &srvStatus)){ + DeleteService(drv->scDriver); + } + } + } return 0; } +#endif /* _WIN32 */ + + +static int rdmsr_supported(void) +{ + struct cpu_id_t* id = get_cached_cpuid(); + return id->flags[CPU_FEATURE_MSR]; +} + int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) { uint64_t r; @@ -339,5 +399,3 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) } } - -#endif /* _WIN32 */