uvtool.c
(plain)
1 /* Copyright (c) 2024 Amelia Zabardast Ziabari 2 ** 3 ** Redistribution and use in source and binary forms, with or without 4 ** modification, are permitted provided that the following conditions are met: 5 ** 6 ** 1. Redistributions of source code must retain the above copyright notice, 7 ** this list of conditions and the following disclaimer. 8 ** 2. Redistributions in binary form must reproduce the above copyright 9 ** notice, this list of conditions and the following disclaimer in the 10 ** documentation and/or other materials provided with the distribution. 11 ** 12 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 13 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 16 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 18 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 19 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 20 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 22 ** POSSIBILITY OF SUCH DAMAGE. 23 */ 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <math.h> 27 #include <string.h> 28 29 #define ERROR(...) (fprintf(stderr, __VA_ARGS__),exit(1)) 30 31 static int states; 32 struct state { 33 int mV; 34 int msr; 35 }; 36 static struct state *table; 37 38 39 static void validate_value( int v ) 40 { 41 if ( ( v - 700 ) % 16 != 0 ) 42 ERROR("specified voltage value (%d) cannot compute to MSR value\n",v); 43 } 44 45 46 static void validate_range( int mi, int ma ) 47 { 48 /* TODO: Pentium M always goes down to 700 mV, but unsure if any processors 49 ** exceed 1500 mV. someone should check this if they need it. 50 ** (Core/Core 2 just have their minimum voltage locked?) 51 */ 52 if ( mi < 700 || ma < 700 || mi > 1500 || ma > 1500 ) 53 ERROR("specified voltage invalid or out of sane range (700-1500)?\n"); 54 if ( mi > ma ) 55 ERROR("specified minimum voltage is larger than maximum voltage?\n"); 56 validate_value( mi ); 57 validate_value( ma ); 58 } 59 60 61 static float lerp( float mi, float ma, float omi, float oma ) 62 { 63 return mi + ( ma - mi ) * ( omi / oma ); 64 } 65 66 67 static void gen_range( int mi, int ma ) 68 { 69 int i; 70 float mV; 71 72 for ( i = 0; i < states; i++ ) 73 { 74 mV = lerp( mi, ma, i, states - 1 ); 75 /* intel appears to round for default values, but some may prefer 76 ** rounding up for safety reasons. alternatively, just raise max mV 77 */ 78 mV = roundf( ( mV - 700 ) / 16 ); 79 table[i].msr = (int) mV; 80 table[i].mV = (int) (mV * 16) + 700; 81 } 82 } 83 84 85 static void print_acc( ) 86 { 87 static int t = 0; 88 89 if ( (t++) >= 5 ) 90 { 91 t = 0; 92 printf( "\n" ); 93 } 94 } 95 96 97 static void print_range( int fmt ) 98 { 99 int i; 100 101 switch ( fmt ) 102 { 103 case 2: /* vids only */ 104 for ( i = states - 1; i >= 0; i-- ) 105 printf( "%d ", table[i].msr ); 106 break; 107 108 case 1: /* netbsd sysctl */ 109 printf( "machdep.cpu.voltage.custom=" ); 110 111 for ( i = states - 1; i >= 0; i-- ) 112 printf( "%d ", table[i].mV ); 113 break; 114 115 default: /* human readable form */ 116 for ( i = 0; i < states; i++ ) 117 { 118 printf( "%4d mV (%2d) ", table[i].mV, table[i].msr ); 119 print_acc( ); 120 } 121 break; 122 } 123 124 printf( "\n" ); 125 } 126 127 128 static void print_omap( int imi, int ima ) 129 { 130 /* get the full range of possible vids so the user can select them */ 131 int i, msrmi, msrma; 132 133 msrmi = (imi - 700) >> 4; 134 msrma = (ima - 700) >> 4; 135 136 for ( i = msrmi; i < (msrma + 1); i++ ) 137 { 138 printf( "%4d mV (%2d) ", (i << 4) + 700, i ); 139 print_acc( ); 140 } 141 142 printf( "\n" ); 143 } 144 145 146 static void print_rmap( int imi, int ima, int fmt ) 147 { 148 gen_range( imi, ima ); 149 print_range( fmt ); 150 } 151 152 153 static void command( char *cmd, int imi, int ima ) 154 { 155 char c; 156 157 validate_range( imi, ima ); 158 159 if ( strlen(cmd) != 1 ) 160 { 161 invalid: 162 ERROR("invalid command (must be d, a, A, v)\n"); 163 } 164 c = cmd[0]; 165 166 switch (c) 167 { 168 case 'd': print_omap( imi, ima ); break; 169 case 'a': print_rmap( imi, ima, 0 ); break; 170 case 'A': print_rmap( imi, ima, 1 ); break; 171 case 'v': print_rmap( imi, ima, 2 ); break; 172 default : goto invalid; 173 } 174 } 175 176 int main( int argc, char **argv ) 177 { 178 if (argc >= 2) 179 { 180 states = atoi(argv[1]); 181 if ( states < 2 || states > 16 ) 182 ERROR("specified amount of states outside sane range (2-16)\n"); 183 table = malloc( sizeof(struct state) * states ); 184 } 185 switch ( argc ) 186 { 187 case 5: command( argv[2], atoi( argv[3] ), atoi( argv[4] ) ); break; 188 189 default: 190 ERROR( 191 "insufficient params.\n" 192 "%s <S> <M> <A> <B>: show possible VIDs\n" 193 "where A-B is min voltage to max voltage in mV (e.g. 1020-1404)\n" 194 "and M is a single-char operation:\n" 195 " d[umb] - print all possible MSR values in given range\n" 196 " a[uto] - auto-calculate new VID table for given range\n" 197 " A[uto] - ditto, but format as a NetBSD est.c sysctl\n" 198 " v[ids] - ditto, but just print raw VID numbers\n" 199 "and S is the total number of original MSR states (e.g. 8)\n" 200 "example: %s 8 a 1020 1404\n", 201 argv[0], argv[0]); 202 } 203 return 0; 204 }