root/lm-sensors/trunk/prog/dump/isadump.c @ 4256

Revision 4256, 7.7 KB (checked in by khali, 6 years ago)

prog/dump/*: More robust user input handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    isadump.c - isadump, a user-space program to dump ISA registers
3    Copyright (C) 2000  Frodo Looijaard <frodol@dds.nl>, and
4                        Mark D. Studebaker <mdsxyz123@yahoo.com>
5    Copyright (C) 2004  The lm_sensors group
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/*
23        Typical usage:
24        isadump 0x295 0x296             Basic winbond dump using address/data registers
25        isadump 0x295 0x296 2           Winbond dump, bank 2
26        isadump 0x2e 0x2f 0x09          Super-I/O, logical device 9
27        isadump -f 0x5000               Flat address space dump like for Via 686a
28        isadump -f 0xecf0 0x10 1        PC87366, temperature channel 2
29*/
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include "util.h"
36#include "superio.h"
37
38
39/* To keep glibc2 happy */
40#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 0
41#include <sys/io.h>
42#else
43#include <asm/io.h>
44#endif
45
46#ifdef __powerpc__
47unsigned long isa_io_base = 0; /* XXX for now */
48#endif /* __powerpc__ */
49
50char hexchar(int i)
51{
52        if ((i >= 0) && (i <= 9))
53                return '0' + i;
54        else if (i <= 15)
55                return 'a' - 10 + i;
56        else
57                return 'X';
58}
59
60void help(void)
61{
62        fprintf(stderr,
63                "Syntax for I2C-like access:\n"
64                "  isadump [-y] [-k V1,V2...] ADDRREG DATAREG [BANK [BANKREG]]\n"
65                "Syntax for flat address space:\n"
66                "  isadump [-y] -f ADDRESS [RANGE [BANK [BANKREG]]]\n");
67}
68
69int default_bankreg(int flat, int addrreg, int datareg)
70{
71        if (flat) {
72                return 0x09; /* Works for National Semiconductor
73                                Super-IO chips */
74        }
75
76        if ((addrreg == 0x2e && datareg == 0x2f)
77         || (addrreg == 0x4e && datareg == 0x4f)) {
78                return 0x07; /* Works for all Super-I/O chips */
79        }
80       
81        return 0x4e; /* Works for Winbond ISA chips, default */
82}
83
84int set_bank(int flat, int addrreg, int datareg, int bank, int bankreg)
85{
86        int oldbank;
87
88        if (flat) {
89                oldbank = inb(addrreg+bankreg);
90                outb(bank, addrreg+bankreg);
91        } else {
92                outb(bankreg, addrreg);
93                oldbank = inb(datareg);
94                outb(bank, datareg);
95        }
96
97        return oldbank;
98}
99
100int main(int argc, char *argv[])
101{
102        int addrreg;        /* address in flat mode */
103        int datareg = 0;    /* unused in flat mode */
104        int range = 256;    /* can be changed only in flat mode */
105        int bank = -1;      /* -1 means no bank operation */
106        int bankreg;
107        int oldbank = 0;
108        int i, j, res;
109        int flags = 0;
110        int flat = 0, yes = 0;
111        char *end;
112        unsigned char enter_key[SUPERIO_MAX_KEY+1];
113
114        enter_key[0] = 0;
115
116        /* handle (optional) flags first */
117        while (1+flags < argc && argv[1+flags][0] == '-') {
118                switch (argv[1+flags][1]) {
119                case 'f': flat = 1; break;
120                case 'y': yes = 1; break;
121                case 'k':
122                        if (2+flags >= argc
123                         || superio_parse_key(enter_key, argv[2+flags]) < 0) {
124                                fprintf(stderr, "Invalid or missing key\n");
125                                help();
126                                exit(1);
127                        }
128                        flags++;
129                        break;
130                default:
131                        fprintf(stderr, "Warning: Unsupported flag "
132                                "\"-%c\"!\n", argv[1+flags][1]);
133                        help();
134                        exit(1);
135                }
136                flags++;
137        }
138
139        /* key is never needed in flat mode */
140        if (flat && enter_key[0]) {
141                fprintf(stderr, "Error: Cannot use key in flat mode\n");
142                exit(1);
143        }
144
145        /* verify that the argument count is correct */
146        if ((!flat && argc < 1+flags+2)
147         || (flat && argc < 1+flags+1)) {
148                help();
149                exit(1);
150        }
151
152        addrreg = strtol(argv[1+flags], &end, 0);
153        if (*end) {
154                fprintf(stderr, "Error: Invalid address!\n");
155                help();
156                exit(1);
157        }
158        if (addrreg < 0 || addrreg > (flat?0xffff:0x3fff)) {
159                fprintf(stderr, "Error: Address out of range "
160                        "(0x0000-0x%04x)!\n", flat?0xffff:0x3fff);
161                help();
162                exit(1);
163        }
164
165        if (flat) {
166                if (1+flags+1 < argc) {
167                        range = strtol(argv[1+flags+1], &end, 0);
168                        if (*end || range <= 0 || range > 0x100
169                         || range & 0xf) {
170                                fprintf(stderr, "Error: Invalid range!\n"
171                                        "Hint: Must be a multiple of 16 no "
172                                        "greater than 256.\n");
173                                help();
174                                exit(1);
175                        }
176                } else {
177                        addrreg &= 0xff00; /* Force alignment */
178                }
179        } else {
180                datareg = strtol(argv[1+flags+1], &end, 0);
181                if (*end) {
182                        fprintf(stderr, "Error: Invalid data register!\n");
183                        help();
184                        exit(1);
185                }
186                if (datareg < 0 || datareg > 0x3fff) {
187                        fprintf(stderr, "Error: Data register out of range "
188                                "(0x0000-0x3fff)!\n");
189                        help();
190                        exit(1);
191                }
192        }
193
194        bankreg = default_bankreg(flat, addrreg, datareg);
195
196        if (1+flags+2 < argc) {
197                bank = strtol(argv[1+flags+2], &end, 0);
198                if (*end) {
199                        fprintf(stderr, "Error: Invalid bank number!\n");
200                        help();
201                        exit(1);
202                }
203                if ((bank < 0) || (bank > 31)) {
204                        fprintf(stderr, "Error: bank out of range (0-31)!\n");
205                        help();
206                        exit(1);
207                }
208
209                if (1+flags+3 < argc) {
210                        bankreg = strtol(argv[1+flags+3], &end, 0);
211                        if (*end) {
212                                fprintf(stderr, "Error: Invalid bank "
213                                        "register!\n");
214                                help();
215                                exit(1);
216                        }
217                        if (bankreg < 0 || bankreg >= range) {
218                                fprintf(stderr, "Error: bank out of range "
219                                        "(0x00-0x%02x)!\n", range-1);
220                                help();
221                                exit(1);
222                        }
223                }
224        }
225
226        if (getuid()) {
227                fprintf(stderr, "Error: Can only be run as root (or make it "
228                        "suid root)\n");
229                exit(1);
230        }
231
232        if (!yes) {
233                fprintf(stderr, "WARNING! Running this program can cause "
234                        "system crashes, data loss and worse!\n");
235
236                if (flat)
237                        fprintf(stderr, "I will probe address range 0x%x to "
238                                "0x%x.\n", addrreg, addrreg + range - 1);
239                else
240                        fprintf(stderr, "I will probe address register 0x%x "
241                                "and data register 0x%x.\n", addrreg, datareg);
242
243                if (bank>=0)   
244                        fprintf(stderr, "Probing bank %d using bank register "
245                                "0x%02x.\n", bank, bankreg);
246
247                fprintf(stderr, "Continue? [Y/n] ");
248                fflush(stderr);
249                if (!user_ack(1)) {
250                        fprintf(stderr, "Aborting on user request.\n");
251                        exit(0);
252                }
253        }
254
255#ifndef __powerpc__
256        if ((datareg < 0x400) && (addrreg < 0x400) && !flat) {
257                if (ioperm(datareg, 1, 1)) {
258                        fprintf(stderr, "Error: Could not ioperm() data "
259                                "register!\n");
260                        exit(1);
261                }
262                if (ioperm(addrreg, 1, 1)) {
263                        fprintf(stderr, "Error: Could not ioperm() address "
264                                "register!\n");
265                        exit(1);
266                }
267        } else {
268                if (iopl(3)) {
269                        fprintf(stderr, "Error: Could not do iopl(3)!\n");
270                        exit(1);
271                }
272        }
273#endif
274
275        /* Enter Super-I/O configuration mode */
276        if (enter_key[0])
277                superio_write_key(addrreg, enter_key);
278
279        if (bank >= 0)
280                oldbank = set_bank(flat, addrreg, datareg, bank, bankreg);
281
282        if (flat)
283                printf("  ");
284        printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
285        for (i = 0; i < range; i += 16) {
286                if (flat)
287                        printf("%04x: ", addrreg + i);
288                else
289                        printf("%02x: ", i);
290
291                /* It was noticed that Winbond Super-I/O chips
292                   would leave the configuration mode after
293                   an arbitrary number of register reads,
294                   causing any subsequent read attempt to
295                   silently fail. Repeating the key every 16 reads
296                   prevents that. */
297                if (enter_key[0])
298                        superio_write_key(addrreg, enter_key);
299
300                for (j = 0; j < 16; j++) {
301                        if (flat) {
302                                res = inb(addrreg + i + j);
303                        } else {       
304                                outb(i+j, addrreg);
305                                res = inb(datareg);
306                        }
307                        printf("%c%c ", hexchar(res/16), hexchar(res%16));
308                }
309                printf("\n");
310        }
311
312        /* Restore the original bank value */
313        if (bank >= 0)
314                set_bank(flat, addrreg, datareg, oldbank, bankreg);
315
316        /* Exit Super-I/O configuration mode */
317        if (enter_key[0])
318                superio_reset(addrreg, datareg);
319
320        exit(0);
321}
Note: See TracBrowser for help on using the browser.