1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include "superiotool.h"
5 #if defined(__FreeBSD__)
10 /* Command line options. */
11 int dump
= 0, verbose
= 0, extra_dump
= 0, alternate_dump
= 0;
13 /* Global flag which indicates whether a chip was detected at all. */
16 static void set_bank(uint16_t port
, uint8_t bank
)
22 static uint8_t datareg(uint16_t port
, uint8_t reg
)
28 uint8_t regval(uint16_t port
, uint8_t reg
)
31 return INB(port
+ ((port
== 0x3bd) ? 2 : 1)); /* 0x3bd is special. */
34 void regwrite(uint16_t port
, uint8_t reg
, uint8_t val
)
40 void enter_conf_mode_winbond_fintek_ite_8787(uint16_t port
)
46 void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port
)
48 OUTB(0xaa, port
); /* Fintek, Winbond */
49 regwrite(port
, 0x02, 0x02); /* ITE */
52 void enter_conf_mode_fintek_7777(uint16_t port
)
58 void exit_conf_mode_fintek_7777(uint16_t port
)
60 OUTB(0xaa, port
); /* Fintek */
63 int superio_unknown(const struct superio_registers reg_table
[], uint16_t id
)
65 return !strncmp(get_superio_name(reg_table
, id
), "<unknown>", 9);
69 const char *get_superio_name(const struct superio_registers reg_table
[],
74 for (i
= 0; /* Nothing */; i
++) {
75 if (reg_table
[i
].superio_id
== EOT
)
78 if ((uint16_t)reg_table
[i
].superio_id
!= id
)
81 return reg_table
[i
].name
;
87 static void set_extra_selector(uint16_t port
, const struct extra_selector
*esel
)
89 if (esel
->idx
== 0) /* entry without extra selector */
92 uint8_t reg_val
= regval(port
, esel
->idx
);
93 reg_val
&= ~esel
->mask
;
95 regwrite(port
, esel
->idx
, reg_val
);
97 reg_val
= regval(port
, esel
->idx
) & esel
->mask
;
99 printf(" -- ESEL[%02xh] 0x%02x", esel
->idx
, reg_val
);
100 if (esel
->name
!= NULL
)
101 printf(" (%s)", esel
->name
);
105 printf(" config: idx=%02xh, mask=%02xh, val=%02xh --", esel
->idx
, esel
->mask
,
109 static void dump_regs(const struct superio_registers reg_table
[],
110 int i
, int j
, uint16_t port
, uint8_t ldn_sel
)
113 const int16_t *idx
, *def
;
115 if (reg_table
[i
].ldn
[j
].ldn
!= NOLDN
) {
116 printf("LDN 0x%02x", reg_table
[i
].ldn
[j
].ldn
);
117 if (reg_table
[i
].ldn
[j
].name
!= NULL
)
118 printf(" (%s)", reg_table
[i
].ldn
[j
].name
);
119 regwrite(port
, ldn_sel
, reg_table
[i
].ldn
[j
].ldn
);
121 if (reg_table
[i
].ldn
[j
].name
== NULL
)
122 printf("Register dump:");
124 printf("(%s)", reg_table
[i
].ldn
[j
].name
);
127 set_extra_selector(port
, ®_table
[i
].ldn
[j
].esel
);
129 idx
= reg_table
[i
].ldn
[j
].idx
;
130 def
= reg_table
[i
].ldn
[j
].def
;
132 if (alternate_dump
) {
136 printf("\nidx def val\n");
138 for (k
= 0; idx
[k
] != EOT
; k
++) {
139 if (skip_def
|| def
[k
] == EOT
) {
145 printf("0x%02x: ", idx
[k
]);
146 val
= regval(port
, idx
[k
]);
149 printf("(NA) 0x%02x\n", val
);
150 else if (def
[k
] == RSVD
)
151 printf("(RR) 0x%02x\n", val
);
152 else if (def
[k
] == MISC
)
153 printf("(MM) 0x%02x\n", val
);
156 printf("0x%02x 0x%02x\n", def
[k
], val
);
158 printf("0x%02x [0x%02x]\n", def
[k
], val
);
163 for (k
= 0; idx
[k
] != EOT
; k
++) {
166 printf(" %02x", idx
[k
]);
170 for (k
= 0; idx
[k
] != EOT
; k
++) {
173 printf(" %02x", regval(port
, idx
[k
]));
177 for (k
= 0; def
[k
] != EOT
; k
++) {
182 else if (def
[k
] == RSVD
)
184 else if (def
[k
] == MISC
)
187 printf(" %02x", def
[k
]);
193 void dump_superio(const char *vendor
,
194 const struct superio_registers reg_table
[],
195 uint16_t port
, uint16_t id
, uint8_t ldn_sel
)
197 int i
, j
, no_dump_available
= 1;
202 for (i
= 0; /* Nothing */; i
++) {
203 if (reg_table
[i
].superio_id
== EOT
)
206 if ((uint16_t)reg_table
[i
].superio_id
!= id
)
209 for (j
= 0; /* Nothing */; j
++) {
210 if (reg_table
[i
].ldn
[j
].ldn
== EOT
)
212 no_dump_available
= 0;
213 dump_regs(reg_table
, i
, j
, port
, ldn_sel
);
216 if (no_dump_available
)
217 printf("No dump available for this Super I/O\n");
221 void dump_io(uint16_t iobase
, uint16_t length
)
225 printf("Dumping %d I/O mapped registers at base 0x%04x:\n",
227 for (i
= 0; i
< length
; i
++)
230 for (i
= 0; i
< length
; i
++)
231 printf("%02x ", INB(iobase
+ i
));
235 void dump_data(uint16_t iobase
, int bank
)
239 printf("Bank %d:\n", bank
);
241 for (i
= 0; i
< 16; i
++)
243 set_bank(iobase
, bank
);
244 for (i
= 0; i
< 256; i
++) {
246 printf("\n%02x: ", i
/ 16);
247 printf("%02x ", datareg(iobase
, i
));
252 void probing_for(const char *vendor
, const char *info
, uint16_t port
)
257 /* Yes, there's no space between '%s' and 'at'! */
258 printf("Probing for %s Super I/O %sat 0x%x...\n", vendor
, info
, port
);
261 /** Print a list of all supported chips from the given vendor. */
262 void print_vendor_chips(const char *vendor
,
263 const struct superio_registers reg_table
[])
267 for (i
= 0; reg_table
[i
].superio_id
!= EOT
; i
++) {
268 printf("%s %s", vendor
, reg_table
[i
].name
);
270 /* Unless the ldn is empty, assume this chip has a dump. */
271 if (reg_table
[i
].ldn
[0].ldn
!= EOT
)
272 printf(" (dump available)");
277 /* If we printed any chips for this vendor, put in a blank line. */
282 /** Print a list of all chips supported by superiotool. */
283 void print_list_of_supported_chips(void)
287 printf("Supported Super I/O chips:\n\n");
289 for (i
= 0; i
< ARRAY_SIZE(vendor_print_functions
); i
++)
290 vendor_print_functions
[i
].print_list();
292 printf("See <https://coreboot.org/Superiotool#Supported_devices> "
293 "for more information.\n");
296 static void print_version(void)
298 printf("superiotool r%s\n", SUPERIOTOOL_VERSION
);
301 int main(int argc
, char *argv
[])
303 int i
, j
, opt
, option_index
;
304 #if defined(__FreeBSD__)
308 static const struct option long_options
[] = {
309 {"dump", no_argument
, NULL
, 'd'},
310 {"extra-dump", no_argument
, NULL
, 'e'},
311 {"alternate-dump", no_argument
, NULL
, 'a'},
312 {"list-supported", no_argument
, NULL
, 'l'},
313 {"verbose", no_argument
, NULL
, 'V'},
314 {"version", no_argument
, NULL
, 'v'},
315 {"help", no_argument
, NULL
, 'h'},
319 while ((opt
= getopt_long(argc
, argv
, "dealVvh",
320 long_options
, &option_index
)) != EOF
) {
332 print_list_of_supported_chips();
348 /* Unknown option. */
354 #if defined(__FreeBSD__)
355 if ((io_fd
= open("/dev/io", O_RDWR
)) < 0) {
357 #elif defined(__NetBSD__)
361 if (ioperm(0, 6000, 1) < 0) {
364 printf("Superiotool must be run as root.\n");
371 /* Do some basic libpci init. */
377 for (i
= 0; i
< ARRAY_SIZE(superio_ports_table
); i
++) {
378 for (j
= 0; superio_ports_table
[i
].ports
[j
] != EOT
; j
++)
379 superio_ports_table
[i
].probe_idregs(
380 superio_ports_table
[i
].ports
[j
]);
384 printf("No Super I/O found\n");
386 #if defined(__FreeBSD__)