Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: gen-seeprom.c | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * id: @(#)gen-seeprom.c 1.12 05/11/15 | |
46 | * purpose: | |
47 | * copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved | |
48 | * copyright: Use is subject to license terms. | |
49 | */ | |
50 | ||
51 | /* | |
52 | * Parse a config file and generate a binary file containing the cpu seeprom | |
53 | * image. | |
54 | */ | |
55 | ||
56 | #include <stdio.h> | |
57 | #include <stdlib.h> | |
58 | #include <unistd.h> | |
59 | #include <fcntl.h> | |
60 | #include <string.h> | |
61 | #include <time.h> | |
62 | #include "gen-seeprom.h" | |
63 | #include "prototypes.h" | |
64 | ||
65 | #define MAX_IMAGE 0x800 | |
66 | ||
67 | int system_type = EXCALIBUR; | |
68 | int system_type_init = 0; | |
69 | int config_type_init = 0; | |
70 | struct fixed_seeprom *seeprom_data; | |
71 | char *config_file; | |
72 | char err_string[MAXLINE]; | |
73 | int type = CPU; | |
74 | int do_checksum = 0; | |
75 | static int quiet = 0, release = 0; | |
76 | int force_debug = 0; | |
77 | ||
78 | static struct unique_functions seeprom_func[] = { | |
79 | SET_FUNC_ENTRY(cpu_dynamic, check_cpu, write_cpu, dump_cpu, reg_cpu) | |
80 | SET_FUNC_ENTRY(sys_dynamic, check_sys, write_sys, dump_sys, reg_sys) | |
81 | SET_FUNC_ENTRY(env_dynamic, check_env, write_env, dump_env, reg_env) | |
82 | SET_FUNC_ENTRY(mem_dynamic, check_mem, write_mem, dump_mem, reg_mem) | |
83 | SET_FUNC_ENTRY(cpu_dynamic, check_cpu, write_cpu, dump_cpu, reg_cpu) | |
84 | }; | |
85 | ||
86 | static void | |
87 | usage(char *name) | |
88 | { | |
89 | static struct tm tm_compiled = { COMPILE_TIME }; | |
90 | time_t compiled, expire; | |
91 | compiled = mktime(&tm_compiled); | |
92 | expire = compiled + ACTIVE_TIME; | |
93 | ||
94 | /* -q option is quiet mode, no processing messages. */ | |
95 | fprintf(stderr, | |
96 | "%s: [ -q ] <config_filename>\n", name); | |
97 | fprintf(stderr, " -q Suppresses config file processing messages.\n"); | |
98 | ||
99 | fprintf(stderr, "\nTool will expire on %s\n", ctime(&expire)); | |
100 | ||
101 | exit(1); | |
102 | } | |
103 | ||
104 | static int | |
105 | usage_expired(void) | |
106 | { | |
107 | int status = 0; | |
108 | ||
109 | static struct tm tm_compiled = { COMPILE_TIME }; | |
110 | time_t compiled, now, expire; | |
111 | ||
112 | compiled = mktime(&tm_compiled); | |
113 | expire = compiled + ACTIVE_TIME; | |
114 | now = time(NULL); | |
115 | now = mktime(gmtime(&now)); | |
116 | status = (now > expire); | |
117 | return (status); | |
118 | } | |
119 | ||
120 | void | |
121 | print_error(char *string) | |
122 | { | |
123 | fprintf(stderr, "%s: ERROR: %s\n", config_file, string); | |
124 | } | |
125 | ||
126 | static void | |
127 | print_input_error(char *parameter) | |
128 | { | |
129 | sprintf(err_string, "Input error for %s", parameter); | |
130 | print_error(err_string); | |
131 | } | |
132 | ||
133 | /* | |
134 | * Get seeprom parameter value from data structure | |
135 | */ | |
136 | unsigned long long | |
137 | get_seeprom(char *name) | |
138 | { | |
139 | int i = 0; | |
140 | char *parameter; | |
141 | ||
142 | while ((parameter = seeprom_data[i].name) != NULL) { | |
143 | if (strcmp(parameter, name) == 0) { | |
144 | return (seeprom_data[i].value); | |
145 | } | |
146 | i++; | |
147 | } | |
148 | sprintf(err_string, "Cannot find value of %s", name); | |
149 | print_error(err_string); | |
150 | return (0); | |
151 | } | |
152 | ||
153 | static int | |
154 | update_reg(data_reg *cpu_reg, char *name, unsigned long long new, | |
155 | unsigned long long *reg, int num_entries) | |
156 | { | |
157 | int i, found; | |
158 | unsigned long long data; | |
159 | ||
160 | i = found = 0; | |
161 | ||
162 | while (!found && (i < num_entries)) { | |
163 | if (strcmp(cpu_reg[i].name, name) == 0) { | |
164 | int bits, mask; | |
165 | bits = cpu_reg[i].size-1; | |
166 | mask = 1; | |
167 | while (bits) { | |
168 | mask |= (1 << bits); | |
169 | bits--; | |
170 | } | |
171 | data = *reg & | |
172 | (0xffffffffffffffffLL ^ (mask << cpu_reg[i].pos)); | |
173 | data |= ((new & mask) << cpu_reg[i].pos); | |
174 | *reg = data; | |
175 | found = 1; | |
176 | } | |
177 | i++; | |
178 | } | |
179 | return (!found); | |
180 | } | |
181 | ||
182 | /* | |
183 | * Set seeprom parameter value in data structure | |
184 | */ | |
185 | int | |
186 | update_seeprom(char *name, unsigned long long value) | |
187 | { | |
188 | int i = 0, retval = 0; | |
189 | char *s1, *s2; | |
190 | char parameter[MAXNAMESIZE]; | |
191 | void (*notify)(void *data); | |
192 | ||
193 | strcpy(parameter, name); | |
194 | if ((s1 = strtok(parameter, ".")) != NULL) { | |
195 | while ((seeprom_data[i].name) != NULL) { | |
196 | if (strcmp(seeprom_data[i].name, s1) == 0) { | |
197 | s2 = strtok(NULL, "."); | |
198 | notify = seeprom_data[i].notify; | |
199 | if (s2 == NULL) { | |
200 | seeprom_data[i].value = value; | |
201 | } else { | |
202 | int (*funcp)(), num_entries; | |
203 | data_reg *cpu_reg; | |
204 | funcp = seeprom_func[type].reg_func; | |
205 | num_entries = funcp(s1, &cpu_reg); | |
206 | if (num_entries) { | |
207 | retval = update_reg(cpu_reg, | |
208 | s2, value, | |
209 | &seeprom_data[i].value, | |
210 | num_entries); | |
211 | } else { | |
212 | retval = 1; | |
213 | } | |
214 | } | |
215 | if (notify != NULL) notify((void *) value); | |
216 | return (retval); | |
217 | } | |
218 | i++; | |
219 | } | |
220 | } | |
221 | return (1); | |
222 | } | |
223 | ||
224 | /* | |
225 | * Get one parameter value from config file | |
226 | */ | |
227 | static unsigned int | |
228 | get_one_input(int num_input, char *input_str, unsigned long long *input_val) | |
229 | { | |
230 | unsigned int retval; | |
231 | ||
232 | retval = 0; | |
233 | if (--num_input) { | |
234 | if ((strncmp(input_str, "0x", 2) == 0) || | |
235 | (strncmp(input_str, "0X", 2) == 0)) { | |
236 | input_str += 2; | |
237 | retval = sscanf(input_str, "%llx", input_val); | |
238 | } else { | |
239 | retval = sscanf(input_str, "%d", input_val); | |
240 | *input_val >>= 32; | |
241 | } | |
242 | } | |
243 | return (retval); | |
244 | } | |
245 | ||
246 | /* | |
247 | * Check if parameter is from the fixed region | |
248 | */ | |
249 | int | |
250 | fixed_parameter(char *name) | |
251 | { | |
252 | int i = 0; | |
253 | char *c, parameter[MAXNAMESIZE]; | |
254 | ||
255 | strcpy(parameter, name); | |
256 | if ((c = strtok(parameter, ".")) != NULL) { | |
257 | while (seeprom_data[i].name != NULL) { | |
258 | if (strcmp(seeprom_data[i++].name, c) == 0) { | |
259 | return (1); | |
260 | } | |
261 | } | |
262 | } | |
263 | return (0); | |
264 | } | |
265 | ||
266 | /* | |
267 | * Parse parameters | |
268 | */ | |
269 | static int | |
270 | process_line(char *line) | |
271 | { | |
272 | char parameter[MAXNAMESIZE]; | |
273 | char input_str[MAXNAMESIZE]; | |
274 | ||
275 | int num_scanned, error; | |
276 | ||
277 | error = 0; | |
278 | num_scanned = sscanf(line, "%32s %32s", parameter, input_str); | |
279 | #if 0 | |
280 | if (num_scanned != 2) { | |
281 | fprintf(stderr, | |
282 | "WARNING: Ignoring following line:\n%s\n", | |
283 | line); | |
284 | return (0); | |
285 | } | |
286 | #endif | |
287 | if (strcmp(parameter, "cfg_type") == 0) { | |
288 | if (!config_type_init) { | |
289 | if (strcmp(input_str, "cpu") == 0) { | |
290 | type = CPU; | |
291 | seeprom_data = &cpu_seeprom_data[0]; | |
292 | } else if (strcmp(input_str, "sys") == 0) { | |
293 | type = SYS; | |
294 | seeprom_data = &sys_seeprom_data[0]; | |
295 | } else if (strcmp(input_str, "env") == 0) { | |
296 | type = ENV; | |
297 | seeprom_data = &env_seeprom_data[0]; | |
298 | } else if (strcmp(input_str, "mem") == 0) { | |
299 | type = MEM; | |
300 | seeprom_data = &mem_seeprom_data[0]; | |
301 | } else if (strcmp(input_str, "cpu_rw") == 0) { | |
302 | type = CPU_RW; | |
303 | seeprom_data = &cpu_rw_data[0]; | |
304 | } else { | |
305 | fprintf(stderr, " invalid config type: %s\n", | |
306 | input_str); | |
307 | error = 1; | |
308 | } | |
309 | config_type_init = 1; | |
310 | } else { | |
311 | fprintf(stderr, "config type already initialized!\n"); | |
312 | error = 1; | |
313 | } | |
314 | return (error); | |
315 | } | |
316 | ||
317 | if (strcmp(parameter, "system") == 0) { | |
318 | if (!system_type_init) { | |
319 | if (strcmp(input_str, "fiesta") == 0) { | |
320 | system_type = FIESTA; | |
321 | } else if (strcmp(input_str, "gmfiesta") == 0) { | |
322 | system_type = GMFIESTA; | |
323 | if (type == CPU) | |
324 | seeprom_data = &gm_cpu_seeprom_data[0]; | |
325 | } else if (strcmp(input_str, "excalibur") == 0) { | |
326 | system_type = EXCALIBUR; | |
327 | } else if (strcmp(input_str, "serrano") == 0) { | |
328 | system_type = SERRANO; | |
329 | if (type == CPU) | |
330 | seeprom_data = | |
331 | &serrano_cpu_seeprom_data[0]; | |
332 | } else { | |
333 | fprintf(stderr, " invalid system type: %s\n", | |
334 | input_str); | |
335 | error = 1; | |
336 | } | |
337 | system_type_init = 1; | |
338 | } else { | |
339 | fprintf(stderr, "system type already initialized!\n"); | |
340 | error = 1; | |
341 | } | |
342 | if ((system_type == FIESTA || system_type == GMFIESTA || | |
343 | system_type == SERRANO) && | |
344 | type == SYS) | |
345 | seeprom_data = &fiesta_sys_data[0]; | |
346 | return (error); | |
347 | } | |
348 | ||
349 | if (fixed_parameter(parameter)) { | |
350 | unsigned long long input_val; | |
351 | if (get_one_input(num_scanned, input_str, &input_val)) { | |
352 | if (update_seeprom(parameter, input_val)) { | |
353 | error = 1; | |
354 | } | |
355 | } else | |
356 | error = 1; | |
357 | } else { | |
358 | int (*funcp)(); | |
359 | ||
360 | funcp = seeprom_func[type].dynamic_func; | |
361 | switch (funcp(parameter, line)) { | |
362 | case ERROR: | |
363 | error = 1; | |
364 | break; | |
365 | case UNKNOWN: | |
366 | fprintf(stderr, | |
367 | "WARNING: Unknown parameter: %s\n", parameter); | |
368 | break; | |
369 | default: | |
370 | break; | |
371 | } | |
372 | } | |
373 | if (error) | |
374 | print_input_error(parameter); | |
375 | return (error); | |
376 | } | |
377 | ||
378 | /* | |
379 | * Print config info | |
380 | */ | |
381 | static void | |
382 | dump_seeprom(void) | |
383 | { | |
384 | char *string; | |
385 | void (*funcp)(); | |
386 | int i = 0; | |
387 | ||
388 | if (quiet) | |
389 | return; | |
390 | ||
391 | while (seeprom_data[i].name != NULL) { | |
392 | if (strcmp(seeprom_data[i].name, "pad")) { | |
393 | string = strdup(seeprom_data[i].name); | |
394 | string = strcat(string, ":"); | |
395 | printf("%-20s", string); | |
396 | printf(" 0x%llx\n", seeprom_data[i].value); | |
397 | } | |
398 | i++; | |
399 | } | |
400 | printf("\n"); | |
401 | funcp = seeprom_func[type].dump_func; | |
402 | funcp(); | |
403 | } | |
404 | ||
405 | /* | |
406 | * Verify parameters are valid | |
407 | */ | |
408 | static int | |
409 | check_data(void) | |
410 | { | |
411 | int (*funcp)(); | |
412 | funcp = seeprom_func[type].check_func; | |
413 | return (funcp()); | |
414 | } | |
415 | ||
416 | /* | |
417 | * Write n bytes to string | |
418 | */ | |
419 | void | |
420 | store_bytes(unsigned short bytes, unsigned long long data, | |
421 | unsigned char **store_ptr) | |
422 | { | |
423 | unsigned short count; | |
424 | unsigned char byte; | |
425 | ||
426 | count = bytes; | |
427 | ||
428 | while (count) { | |
429 | byte = data >> ((count-1)*8); | |
430 | byte &= 0xff; | |
431 | **store_ptr = byte; | |
432 | *store_ptr += 1; | |
433 | count--; | |
434 | } | |
435 | } | |
436 | ||
437 | /* | |
438 | Generate binary image | |
439 | */ | |
440 | static int | |
441 | write_image(char *out_file) | |
442 | { | |
443 | int i, size; | |
444 | unsigned char *image, *ptr; | |
445 | void (*funcp)(); | |
446 | int file, retval = 0; | |
447 | int checksum_offset = 0; | |
448 | int found = 0; | |
449 | ||
450 | ptr = image = malloc(MAX_IMAGE); | |
451 | ||
452 | i = 0; | |
453 | while (seeprom_data[i].name != NULL) { | |
454 | if (strcmp(seeprom_data[i].name, "checksum")) { | |
455 | if (!found) | |
456 | checksum_offset += seeprom_data[i].size; | |
457 | } else { | |
458 | found = 1; | |
459 | if (do_checksum && seeprom_data[i].size != 2) { | |
460 | fprintf(stderr, "Cannot generate checksum,"); | |
461 | fprintf(stderr, | |
462 | "checksum size must be 2 bytes!\n"); | |
463 | do_checksum = 0; | |
464 | } | |
465 | } | |
466 | store_bytes(seeprom_data[i].size, seeprom_data[i].value, &ptr); | |
467 | i++; | |
468 | } | |
469 | ||
470 | funcp = (void (*)()) seeprom_func[type].write_func; | |
471 | funcp(&ptr); | |
472 | ||
473 | size = ptr-image; | |
474 | if (size > MAX_IMAGE) { | |
475 | sprintf(err_string, | |
476 | "SEEPROM image size of %d," | |
477 | "exceeds maximum size of %d bytes!", | |
478 | size, MAX_IMAGE); | |
479 | print_error(err_string); | |
480 | retval = 1; | |
481 | } else { | |
482 | if (do_checksum) { | |
483 | if (fixed_parameter("checksum")) { | |
484 | /* | |
485 | modify checksum for release images | |
486 | so diff between debug and release | |
487 | version is less obvious | |
488 | */ | |
489 | unsigned short cksum = | |
490 | checksum((unsigned short *) image, size); | |
491 | if (release && type == CPU) | |
492 | cksum *= 2; | |
493 | image[checksum_offset] = (cksum >> 8) & 0xff; | |
494 | image[checksum_offset+1] = cksum & 0xff; | |
495 | } | |
496 | } | |
497 | file = open(out_file, O_CREAT|O_TRUNC|O_WRONLY, 0666); | |
498 | if (file < 0) { | |
499 | fprintf(stderr, "Can't open output file %s\n", | |
500 | out_file); | |
501 | retval = 1; | |
502 | } else { | |
503 | int tmp = write(file, image, size); | |
504 | if (tmp != size) { | |
505 | fprintf(stderr, "Short write on %s\n", | |
506 | out_file); | |
507 | retval = 1; | |
508 | } else { | |
509 | if (!quiet) | |
510 | printf("Wrote %d bytes to %s\n", | |
511 | size, out_file); | |
512 | } | |
513 | close(file); | |
514 | } | |
515 | } | |
516 | free(image); | |
517 | return (retval); | |
518 | } | |
519 | ||
520 | int | |
521 | main(int argc, char **argv) | |
522 | { | |
523 | char *out_file; | |
524 | char line[MAXLINE]; | |
525 | int c; | |
526 | extern char *optarg; | |
527 | extern int optind; | |
528 | char *output_file, *endptr; | |
529 | FILE *file; | |
530 | ||
531 | if (usage_expired()) { | |
532 | fprintf(stderr, "%s: tool expired. Need new copy.\n", argv[0]); | |
533 | exit(1); | |
534 | } | |
535 | ||
536 | while ((c = getopt(argc, argv, "qr")) != EOF) | |
537 | switch (c) { | |
538 | case 'q': | |
539 | quiet = 1; | |
540 | break; | |
541 | #ifndef DEBUG | |
542 | /* r option will clear high bit of id_magic */ | |
543 | /* as well as muddle up checksum. */ | |
544 | case 'r': | |
545 | release = 1; | |
546 | break; | |
547 | #endif | |
548 | default: | |
549 | usage(argv[0]); | |
550 | } | |
551 | ||
552 | ||
553 | if (optind < argc) { | |
554 | config_file = argv[optind]; | |
555 | } else { | |
556 | usage(argv[0]); | |
557 | } | |
558 | ||
559 | if (!quiet) | |
560 | printf("config_file: %s\n", config_file); | |
561 | if ((file = fopen(config_file, "r")) != NULL) { | |
562 | while (fgets(line, MAXLINE, file)) { | |
563 | if ((line[0] != '\n') && (line[0] != '#')) { | |
564 | if (process_line(line)) { | |
565 | exit(1); | |
566 | } | |
567 | } | |
568 | } | |
569 | fclose(file); | |
570 | } else { | |
571 | sprintf(err_string, "Can't open config file %s!", config_file); | |
572 | print_error(err_string); | |
573 | exit(1); | |
574 | } | |
575 | ||
576 | if (check_data()) { | |
577 | fprintf(stderr, "Config file error!\n"); | |
578 | exit(1); | |
579 | } | |
580 | ||
581 | dump_seeprom(); | |
582 | output_file = strdup(config_file); | |
583 | endptr = strrchr(output_file, '.'); | |
584 | if (endptr != NULL) *endptr = 0; | |
585 | out_file = strcat(output_file, ".bin"); | |
586 | /* Debug images have the high bit of id_magic set */ | |
587 | if (force_debug) | |
588 | release = 0; | |
589 | if (type == CPU && !release) { | |
590 | unsigned long long temp; | |
591 | temp = get_seeprom("id_magic"); | |
592 | update_seeprom("id_magic", temp | 0x8000); | |
593 | } | |
594 | if (write_image(out_file)) { | |
595 | sprintf(err_string, "Write to output file %s unsuccessful!", | |
596 | out_file); | |
597 | print_error(err_string); | |
598 | exit(1); | |
599 | } | |
600 | exit(0); | |
601 | } |