/* SlimCPU - utility to access SKX CPU registers * * (C) Netapp Copyright 2018 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include "slimCPU.h" #define MSRACC_NODE_NAME "/dev/msrAccessDrv" using namespace std; int proc_GetCPUCount (unsigned int * retV) { FILE* file; char temp[8]; file = popen("cat /proc/cpuinfo | grep \"physical id\" | sort | uniq | wc -l", "r"); if (file == NULL) return -1; fgets(temp, sizeof(temp), file); sscanf(temp, "%d", retV); pclose(file); return 0; } unsigned int proc_GetTargetCPUID(unsigned int phyID) { unsigned int count; if (proc_GetCPUCount(&count) != 0) { printf("Error: can not find valid CPU count\n"); return 0xFFFFFFFF; } else if (phyID >= count) { printf("Error: CPU ID not valid - %x\n", phyID); return 0xFFFFFFFF; } else { return (sysconf(_SC_NPROCESSORS_ONLN)/count)*phyID; } } unsigned int proc_ReadRegister( unsigned int cpu, unsigned int addr, unsigned long long * retV) { FILE* file; struct msracc_drv_cmd msrCmd; unsigned int targetCPU; if ((targetCPU = proc_GetTargetCPUID(cpu)) == 0xFFFFFFFF) return -1; file = fopen(MSRACC_NODE_NAME, "r"); if (file == NULL) return -1; msrCmd.cpu_id = targetCPU; msrCmd.msr_offset = addr; if (0 != ioctl(fileno(file), MSRACC_IOCTL_GET_MSR, &msrCmd)) return -1; *retV = ((unsigned long long)msrCmd.val_high << 32) | (unsigned long long)msrCmd.val_low; fclose(file); return 0; } unsigned int proc_WriteRegister( unsigned int cpu, unsigned int addr, unsigned long long value) { FILE* file; struct msracc_drv_cmd msrCmd; unsigned int targetCPU; if ((targetCPU = proc_GetTargetCPUID(cpu)) == 0xFFFFFFFF) return -1; file = fopen(MSRACC_NODE_NAME, "r"); if (file == NULL) return -1; msrCmd.cpu_id = targetCPU; msrCmd.msr_offset = addr; msrCmd.val_low = (unsigned int)value; msrCmd.val_high = (unsigned int)(value >> 32); if (0 != ioctl(fileno(file), MSRACC_IOCTL_SET_MSR, &msrCmd)) { fclose(file); return -1; } fclose(file); return 0; } void show_usage(unsigned int cnt) { printf("Syntax: \n"); printf(" Read - cpuID rd startRegAddr(HEX) [endRegAddr(HEX)]\n"); printf(" Write - cpuID wr regAddr writeValue(HEX)\n "); printf(" cpuID: 0 ~ %d\n", cnt-1 ); return ; } int main ( int argc, char *argv[] ) { unsigned long addr, addrEnd; unsigned long parm[5]; unsigned long long value64; unsigned int id,count; char * op; if (proc_GetCPUCount(&count) != 0) { printf("Error: can not find valid CPU count\n"); return 0xFF; } // param: main cpuID rd regAddr [endAddr] // main cpuID wr regAddr writeValue op = argv[2]; if ( ((argc != 4 ) && ( 5 != argc) ) || ( strcasecmp( op, "rd") && strcasecmp( op, "wr") ) ) { show_usage(count); return 1; } for (int i = 1; i < argc; i++) { if (i != 2 ) sscanf(argv[i], "%lX", &parm[i]); else parm[2] = 0; } id = (unsigned int)parm[1]; if ( id >= count ) { printf("Error: not a valid CPU ID: %X\n", id); printf("\n"); show_usage(count); return 0xFF; } if ( !strcasecmp( op , "rd") ) //read operation { addr = parm[3]; if ( argc == 4 ) addrEnd = addr; else if ( argc == 5 ) addrEnd = parm[4]; while(addr <= addrEnd) { if ( proc_ReadRegister(id, addr, &value64) != 0 ) { printf("Read Error! \n"); return 2; } printf("%lx: %16llx\n", addr, value64); addr++; } } else { if ( argc != 5 ) { printf("Error: input pamameter not correct! \n"); show_usage(count); return 0xFF; } addr = parm[3]; value64 = parm[4]; if ( proc_WriteRegister(id, addr, value64) != 0 ) { printf("Write failed! \n" ); return 2; } } return 0; }