#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <nlist.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <mach/mach_types.h>
#include <mach/mach.h>
#include <mach/host_info.h>
#include <mach/mach_error.h>
extern int errno;
extern int optind;
extern char *optarg;
extern int optopt;
extern int opterr;
extern int optreset;
#define pmsMaxStates 64
#define HalfwayToForever 0x7FFFFFFFFFFFFFFFULL
#define century 790560000000000ULL
typedef void (*pmsSetFunc_t)(uint32_t, uint32_t);
typedef struct pmsStat {
uint64_t stTime[2];
uint32_t stCnt[2];
} pmsStat;
typedef struct pmsDef {
uint64_t pmsLimit;
uint32_t pmsStepID;
uint32_t pmsSetCmd;
#define pmsCngXClk 0x80000000
#define pmsXUnk 0x7F
#define pmsXClk 0x7F000000
#define pmsCngCPU 0x00800000
#define pmsSync 0x00400000
#define pmsMustCmp 0x00200000
#define pmsCPU 0x001F0000
#define pmsCPUUnk 0x1F
#define pmsCngVolt 0x00008000
#define pmsVoltage 0x00007F00
#define pmsVoltUnk 0x7F
#define pmsPowerID 0x000000FF
#define pmsDelay 0xFFFFFFFD
#define pmsParkIt 0xFFFFFFFF
#define pmsCInit ((pmsXUnk << 24) | (pmsCPUUnk << 16) | (pmsVoltUnk << 8))
union sf {
pmsSetFunc_t pmsSetFunc;
uint32_t pmsSetFuncInd;
} sf;
uint32_t pmsDown;
uint32_t pmsNext;
uint32_t pmsTDelay;
} pmsDef;
typedef struct pmsCtl {
pmsStat (*pmsStats)[pmsMaxStates];
pmsDef *pmsDefs[pmsMaxStates];
} pmsCtl;
typedef struct pmsd {
uint32_t pmsState;
uint32_t pmsCSetCmd;
uint64_t pmsPop;
uint64_t pmsStamp;
uint64_t pmsTime;
} pmsd;
enum {
pmsIdle = 0,
pmsNorm = 1,
pmsNormHigh = 2,
pmsBoost = 3,
pmsLow = 4,
pmsHigh = 5,
pmsPrepCng = 6,
pmsPrepSleep = 7,
pmsOverTemp = 8,
pmsEnterNorm = 9,
pmsFree = 10,
pmsStartUp = 0xFFFFFFFE,
pmsParked = 0xFFFFFFFF
};
enum {
pmsCPark = 0,
pmsCStart = 1,
pmsCFLow = 2,
pmsCFHigh = 3,
pmsCCnfg = 4,
pmsCQuery = 5,
pmsCExperimental = 6,
pmsCFree = 7
};
#define pmsSetFuncMax 32
char stepfile[512];
FILE *sfile;
pmsDef pmsDefs[pmsMaxStates];
int defd[pmsMaxStates];
char *cspot, *otoken;
char mimesteps[((sizeof(pmsDefs) / 3) * 4) + 4];
extern kern_return_t pmsCall(uint32_t rqst, pmsDef *pd, uint32_t psize);
extern kern_return_t stepclientsend (void *pmsTable, uint32_t pmsTableLength, void *pmsAuxTable, uint32_t pmsAuxTableLength);
extern kern_return_t stepclientcontrol (uint32_t newStepLevel);
int cb2b64(unsigned char *in, unsigned char *out, int len);
#define century 790560000000000ULL
int main(int argc, char **argv) {
int i, j, k, opt, maxstep, cline, activate, quiet, userclient, raw, mime, mlen, form;
char line[512], *xx;
int chrs, lsize, ltoken, mtoken;
char *badchar;
int mult, errors;
uint32_t pStepID, pHWSel, pSetFunc, pDown, pNext, stepLevel, pDelay;
uint64_t pLimit;
kern_return_t ret;
int cstp, cstpx, seen[pmsMaxStates], lchkd[pmsMaxStates];
activate = 0;
quiet = 0;
userclient = 0;
raw = 0;
mime = 0;
stepfile[0] = 0;
while(1) {
if(optind >= argc) break;
if(*argv[optind] != '-') {
strncpy(stepfile, argv[optind], 511);
optind++;
}
opt = getopt(argc, argv, "aqhrsum");
if(opt == -1) break;
switch (opt) {
case 'a':
activate = 1;
break;
case 'm':
mime = 1;
break;
case 'q':
quiet = 1;
break;
case 'r':
raw = 1;
break;
case 'u':
userclient = 1;
break;
case 's':
if(*argv[optind] != '-') {
stepLevel = strtoul(argv[optind], 0, 0);
optind++;
if (stepLevel > 3) {
printf ("Invalid step level %d\n", stepLevel);
exit (0);
}
if (geteuid() != 0 ) {
printf("\nroot is required for controlling step levels\n");
exit(1);
}
ret = stepclientcontrol (stepLevel);
if(ret == KERN_SUCCESS) {
printf("\nStep controlled successfully\n");
} else
printf("\nStep control failed\n");
exit (0);
}
break;
default:
printf("usage: pmsset - read the code dude...\n");
exit(1);
}
}
if (stepfile[0] == 0) {
printf("Step file name missing\n");
exit(1);
}
if(!quiet) printf("\nCompiling step file: \"%s\"\n\n", stepfile);
sfile = fopen(stepfile, "r");
if(sfile == 0) {
printf("Step definition file error, errno = %d\n", errno);
exit(1);
}
bzero((void *)pmsDefs, pmsMaxStates * sizeof(pmsDef));
for(i = 0; i < pmsMaxStates; i++) defd[i] = 0;
errors = 0;
cline = 0;
maxstep = -1;
while(1) {
line[511] = 0;
xx = fgets(line, 511, sfile);
if(!(uint32_t)xx) {
if(feof(sfile)) break;
printf("Error reading definition file\n");
errors = 1;
break;
}
cline++;
lsize = strlen(line);
if(line[lsize - 1] == '\n') lsize = lsize - 1;
line[lsize] = 0;
if(!quiet) printf("%3d) %s\n",cline, line);
chrs = strspn(line, " \t");
cspot = &line[chrs];
if(cspot[0] == 0 | cspot[0] == ';') continue;
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
if(cspot[0] == 0 | cspot[0] == ';') continue;
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pStepID = strtoul(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid step ID\n");
errors = 1;
continue;
}
if(pStepID >= pmsMaxStates) {
if(!quiet) printf(" Step ID out of range\n");
errors = 1;
continue;
}
if(defd[pStepID]) {
if(!quiet) printf(" Step previously defined, line = %d\n", defd[pStepID]);
errors = 1;
continue;
}
pmsDefs[pStepID].pmsStepID = pStepID;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
if(!quiet) printf(" Missing down step\n");
errors = 1;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pDown = strtoul(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid down step\n");
errors = 1;
continue;
}
if((pDown != 0xFFFFFFFF) && (pDown >= pmsMaxStates)) {
if(!quiet) printf(" Down step out of range\n");
errors = 1;
continue;
}
pmsDefs[pStepID].pmsDown = pDown;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
if(!quiet) printf(" Missing next step\n");
errors = 1;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pNext = strtoul(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid next step\n");
errors = 1;
continue;
}
if((pNext != 0xFFFFFFFF) && (pNext >= pmsMaxStates)) {
if(!quiet) printf(" Next step out of range\n");
errors = 1;
continue;
}
pmsDefs[pStepID].pmsNext = pNext;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
if(!quiet) printf(" Missing hardware selector\n");
errors = 1;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pHWSel = strtoul(cspot, &badchar, 16);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid set command\n");
errors = 1;
continue;
}
pmsDefs[pStepID].pmsSetCmd = pHWSel;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
if(!quiet) printf(" Missing platform set function\n");
errors = 1;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pSetFunc = strtoul(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid platform set function\n");
errors = 1;
continue;
}
pmsDefs[pStepID].sf.pmsSetFuncInd = pSetFunc;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
pmsDefs[pStepID].pmsLimit = century;
defd[pStepID] = cline;
if((int)pStepID > maxstep) maxstep = pStepID;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pLimit = strtoull(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid time limit\n");
errors = 1;
continue;
}
if(pLimit > century) {
if(!quiet) printf(" Time limit greater than one century\n");
errors = 1;
continue;
}
if(pLimit == 0xFFFFFFFFFFFFFFFFULL) pLimit = century;
if((pLimit != 0) && (pLimit < 100ULL)) {
if(!quiet) printf(" Time limit smaller than 100 microseconds\n");
errors = 1;
continue;
}
pmsDefs[pStepID].pmsLimit = pLimit;
chrs = strspn(&cspot[ltoken + 1], " \t");
cspot = &cspot[chrs + ltoken + 1];
if(cspot[0] == 0 | cspot[0] == ';') {
pmsDefs[pStepID].pmsTDelay = pmsIdle;
defd[pStepID] = cline;
if((int)pStepID > maxstep) maxstep = pStepID;
continue;
}
ltoken = strcspn(cspot, " \t");
cspot[ltoken] = 0;
pDelay = strtoul(cspot, &badchar, 0);
if((*badchar != 0) && (*badchar != ' ') && (*badchar != ';')) {
if(!quiet) printf(" Invalid TDelay\n");
errors = 1;
continue;
}
if(pDelay >= pmsMaxStates) {
if(!quiet) printf(" TDelay step out of range\n");
errors = 1;
continue;
}
pmsDefs[pStepID].pmsTDelay = pDelay;
defd[pStepID] = cline;
if((int)pStepID > maxstep) maxstep = pStepID;
}
if(!quiet) printf("\n\nPost-compile validation\n");
if(!quiet) printf("\n Stmt StepID Down Next SetCMD SetFunc Limit TDelay\n");
for(i = 0; i <= maxstep; i++) {
if(!defd[i]) continue;
if(!quiet) printf("%4d) %6d %6d %6d %08X %6d %20lld %6d\n", defd[i], pmsDefs[i].pmsStepID, pmsDefs[i].pmsDown,
pmsDefs[i].pmsNext, pmsDefs[i].pmsSetCmd,
pmsDefs[i].sf.pmsSetFuncInd, pmsDefs[i].pmsLimit, pmsDefs[i].pmsTDelay);
if((pmsDefs[i].pmsSetCmd != 0xFFFFFFFF) && (pmsDefs[i].pmsDown != 0xFFFFFFFF) && !defd[pmsDefs[i].pmsDown]) {
if(!quiet) printf(" Down step has not been defined\n");
errors = 1;
}
if((pmsDefs[i].pmsSetCmd != 0xFFFFFFFF) && (pmsDefs[i].pmsNext != 0xFFFFFFFF) && !defd[pmsDefs[i].pmsNext]) {
if(!quiet) printf(" Next step has not been defined\n");
errors = 1;
}
if((pmsDefs[i].pmsSetCmd != pmsDelay) && (pmsDefs[i].pmsTDelay != pmsIdle)) {
if(!quiet) printf(" TDelay specfied for a non-delay command\n");
errors = 1;
}
if((pmsDefs[i].pmsSetCmd == pmsDelay) && !defd[pmsDefs[i].pmsTDelay]) {
if(!quiet) printf(" TDelay step has not been defined\n");
errors = 1;
}
}
if(!quiet) printf("\n\nChecking for infinite non-wait loops\n");
for(i = 0; i < pmsMaxStates; i++) lchkd[i] = 0;
for(i = 0; i <= maxstep; i++) {
if(lchkd[i]) continue;
for(j = 0; j < pmsMaxStates; j++) seen[j] = 0;
cstp = i;
while(1) {
if(seen[cstp]) {
if(!quiet) printf("%4d) Infinite non-wait loop detected: %d", defd[cstp], cstp);
cstpx = cstp;
while(1) {
cstp = pmsDefs[cstp].pmsNext;
if(!quiet) printf(" --> %d", cstp);
if(cstp = cstpx) break;
}
if(!quiet) printf("\n");
errors = 1;
break;
}
lchkd[cstp] = 1;
seen[cstp] = 1;
if(pmsDefs[cstp].pmsSetCmd == pmsParkIt) break;
if(pmsDefs[cstp].pmsSetCmd == pmsDelay) break;
if((pmsDefs[cstp].pmsLimit != 0) && ((pmsDefs[cstp].pmsSetCmd & pmsSync) != pmsSync)) break;
if(pmsDefs[cstp].pmsNext == pmsParked) break;
cstp = pmsDefs[cstp].pmsNext;
}
}
if (raw) {
for(i = 0; i <= maxstep; i++) {
printf ("%08x %08x %08x %08x %08x %08x %08x %08x ", (unsigned int)((pmsDefs[i].pmsLimit >> 32) & 0xFFFFFFFF),
(unsigned int)(pmsDefs[i].pmsLimit & 0xFFFFFFFF), pmsDefs[i].pmsStepID, pmsDefs[i].pmsSetCmd, pmsDefs[i].sf.pmsSetFuncInd,
pmsDefs[i].pmsDown, pmsDefs[i].pmsNext, pmsDefs[i].pmsTDelay);
}
printf ("\n");
}
if (mime) {
mlen = cb2b64((char *)pmsDefs, mimesteps, (maxstep + 1) * sizeof(pmsDef));
for(i = 0; i < (mlen / 4); i++) {
form = i % 5;
if(form == 0) printf(" ");
printf("%c%c%c%c", mimesteps[i * 4], mimesteps[(i * 4) + 1], mimesteps[(i * 4) + 2],
mimesteps[(i * 4) + 3]);
if(form == 4) printf("\n");
}
printf ("\n");
}
if(errors) {
printf("\nErrors detected, update abandoned\n");
exit(1);
}
if(!activate) {
printf("\nNo activation requested (-a), update abandoned\n");
exit(0);
}
if (geteuid() != 0 ) {
printf("\nNo activation: root is required\n");
exit(1);
}
printf("\nAttempting step activation\n");
if (userclient)
ret = stepclientsend (&pmsDefs[0], (maxstep + 1) * sizeof(pmsDef), NULL, 0);
else
ret = pmsCall(pmsCCnfg, &pmsDefs[0], (maxstep + 1) * sizeof(pmsDef));
if(ret == KERN_SUCCESS) {
printf("\nStep table successfully installed\n");
exit(0);
}
printf("Step table install failed, ret = %08X\n", ret);
exit(1);
}
unsigned char *b2b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int cb2b64(unsigned char *in, unsigned char *out, int len) {
int outpos, extra, chunks, i;
uint32_t d24;
outpos = 0;
chunks = len / 3;
for(i = 0; i < chunks; i++) {
d24 = (in[0] << 16) | (in[1] << 8) | in[2];
out[outpos] = b2b64[(d24 >> 18) & 0x3F];
out[outpos + 1] = b2b64[(d24 >> 12) & 0x3F];
out[outpos + 2] = b2b64[(d24 >> 6) & 0x3F];
out[outpos + 3] = b2b64[d24 & 0x3F];
outpos = outpos + 4;
in = in + 3;
}
extra = len % 3;
if(extra == 0) return outpos;
out[outpos + 2] = '=';
out[outpos + 3] = '=';
out[outpos] = b2b64[(in[0] >> 2) & 0x3F];
if(extra == 1) {
out[outpos + 1] = b2b64[(in[0] << 4) & 0x30];
return (outpos + 4);
}
out[outpos + 1] = b2b64[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 15)];
out[outpos + 2] = b2b64[(in[1] << 2) & 0x3C];
return (outpos + 4);
}