FreeCalypso > hg > freecalypso-reveng
comparison fluid-mnf/machine.c @ 311:9cecc930d78f
fluid-mnf: original source from TI,
defenestrated line endings and rearranged directory structure,
but no *.[ch] source file content changes yet
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 29 Feb 2020 05:36:07 +0000 |
parents | |
children | 435e041897f2 |
comparison
equal
deleted
inserted
replaced
310:ae39d76d5b7a | 311:9cecc930d78f |
---|---|
1 /****************************************************************************** | |
2 * FLUID (Flash Loader Utility Independent of Device) | |
3 * | |
4 * Copyright Texas Instruments, 2001. | |
5 * Mads Meisner-Jensen, mmj@ti.com. | |
6 * Original state-machine logic by Delta Technologies, Copyright, 2001. | |
7 * | |
8 * Core functionality. State machines and support functions. | |
9 * | |
10 * $Id: machine.c 1.35.1.37 Mon, 28 Apr 2003 08:49:16 +0200 tsj $ | |
11 * | |
12 ******************************************************************************/ | |
13 | |
14 #include "fluid.h" | |
15 #include "flash.h" | |
16 #include "target.h" | |
17 #include "fileio.h" | |
18 #include "../target/protocol.h" | |
19 #include "misc.h" | |
20 #include "lz.h" | |
21 #include "trace.h" | |
22 // Secure Calypso Plus | |
23 #include "../inc/ram_load.h" | |
24 #include "../inc/secure_types.h" | |
25 | |
26 #include <stdio.h> | |
27 #include <malloc.h> | |
28 #include <stdlib.h> | |
29 #include <string.h> | |
30 | |
31 /****************************************************************************** | |
32 * Constants and typedefs | |
33 ******************************************************************************/ | |
34 | |
35 // Due to memory wrap/mirror used in flash_read_machine(), IMAGE_SIZE_MAX | |
36 // *must* be a power of two. | |
37 #define IMAGE_SIZE_MAX (8 * 1024 * 1024) | |
38 | |
39 #define IMAGE_CHUNK_SIZE 8192 | |
40 | |
41 #define ERASE_LIST_SIZE_MAX 256 | |
42 #define SECTOR_MAP_SIZE_MAX 256 | |
43 | |
44 #define TARGET_PROGRAM_SIZE_MAX (8 * 1024) | |
45 | |
46 #define READ_LIST_SIZE_MAX 40 | |
47 | |
48 #define RETRIES_MAX 30 | |
49 | |
50 // Default target receive delay in milli-seconds. | |
51 #define TARGET_RECV_DELAY 250 | |
52 #define TARGET_RECV_LONG_DELAY 1000 | |
53 | |
54 // Default target reset delay in milli-seconds. | |
55 #define TARGET_RESET_DELAY 200 | |
56 | |
57 // CS_MODE 0: Flash at 0x04000000 @ CS5 on E-Sample | |
58 #define CALP_OFFSET 0x04000000 | |
59 | |
60 /****************************************************************************** | |
61 * Globals | |
62 ******************************************************************************/ | |
63 | |
64 // Secure Calypso Plus | |
65 T_RAM_LOADER d_ram_loader; | |
66 T_FRAME d_frame; | |
67 UWORD16 d_certificate_length = 0; | |
68 char a_certified_cmd_file_name[] = "cmdp_cert.m0"; | |
69 | |
70 struct target_s { | |
71 uint32 cmd_load_addr; | |
72 uint32 method_load_addr; | |
73 const char type; | |
74 const char *name; | |
75 const char *prefix; | |
76 }; | |
77 // Note that the ROM bootloader of Calypso rev. A devices are unable to | |
78 // write the bottom 128kB of internal RAM. Therefore the address have been | |
79 // changed from 0x804000 to 0x0820000 | |
80 const struct target_s target[] = | |
81 { | |
82 { 0x0000000, 0x0000000, 'u', "Unknown", "oops" }, | |
83 { 0x0000000, 0x0000000, 'u', "Unknown1", "oops1" }, | |
84 { 0x0000000, 0x0000000, 'G', "Gemini?", "gem?" }, | |
85 { 0x3004000, 0x3000000, 'U', "Ulysses", "uly" }, | |
86 { 0x0820000, 0x0800000, 'C', "Calypso", "cal" }, | |
87 { 0x0804000, 0x0800000, 'c', "Calypso Lite", "cal_l" }, | |
88 { 0x8020000, 0x8000100, 'P', "Calypso Plus", "cal_p" } | |
89 }; | |
90 int target_type; | |
91 int target_clk; // 13000000 or 14745600 | |
92 | |
93 struct device_s *device; | |
94 | |
95 uint8 target_program[TARGET_PROGRAM_SIZE_MAX]; | |
96 int target_program_size; | |
97 int target_fifo_size; | |
98 | |
99 uint8 image[IMAGE_SIZE_MAX]; | |
100 int image_size; // size of image buffer | |
101 int image_chunk_size; // number of bytes in each chunk | |
102 int image_size_in_chunks; // size of image buffer in chunks | |
103 | |
104 // Each byte in the image_map represents one chunk of the image. Each byte | |
105 // can have one of the following values: | |
106 // '\0' = no data in this chunk | |
107 // 's' = skip this chunk when programming | |
108 // 'c' = chunk checksum ok, skip this chunk when programming | |
109 // 'x' = used | |
110 uint8 image_map[IMAGE_SIZE_MAX / IMAGE_CHUNK_SIZE]; | |
111 int image_map_size; // number of entries in image_map | |
112 | |
113 // Each byte in the sector_map represents one sector. Each byte can have one | |
114 // of the following values: | |
115 // '\0' = sector unused (don't erase) | |
116 // 'c' = sector already empty/erased (don't erase) (not used) | |
117 // 's' = skip this sector when erasing (due to erase override) | |
118 // 'X' = force erase this sector (due to erase override) | |
119 // 'x' = erase this sector (normal case --- sector is covered by image) | |
120 int sector_map[SECTOR_MAP_SIZE_MAX]; | |
121 int sector_map_size; | |
122 | |
123 int erase_list[ERASE_LIST_SIZE_MAX]; | |
124 int erase_list_size; | |
125 | |
126 struct image_part_s read_list[READ_LIST_SIZE_MAX]; | |
127 int read_list_size; | |
128 int read_total_size; | |
129 | |
130 int image_map_count_used_chunks(void); | |
131 int image_map_update(void); | |
132 int sector_map_init(void); | |
133 | |
134 void image_map_show(void); | |
135 void sector_map_show(void); | |
136 void target_timers_show(void); | |
137 | |
138 void parse_arg_erase_override(char *p); | |
139 void parse_arg_read(char *p); | |
140 void parse_arg_write(char *p); | |
141 | |
142 void error_proto(char ch, char ch_expected); | |
143 | |
144 int target_type_set(uint16 code); | |
145 | |
146 // Secure Calypso Plus | |
147 void f_print_signalling_response(int level); | |
148 void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate); | |
149 void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate); | |
150 void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts); | |
151 void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts); | |
152 UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate); | |
153 void target_imei_protection(void); | |
154 | |
155 /****************************************************************************** | |
156 * Main | |
157 ******************************************************************************/ | |
158 | |
159 void bootloader_machine(void); | |
160 void cmd_machine(void); | |
161 void flash_checksum_machine(void); | |
162 void flash_detect_machine(void); | |
163 void method_download_machine(void); | |
164 void flash_program_machine(void); | |
165 void flash_read_machine(void); | |
166 void target_reset_machine(void); | |
167 | |
168 void fluid_machine(void) | |
169 { | |
170 int error; | |
171 | |
172 // If user has specifically asked fluid just to reset the target, we do | |
173 // that and only that! This way, we can use fluid just to reset the | |
174 // target without doing anything else! | |
175 if (arg_target_reset == 2 && arg_dry_run) { | |
176 flowf(VERBOSE, "Resetting target: "); | |
177 target_reset(0); | |
178 target_wait(0, TARGET_RESET_DELAY); | |
179 target_reset(1); | |
180 flowf(VERBOSE, "ok\n"); | |
181 } | |
182 | |
183 file_read_devices("devices.txt"); | |
184 | |
185 if (arg_list_devices) { | |
186 devices_list(); | |
187 exit(0); | |
188 } | |
189 | |
190 image_size = IMAGE_SIZE_MAX; | |
191 image_chunk_size = IMAGE_CHUNK_SIZE; | |
192 image_map_size = IMAGE_SIZE_MAX / image_chunk_size; | |
193 image_size_in_chunks = | |
194 (image_size + image_chunk_size - 1) / image_chunk_size; | |
195 | |
196 // Read the flash image file(s) unless user wants to read from the flash | |
197 if (*arg_read == 0) { | |
198 file_read_image(image, IMAGE_SIZE_MAX, image_map, image_chunk_size); | |
199 | |
200 // Optionally overwrite image with values given on the command-line | |
201 parse_arg_write(arg_write); | |
202 | |
203 if (arg_image_map_show) | |
204 image_map_show(); | |
205 } | |
206 | |
207 if ((error = target_driver_init(arg_uart_port, 115200, | |
208 arg_uart_flowcontrol)) < 0) | |
209 main_fatal(error); | |
210 | |
211 if (target_type_set(arg_target_type) != 0) | |
212 flowf(VERBOSE, "Target type '%s' selected.\n", target[target_type].name); | |
213 | |
214 // Conditionally disable tracing | |
215 if (arg_debug_trace_pe) | |
216 tr_enable(0); | |
217 | |
218 if (arg_debug_resume) { | |
219 // If resuming in command interpreter, we should set the baudrate | |
220 // because we do not pass through the code that normally sets it. | |
221 if ((error = target_driver_baudrate(arg_uart_baudrate)) < 0) | |
222 main_fatal(error); | |
223 } | |
224 else { | |
225 bootloader_machine(); | |
226 cmd_machine(); | |
227 } | |
228 if (*arg_read != 0) { | |
229 parse_arg_read(arg_read); | |
230 flash_read_machine(); | |
231 file_write_image(image, image_size, read_list); | |
232 } | |
233 else { | |
234 if (arg_checksum) | |
235 flash_checksum_machine(); | |
236 flash_detect_machine(); | |
237 if (!arg_debug_resume) { | |
238 method_download_machine(); | |
239 } | |
240 tr_enable(1); // Ensure full tracing is on | |
241 flash_program_machine(); | |
242 if (*arg_imeisv && *arg_platform_certificate_addr) | |
243 target_imei_protection(); | |
244 if (arg_timers_show) | |
245 target_timers_show(); | |
246 if (arg_target_reset == 1) | |
247 target_reset_machine(); | |
248 } | |
249 } | |
250 | |
251 | |
252 /****************************************************************************** | |
253 * Bootloader (TI Target Monitor) Access | |
254 ******************************************************************************/ | |
255 | |
256 // Invoke the Fluid bootloader embedded in the TI bootloader/target-monitor | |
257 // code. The command to enter the loader is 0xAA 0x01 0xDD, which must be | |
258 // received by the phone within 50ms from reset. | |
259 | |
260 int bootloader_is_rom; | |
261 int bootloader_is_secure_rom; // Secure Calypso Plus | |
262 int bootloader_blocksize_max; | |
263 | |
264 void bootloader_fluid_init(void); | |
265 void bootloader_rom_init(void); | |
266 void bootloader_secure_rom_init(void); // Secure Calypso Plus | |
267 | |
268 void bootloader_machine(void) | |
269 { | |
270 // FIXME: why do we have to send an additional char (0) ? | |
271 uint8 sendbuf_rom[3] = { '<', 'i', 0x0 }; | |
272 uint8 sendbuf_fluid[3] = { 0xAA, 0x01, 0xDD }; | |
273 int i, error; | |
274 char ch1, ch2; | |
275 // Secure Calypso Plus | |
276 UWORD16 d_j; | |
277 | |
278 target_trace_enable(0); | |
279 | |
280 flowf(NORMAL, "Bootloader: "); | |
281 | |
282 // Wait a short while with power removed, then flush receive buffer. | |
283 target_power(1); | |
284 target_reset(0); | |
285 target_wait(0, TARGET_RESET_DELAY); | |
286 target_reset(1); | |
287 target_recv_reset(); | |
288 | |
289 // Continuously send Fluid Bootloader escape sequence until we get an | |
290 // acknowledgement. Note that we have to establish contact within 50ms | |
291 // from reset, otherwise we lose our chance! Note that we actually wait | |
292 // up to 500ms because the target may take some time to reset. | |
293 i = 0; | |
294 flowf(DEBUG, "(ROM/fluid-delay = %d/%d, ", | |
295 arg_boot_delay_rom, arg_boot_delay_fluid); | |
296 | |
297 switch (arg_rom_bootloader) { | |
298 case -1: | |
299 if ((error = target_driver_baudrate(115200)) < 0) | |
300 main_fatal(error); | |
301 break; | |
302 case +1: | |
303 if ((error = target_driver_baudrate(19200)) < 0) | |
304 main_fatal(error); | |
305 break; | |
306 } | |
307 while (1) | |
308 { | |
309 target_recv_reset(); | |
310 | |
311 // If we are allowed to try fluid bootloader... | |
312 if (arg_rom_bootloader != +1) { | |
313 // If we should ONLY try fluid bootloader... | |
314 flowf(DEBUG, "F"); | |
315 if (arg_rom_bootloader == 0) | |
316 if ((error = target_driver_baudrate(115200)) < 0) | |
317 main_fatal(error); | |
318 target_send(sendbuf_fluid, 3); | |
319 if (target_wait(1, arg_boot_delay_fluid) > 0 && | |
320 target_getchar() == PROTO_HELLO) { | |
321 bootloader_is_rom = 0; | |
322 bootloader_is_secure_rom = 0; // Secure Calypso Plus | |
323 break; | |
324 } | |
325 } | |
326 // If we are allowed to try ROM bootloader... | |
327 if (arg_rom_bootloader != -1) { | |
328 flowf(DEBUG, "R"); | |
329 if (arg_rom_bootloader == 0) | |
330 if ((error = target_driver_baudrate(19200)) < 0) | |
331 main_fatal(error); | |
332 target_send(sendbuf_rom, 3); | |
333 | |
334 if (target_wait(1, arg_boot_delay_rom) >= 1) { | |
335 ch1 = target_getchar(); | |
336 if (ch1 == '>') { | |
337 if (target_wait(1, arg_boot_delay_rom) >= 1) { | |
338 ch2 = target_getchar(); | |
339 if (ch2 == 'i') { | |
340 bootloader_is_rom = 1; | |
341 | |
342 // Secure Calypso Plus | |
343 if (target_wait(2, arg_boot_delay_rom) < 2) | |
344 flowf(DEBUG, ", Non-secure boot ROM code"); | |
345 else { | |
346 flowf(DEBUG, ", Secure Calypso Plus ROM)"); | |
347 ch1 = target_getchar(); | |
348 ch2 = target_getchar(); | |
349 d_ram_loader.d_romcode_version = (UWORD16)(ch1) & 0xFF; | |
350 d_ram_loader.d_romcode_version |= ((UWORD16)(ch2 & 0xFF)) << 8; | |
351 //d_ram_loader.d_romcode_version |= (((UWORD16)ch2) << 8) & 0xFF00; | |
352 | |
353 if (d_ram_loader.d_romcode_version == 0x0410 || d_ram_loader.d_romcode_version == 0x0411) { | |
354 bootloader_is_secure_rom = 1; | |
355 | |
356 if (target_wait((C_WORD32LGB * C_MD5HASHLG), TARGET_RECV_DELAY) < (C_WORD32LGB * C_MD5HASHLG)) | |
357 main_fatal(E_RECV_TIMEOUT); | |
358 | |
359 for (d_j = 0 ; d_j < (C_WORD32LGB * C_MD5HASHLG) ; d_j++) | |
360 d_ram_loader.a_hash_man_pub_key[d_j] = target_getchar(); | |
361 | |
362 if (target_wait((C_WORD32LGB * C_DIE_ID_SIZE), TARGET_RECV_DELAY) < (C_WORD32LGB * C_DIE_ID_SIZE)) | |
363 main_fatal(E_RECV_TIMEOUT); | |
364 | |
365 for (d_j = 0 ; d_j < (C_WORD32LGB * C_DIE_ID_SIZE) ; d_j++) | |
366 d_ram_loader.a_die_id[d_j] = target_getchar(); | |
367 | |
368 // SIGNALLING RESPONSE | |
369 f_print_signalling_response(VERBOSE); | |
370 | |
371 if (*arg_die_id_file_name != 0) { | |
372 if ((error = file_write_die_id(&d_ram_loader.a_die_id[0], arg_die_id_file_name)) < 0) { | |
373 flowf(NORMAL, "\n"); | |
374 main_fatal(error); | |
375 } | |
376 | |
377 flowf(NORMAL, "\nDie id retrieved and written to %s.\n", arg_die_id_file_name); | |
378 exit(0); | |
379 } | |
380 } | |
381 else { | |
382 flowf(NORMAL, "\nSecure Calypso Plus ROM Code Version 0x%4.4x is not supported by FLUID.\n", d_ram_loader.d_romcode_version); | |
383 main_fatal(E_BOOTLOADER); | |
384 } | |
385 } | |
386 // End Secure Calypso Plus | |
387 | |
388 break; | |
389 } | |
390 else | |
391 flowf(DEBUG, "?"); | |
392 } | |
393 } | |
394 } | |
395 } | |
396 // If target is still not responding, we could not control the reset | |
397 // line, so we ask the user to reset the target | |
398 if (i++ == RETRIES_MAX) | |
399 flowf (NORMAL, "(reset target) "); | |
400 } | |
401 if (!bootloader_is_secure_rom) | |
402 flowf(DEBUG, ") "); | |
403 | |
404 // Read the command interpreter image file. | |
405 if (bootloader_is_secure_rom) | |
406 target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, a_certified_cmd_file_name); | |
407 else | |
408 target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, "cmd.m0"); | |
409 | |
410 if (target_program_size == 0) | |
411 main_error(E_FILE_EMPTY); | |
412 | |
413 if (bootloader_is_secure_rom) | |
414 bootloader_secure_rom_init(); | |
415 else if (bootloader_is_rom) | |
416 bootloader_rom_init(); | |
417 else | |
418 bootloader_fluid_init(); | |
419 | |
420 flowf(NORMAL, ") ok\n"); | |
421 } | |
422 | |
423 void bootloader_fluid_init(void) | |
424 { | |
425 int divider; | |
426 char version; | |
427 uint8 data[4]; | |
428 uint16 chip_id_code; | |
429 | |
430 flowf(NORMAL, "(fluid"); | |
431 | |
432 target_clk = 13000000; | |
433 | |
434 // Now send baudrate to make the target stop sending 'H'ello. | |
435 divider = target_uart_baudrate_divider_get(target_clk, 115200); | |
436 flowf(DEBUG, ", baudrate = "); | |
437 target_putchar(0); | |
438 target_putchar((char) divider); | |
439 flowf(DEBUG, "%d, ", 115200); | |
440 | |
441 // Wait a short while before flushing receive buffer. Then make sure | |
442 // that the target is indeed silent | |
443 target_wait(0, 10); | |
444 target_recv_reset(); | |
445 if (target_wait(1, 50) > 0) | |
446 main_fatal(E_RECV_ANTITIMEOUT); | |
447 | |
448 // NOTEME: The sequence below to query the Bootloader VERSION *has* to | |
449 // have 100ms + 100ms delays. It seems as unnecessarily large delays but | |
450 // practice shows that they cannot be shorter. To be investigated... | |
451 | |
452 // Get version of bootloader | |
453 target_putchar(PROTO_VERSION); | |
454 if (target_wait(1, TARGET_RECV_DELAY) < 1) | |
455 main_fatal(E_RECV_TIMEOUT); | |
456 version = target_getchar(); | |
457 flowf(NORMAL, ", version %c", version); | |
458 | |
459 // Bootloader revision 3 and upwards supports generic query | |
460 if (version < '3') { | |
461 main_fatal(E_BOOTLOADER); | |
462 } | |
463 | |
464 target_trace_enable(1); | |
465 target_putchar(PROTO_QUERY); | |
466 target_putchar(PROTO_QUERY_CHIP); | |
467 if (target_wait(4, TARGET_RECV_DELAY) < 4) | |
468 main_fatal(E_RECV_TIMEOUT); | |
469 target_recv(data, 4); | |
470 chip_id_code = data[0] + (data[1] << 8); | |
471 if (target_type_set(chip_id_code) == 0 || arg_verbose >= VERBOSE) { | |
472 flowf(VERBOSE, ", chipid = 0x%04X", chip_id_code); | |
473 if (target_type_set(chip_id_code) == 0) | |
474 main_fatal(E_TARGET_TYPE); | |
475 } | |
476 flowf(VERBOSE, ", %s", target[target_type].name); | |
477 } | |
478 | |
479 void bootloader_rom_init(void) | |
480 { | |
481 int error; | |
482 char ch, version = '?'; | |
483 | |
484 // Initialization: 115200 bps, 39 MHz DPLL, no timeout | |
485 uint8 sendbuf[11] = { '<', 'p', 0x00, 0x0D, 0x14, 0x25, | |
486 0x22, 0x00, 0x00, 0x00, 0x00}; | |
487 // Initialization: 115200 bps, 13 MHz DPLL, no timeout. | |
488 //uint8 sendbuf[11] = { '<', 'p', 0x00, 0x00, 0x1C, 0xE7, | |
489 // 0x22, 0x00, 0x00, 0x00, 0x00 }; | |
490 | |
491 flowf(NORMAL, "(ROM"); | |
492 | |
493 // Configure/init the ROM bootloader | |
494 flowf(VERBOSE, ", baudrate = %d", 115200); | |
495 target_send(sendbuf, 11); | |
496 | |
497 // Wait until DPLL is settled and target responds | |
498 if (target_wait(4, 300) < 4) | |
499 main_fatal(E_RECV_TIMEOUT); | |
500 if ((ch = target_getchar ()) != '>') | |
501 error_proto(ch, '>'); | |
502 if ((ch = target_getchar ()) != 'p') | |
503 error_proto(ch, 'p'); | |
504 | |
505 // Receive maximum blocksize | |
506 bootloader_blocksize_max = target_getchar(); | |
507 bootloader_blocksize_max += target_getchar() << 8; | |
508 bootloader_blocksize_max -= 10; // Subtract the block header | |
509 flowf(DEBUG, ", blocksize = %iB", bootloader_blocksize_max); | |
510 | |
511 if ((error = target_driver_baudrate (115200)) < 0) | |
512 main_fatal(error); | |
513 | |
514 flowf(NORMAL, ", version %c", version); | |
515 | |
516 // NOTEME: Can we be sure that it is always a Calypso type? | |
517 target_type_set('c'); | |
518 } | |
519 | |
520 // Secure Calypso Plus | |
521 void bootloader_secure_rom_init(void) | |
522 { | |
523 int error; | |
524 UWORD8 d_char; | |
525 UWORD16 d_j; | |
526 | |
527 // cmdp_cert.m0 has been 16 bit aligned using hex470, so the memory width | |
528 // parameter is set to 2 bytes. | |
529 buffer_endian_convert(target_program, target_program_size, 2); | |
530 | |
531 // Check if firmware manufacturer certificate stored in flash is requested | |
532 if (arg_request_certificate) { | |
533 // Clear the request | |
534 arg_request_certificate = 0; | |
535 d_ram_loader.b_certificate_request = C_FALSE; | |
536 | |
537 // Certificate Request | |
538 d_frame.a_data[0] = '<'; | |
539 d_frame.a_data[1] = 'c'; | |
540 d_frame.d_max_byte = 2; | |
541 | |
542 target_send(&d_frame.a_data[0], d_frame.d_max_byte); | |
543 | |
544 // Certificate Response | |
545 target_expect_char('>', arg_boot_delay_rom); | |
546 target_expect_char('c', arg_boot_delay_rom); | |
547 | |
548 if (target_wait(2, TARGET_RECV_DELAY) < 2) | |
549 main_fatal(E_RECV_TIMEOUT); | |
550 | |
551 d_ram_loader.u_firm_cert.a_firm_cert[0] = target_getchar (); | |
552 d_ram_loader.u_firm_cert.a_firm_cert[1] = target_getchar (); | |
553 | |
554 d_certificate_length = (UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[0]) & 0xFF; | |
555 d_certificate_length |= ((UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[1]) << 8) & 0xFF00; | |
556 | |
557 // We have already read two bytes of the certificate for the CERT_SIZE | |
558 // and the certificate signature is handled later. | |
559 for (d_j = 2 ; d_j < d_certificate_length - (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) { | |
560 if (target_wait(1, arg_boot_delay_rom * 4) > 0) | |
561 d_ram_loader.u_firm_cert.a_firm_cert[d_j] = target_getchar (); | |
562 else | |
563 main_fatal(E_RECV_TIMEOUT); | |
564 } | |
565 | |
566 for (d_j = 0; d_j < (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) { | |
567 if (target_wait(1, arg_boot_delay_rom * 4) > 0) | |
568 d_ram_loader.a_Certsig[d_j] = target_getchar (); | |
569 else | |
570 main_fatal(E_RECV_TIMEOUT); | |
571 | |
572 d_ram_loader.u_firm_cert.a_firm_cert[d_j + sizeof(T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA) - (C_WORD32LGB * C_MANUF_SIG_SIZE)] = d_ram_loader.a_Certsig[d_j]; | |
573 } | |
574 | |
575 f_print_certificate_platform_data(NORMAL, &d_ram_loader.u_firm_cert.d_firm_cert); | |
576 } | |
577 | |
578 // Parameter Request | |
579 d_ram_loader.d_baud_rate = f_convert_uart_baud_rate(arg_uart_baudrate_during_cmd_download); | |
580 d_ram_loader.d_uart_timeout = arg_uart_timeout_configuration; // TODO: Verify that MSB byte is sent in first position. | |
581 | |
582 d_frame.a_data[0] = '<'; | |
583 d_frame.a_data[1] = 'p'; | |
584 d_frame.a_data[2] = d_ram_loader.d_baud_rate; | |
585 memcpy(&d_frame.a_data[3], &d_ram_loader.d_uart_timeout, sizeof(UWORD32)); | |
586 | |
587 d_frame.d_max_byte = 3 + sizeof(UWORD32); | |
588 | |
589 d_certificate_length = (UWORD16)(target_program[0]) & 0xFF; | |
590 d_certificate_length |= ((UWORD16)(target_program[1]) & 0xFF) << 8; | |
591 | |
592 for (d_j = 0 ; d_j < d_certificate_length; d_j++) | |
593 d_ram_loader.u_code_certificate.a_code_certificate[d_j] = target_program[d_j]; | |
594 | |
595 f_print_certificate(DEBUG, &d_ram_loader.u_code_certificate.d_code_certificate); | |
596 | |
597 // Send the data | |
598 target_send(&d_frame.a_data[0], d_frame.d_max_byte); | |
599 target_send(&target_program[0], d_certificate_length); | |
600 | |
601 // Parameter Response | |
602 if (target_wait(2, TARGET_RECV_DELAY) < 2) | |
603 main_fatal(E_RECV_TIMEOUT); | |
604 | |
605 if ((d_char = target_getchar ()) != '>') | |
606 error_proto(d_char, '>'); | |
607 | |
608 if ((d_char = target_getchar ()) != 'p') { | |
609 if (d_char == 'P') { | |
610 // PARAMETER_NACK_RESPONSE | |
611 if (target_wait(1, arg_boot_delay_rom) >= 1) { | |
612 d_ram_loader.d_param_req_sts = target_getchar(); | |
613 f_print_parameter_nack_status(NORMAL, d_ram_loader.d_param_req_sts); | |
614 } | |
615 } | |
616 error_proto(d_char, 'p'); | |
617 } | |
618 | |
619 // PARAMETER_ACK_RESPONSE | |
620 | |
621 flowf(NORMAL, "\n(Secure ROM"); | |
622 | |
623 if ((error = target_driver_baudrate (arg_uart_baudrate_during_cmd_download)) < 0) | |
624 main_fatal(error); | |
625 | |
626 // Configure/init the ROM bootloader | |
627 flowf(VERBOSE, ", UART baud rate during download of flash programmer, %s = %d Kbps", a_certified_cmd_file_name, arg_uart_baudrate_during_cmd_download); | |
628 } | |
629 // End Secure Calypso Plus | |
630 | |
631 /****************************************************************************** | |
632 * Command Interpreter Download | |
633 ******************************************************************************/ | |
634 | |
635 int cmd_baudrate(int baudrate); | |
636 void cmd_machine_fluid(void); | |
637 void cmd_machine_rom(void); | |
638 void cmd_machine_secure_rom(void); // Secure Calypso Plus | |
639 | |
640 void cmd_machine(void) | |
641 { | |
642 char ramcs0, ch; | |
643 uint8 count = 0; | |
644 uint16 chip_id; | |
645 | |
646 flowf(VERBOSE, "Command Interpreter: ("); | |
647 | |
648 target_trace_enable(0); | |
649 | |
650 // Secure Calypso Plus | |
651 if (bootloader_is_secure_rom) | |
652 cmd_machine_secure_rom(); | |
653 else if (bootloader_is_rom) | |
654 cmd_machine_rom(); | |
655 else | |
656 cmd_machine_fluid(); | |
657 | |
658 // Now send 'H'ello command to target and get the response, such as | |
659 // hardware type etc. | |
660 while (count < RETRIES_MAX) { | |
661 target_putchar(PROTO_HELLO); | |
662 if (target_wait(1, TARGET_RECV_DELAY) >= 1) { | |
663 ch = target_getchar(); | |
664 flowf(DEBUG, ", received %c (0x%2.2x)", ch, ch); | |
665 if (ch == PROTO_READY) | |
666 break; | |
667 } | |
668 count++; | |
669 } | |
670 | |
671 if (count == RETRIES_MAX) | |
672 main_fatal(E_RECV_TIMEOUT); | |
673 | |
674 if (target_wait(5, TARGET_RECV_DELAY) < 4) | |
675 main_fatal(E_RECV_TIMEOUT); | |
676 | |
677 chip_id = (target_getchar() & 0xFF); | |
678 chip_id |= (target_getchar() & 0xFF) << 8; | |
679 ramcs0 = (target_getchar() == 'R'); | |
680 ch = target_getchar(); | |
681 flowf(BLABBER, ", SRAM = %dk", (1 << ch) / 1024); | |
682 target_fifo_size = target_getchar(); | |
683 flowf(DEBUG, ", fifo = %d", target_fifo_size); | |
684 | |
685 if (target_type_set(chip_id) == 0 || arg_verbose >= VERBOSE) { | |
686 flowf(BLABBER, ", "); | |
687 flowf(VERBOSE, "chipid = 0x%04X", chip_id); | |
688 if (target_type_set(chip_id) == 0) | |
689 main_fatal(E_TARGET_TYPE); | |
690 } | |
691 flowf(VERBOSE, ", %s", target[target_type].name); | |
692 | |
693 if (ramcs0) | |
694 flowf(VERBOSE, ", RAM"); | |
695 | |
696 // Configure target | |
697 target_putchar(PROTO_INIT); | |
698 target_putchar(target[target_type].type); | |
699 target_expect_char(PROTO_READY, TARGET_RECV_DELAY); | |
700 | |
701 // Change baudrate. First try to change to new baudrate. If this fails, | |
702 // try 115.2 Kbps. If this also fails, panic and bail out. | |
703 if (arg_uart_baudrate != 115200) { | |
704 flowf(VERBOSE, ", baudrate = "); | |
705 flowf(VERBOSE, "%d", arg_uart_baudrate); | |
706 if (!cmd_baudrate(arg_uart_baudrate)) { | |
707 arg_uart_baudrate = 115200; | |
708 flowf(VERBOSE, " %d", arg_uart_baudrate); | |
709 if (!cmd_baudrate(arg_uart_baudrate)) | |
710 main_fatal(E_RECV_TIMEOUT); | |
711 } | |
712 } | |
713 flowf(VERBOSE, ") "); | |
714 flowf(VERBOSE, "ok\n"); | |
715 | |
716 // Secure Calypso Plus | |
717 | |
718 // There is a bug in ROM code 0x0410 which means that the secure boot | |
719 // loader cannot boot if the firmware certificate size is greater than the | |
720 // max size of 0xFFF8. A workaround is to change the memory mapping on CS5 | |
721 // by initially setting DIP switches 9 and 10 to ON and thereby exchanging | |
722 // the mapping of RAM and flash. While waiting, set the DIP switches back | |
723 // to OFF. See SECURITY.txt and BUG03314 in CALPLUS228. | |
724 if (arg_delay_for_changing_cs5 != 0) { | |
725 flowf(NORMAL, "\nWaiting %d seconds for changing memory mapping on CS5 or connecting via JTAG...\n", arg_delay_for_changing_cs5); | |
726 target_wait(0, arg_delay_for_changing_cs5 * 1000); | |
727 } | |
728 } | |
729 | |
730 int cmd_baudrate(int baudrate) | |
731 { | |
732 int error; | |
733 int divider; | |
734 char xxo; | |
735 | |
736 target_putchar(PROTO_BAUDRATE); | |
737 if (baudrate == 230400 || baudrate == 460800 || baudrate == 921600) { | |
738 // Changing the target clock frequency to 14 MHz | |
739 target_clk = 14745600; | |
740 // If we are using a 14 MHz compatible baud rate, we should enable the | |
741 // eXternal Xtal Oscillator of the target | |
742 xxo = PROTO_BAUDRATE_XXO; | |
743 } | |
744 else { | |
745 target_clk = 13000000; | |
746 xxo = 0; | |
747 } | |
748 | |
749 divider = target_uart_baudrate_divider_get(target_clk, baudrate); | |
750 target_putchar(xxo); | |
751 target_putchar((char) divider); | |
752 | |
753 if ((error = target_driver_baudrate(baudrate)) < 0) | |
754 main_fatal(error); | |
755 | |
756 // Wait for acknowledgement | |
757 if (target_wait(1, 2 * TARGET_RECV_DELAY) >= 1 && | |
758 target_getchar() == PROTO_READY) { | |
759 return 1; | |
760 } | |
761 else { | |
762 if ((error = target_driver_baudrate(115200)) < 0) | |
763 main_fatal(error); | |
764 return 0; | |
765 } | |
766 } | |
767 | |
768 void cmd_machine_fluid(void) | |
769 { | |
770 uint8 sendbuf[1+4+2]; | |
771 int error; | |
772 | |
773 // Send 'Download' command header. Then wait for acknowledgement. | |
774 buf_put1(&sendbuf[0], PROTO_DOWNLOAD); | |
775 buf_put4(&sendbuf[1], target[target_type].cmd_load_addr); | |
776 buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2); | |
777 target_send(sendbuf, 1+4+2); | |
778 flowf(BLABBER, "0x%X", target[target_type].cmd_load_addr); | |
779 if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) | |
780 main_fatal(error); | |
781 | |
782 // Send data. Then wait for acknowledgement. | |
783 target_trace_enable(1); | |
784 target_send(target_program, target_program_size); | |
785 flowf(BLABBER, ", %d", target_program_size); | |
786 } | |
787 | |
788 void cmd_machine_rom(void) | |
789 { | |
790 uint8 sendbuf[10], *buf; | |
791 int error, i; | |
792 int block_addr; | |
793 int block_offset = 0; | |
794 int block_size; | |
795 uint8 ch, blksum, cksum = 0; | |
796 | |
797 // NOTEME: Can we be sure that it is always a Calypso type? | |
798 target_type_set('c'); | |
799 | |
800 block_addr = target[target_type].cmd_load_addr; | |
801 | |
802 buffer_endian_convert(target_program, target_program_size, 2); | |
803 | |
804 flowf(BLABBER, "0x%X, ", target[target_type].cmd_load_addr); | |
805 | |
806 // Transfer the target program as blocks | |
807 while (block_offset < target_program_size) | |
808 { | |
809 block_size = target_program_size - block_offset; | |
810 if (block_size > bootloader_blocksize_max) | |
811 block_size = bootloader_blocksize_max; | |
812 | |
813 // Initialize block transfer | |
814 buf = sendbuf; | |
815 buf += buf_put1(buf, '<'); | |
816 buf += buf_put1(buf, 'w'); | |
817 buf += buf_put1(buf, 0x01); // block index - just use #1 - not important | |
818 buf += buf_put1(buf, 0x01); // block number - just use #1 - not important | |
819 buf += buf_put2no(buf, (uint16) block_size); | |
820 buf += buf_put4no(buf, block_addr + block_offset); | |
821 target_send(sendbuf, 10); | |
822 | |
823 // Send the data | |
824 target_send(&target_program[block_offset], block_size); | |
825 | |
826 // Calculate block check-sum | |
827 blksum = 5; | |
828 blksum += block_size & 0x00ff; | |
829 blksum += (((block_addr + block_offset) & 0xff000000) >> 24); | |
830 blksum += (((block_addr + block_offset) & 0x00ff0000) >> 16); | |
831 blksum += (((block_addr + block_offset) & 0x0000ff00) >> 8); | |
832 blksum += ( (block_addr + block_offset) & 0x000000ff); | |
833 for (i = block_offset; i < (block_offset + block_size); i++) | |
834 blksum += target_program[i]; | |
835 cksum += ~blksum; | |
836 | |
837 block_offset = block_offset + block_size; | |
838 | |
839 if ((error = target_expect_char ('>', TARGET_RECV_DELAY)) < 0) | |
840 main_fatal (error); | |
841 if ((error = target_expect_char ('w', TARGET_RECV_DELAY)) < 0) | |
842 main_fatal (error); | |
843 | |
844 flowf(BLABBER, "."); | |
845 } | |
846 flowf(BLABBER, ", %d", target_program_size); | |
847 target_wait(0, 100); | |
848 | |
849 // Request compare of checksum | |
850 target_putchar('<'); | |
851 target_putchar('c'); | |
852 target_putchar((char) ~cksum); | |
853 | |
854 if ((error = target_expect_char('>', TARGET_RECV_DELAY)) < 0) | |
855 main_fatal(error); | |
856 if ((error = target_expect_char('c', TARGET_RECV_DELAY)) < 0) | |
857 main_fatal(error); | |
858 if ((error = target_wait(1, TARGET_RECV_DELAY)) < 1) | |
859 main_fatal(error); | |
860 ch = target_getchar(); | |
861 flowf(DEBUG, ", cksum = 0x%x (0x%x)", ch, cksum); | |
862 if (ch != cksum) | |
863 main_fatal(E_SEND_CHECKSUM); | |
864 | |
865 // Branch to code | |
866 buf = sendbuf; | |
867 buf += buf_put1(buf, '<'); | |
868 buf += buf_put1(buf, 'b'); | |
869 buf += buf_put4no(buf, target[target_type].cmd_load_addr); | |
870 target_send(sendbuf, 6); | |
871 | |
872 if (target_wait(2, TARGET_RECV_DELAY) < 2) | |
873 main_fatal(E_RECV_TIMEOUT); | |
874 if ((ch = target_getchar()) != '>') | |
875 error_proto(ch, '>'); | |
876 if ((ch = target_getchar()) != 'b') | |
877 error_proto(ch, 'b'); | |
878 | |
879 target_wait(0, 100); | |
880 } | |
881 | |
882 // Secure Calypso Plus | |
883 void cmd_machine_secure_rom(void) | |
884 { | |
885 UWORD8 d_char; | |
886 UWORD16 d_i; | |
887 | |
888 target_type_set('p'); | |
889 flowf(BLABBER, "0x%X", d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode); | |
890 flowf(DEBUG, ")"); | |
891 | |
892 // Prepare the write command | |
893 d_ram_loader.d_nb_byte_in_block = (UWORD32) arg_block_size; | |
894 d_ram_loader.d_nb_byte_sent = 0; | |
895 d_ram_loader.d_block_address = d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode; | |
896 | |
897 while (d_ram_loader.d_nb_byte_sent < d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize) { | |
898 flowf(DEBUG, "\nCurrent write parameters:\n"); | |
899 flowf(DEBUG, " Max Number of Bytes in Block: %ld\n", d_ram_loader.d_nb_byte_in_block); | |
900 flowf(DEBUG, " Block Address : 0x%8.8lx\n", d_ram_loader.d_block_address); | |
901 flowf(DEBUG, " Code Size : %ld\n", d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize); | |
902 flowf(DEBUG, " Bytes sent : %ld\n", d_ram_loader.d_nb_byte_sent); | |
903 | |
904 // Set block size | |
905 d_ram_loader.d_block_size = d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize - d_ram_loader.d_nb_byte_sent; | |
906 if (d_ram_loader.d_block_size > d_ram_loader.d_nb_byte_in_block) | |
907 d_ram_loader.d_block_size = d_ram_loader.d_nb_byte_in_block; | |
908 | |
909 flowf(DEBUG, " Block Size : %ld\n", d_ram_loader.d_block_size); | |
910 | |
911 // Write Request | |
912 d_frame.a_data[0] = '<'; | |
913 d_frame.a_data[1] = 'w'; | |
914 | |
915 // Send block size | |
916 for (d_i = 0; d_i < 32; d_i += 8) | |
917 d_frame.a_data[2 + d_i / 8] = (UWORD8)(d_ram_loader.d_block_size >> (24 - d_i)); | |
918 | |
919 // Send block address | |
920 for (d_i = 0; d_i < 32; d_i += 8) | |
921 d_frame.a_data[2 + sizeof(UWORD32) + d_i / 8] = (UWORD8)(d_ram_loader.d_block_address >> (24 - d_i)); | |
922 | |
923 d_frame.d_max_byte = 2 + sizeof(UWORD32) + sizeof(UWORD32); | |
924 | |
925 // Send the data | |
926 target_send(&d_frame.a_data[0], d_frame.d_max_byte); | |
927 target_send(&target_program[d_certificate_length + d_ram_loader.d_nb_byte_sent], d_ram_loader.d_block_size); | |
928 | |
929 // Update next block address | |
930 d_ram_loader.d_block_address += d_ram_loader.d_block_size; | |
931 d_ram_loader.d_nb_byte_sent += d_ram_loader.d_block_size; | |
932 | |
933 // Write Response | |
934 if (target_wait(2, TARGET_RECV_DELAY) < 2) | |
935 main_fatal(E_RECV_TIMEOUT); | |
936 | |
937 if ((d_char = target_getchar ()) != '>') | |
938 error_proto(d_char, '>'); | |
939 | |
940 if ((d_char = target_getchar ()) != 'w') { | |
941 if (d_char == 'W') { | |
942 // WRITE_NACK_RESPONSE | |
943 if (target_wait(1, arg_boot_delay_rom) >= 1) { | |
944 d_ram_loader.d_write_status = target_getchar(); | |
945 f_print_write_nack_status(NORMAL, d_ram_loader.d_write_status); | |
946 } | |
947 } | |
948 error_proto(d_char, 'w'); | |
949 } | |
950 | |
951 // WRITE_ACK_RESPONSE | |
952 } // End while | |
953 if (arg_verbose == BLABBER) | |
954 flowf(BLABBER, ", "); | |
955 else | |
956 flowf(DEBUG, "("); | |
957 | |
958 flowf(BLABBER, "%d", d_ram_loader.d_nb_byte_sent); | |
959 target_wait(0, 100); | |
960 | |
961 // Abort Request | |
962 d_frame.a_data[0] = '<'; | |
963 d_frame.a_data[1] = 'a'; | |
964 d_frame.d_max_byte = 2; | |
965 | |
966 target_send(&d_frame.a_data[0], d_frame.d_max_byte); | |
967 target_wait(0, 100); | |
968 } | |
969 | |
970 void f_print_signalling_response(int level) { | |
971 UWORD16 d_i; | |
972 | |
973 flowf(level, "\nSignalling Response:\n"); | |
974 | |
975 flowf(level, " ROM Code Version: 0x%4.4x\n", d_ram_loader.d_romcode_version); | |
976 | |
977 flowf(level, " Hash (ManPubKey): "); | |
978 for (d_i = 0; d_i < (C_WORD32LGB * C_MD5HASHLG); d_i++) { | |
979 if (d_i == (C_WORD32LGB * C_MD5HASHLG) / 2) | |
980 flowf(level, "\n "); | |
981 flowf(level, "0x%2.2x ", d_ram_loader.a_hash_man_pub_key[d_i]); | |
982 } | |
983 flowf(level, "\n"); | |
984 | |
985 flowf(level, " Die Id : "); | |
986 for (d_i = 0; d_i < (C_WORD32LGB * C_DIE_ID_SIZE); d_i++) | |
987 flowf(level, "0x%2.2x ", d_ram_loader.a_die_id[d_i]); | |
988 flowf(level, "\n"); | |
989 } /* f_print_signalling_response() */ | |
990 | |
991 void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate) { | |
992 UWORD16 d_i, d_j, d_max = 4; | |
993 | |
994 flowf(level, "\nFirmware Manufacturer Certificate:\n"); | |
995 flowf(level, "----------------------------------\n"); | |
996 | |
997 flowf(level, " Size of Certificate: %d bytes\n", p_certificate->d_manufacturer_certificate.d_Certsize); | |
998 flowf(level, " Type of Certificate: 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Certtype); | |
999 flowf(level, " Emulation Request : 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Debugrequest); | |
1000 flowf(level, " Address of Code : 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Addcode); | |
1001 flowf(level, " Size of Code : %ld bytes\n", p_certificate->d_manufacturer_certificate.d_Codesize); | |
1002 flowf(level, " Entry Point Address: 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_CodeStartAdd); | |
1003 | |
1004 flowf(level, " Manufacturer Public Key:\n"); | |
1005 flowf(level, " Public Modulus:"); | |
1006 d_j = d_max; | |
1007 for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { | |
1008 if (d_j++ == d_max) { | |
1009 flowf(level, "\n "); | |
1010 d_j = 1; | |
1011 } | |
1012 flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Manpubkey.a_Modulus[d_i]); | |
1013 } | |
1014 flowf(level, "\n"); | |
1015 flowf(level, " Public Modulus Length:\n"); | |
1016 flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_ModulusLength); | |
1017 flowf(level, " Public Exponent:\n"); | |
1018 flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_Exponent); | |
1019 | |
1020 flowf(level, " Originator Public Key:\n"); | |
1021 flowf(level, " Public Modulus:"); | |
1022 d_j = d_max; | |
1023 for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { | |
1024 if (d_j++ == d_max) { | |
1025 flowf(level, "\n "); | |
1026 d_j = 1; | |
1027 } | |
1028 flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Origpubkey.a_Modulus[d_i]); | |
1029 } | |
1030 flowf(level, "\n"); | |
1031 flowf(level, " Public Modulus Length:\n"); | |
1032 flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_ModulusLength); | |
1033 flowf(level, " Public Exponent:\n"); | |
1034 flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_Exponent); | |
1035 | |
1036 flowf(level, " Originator Public Key Signature:"); | |
1037 d_j = d_max; | |
1038 for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { | |
1039 if (d_j++ == d_max) { | |
1040 flowf(level, "\n "); | |
1041 d_j = 1; | |
1042 } | |
1043 flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Origpubkeysig[d_i]); | |
1044 } | |
1045 flowf(level, "\n"); | |
1046 | |
1047 flowf(level, " Software Signature:"); | |
1048 d_j = d_max; | |
1049 for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { | |
1050 if (d_j++ == d_max) { | |
1051 flowf(level, "\n "); | |
1052 d_j = 1; | |
1053 } | |
1054 flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Swsig[d_i]); | |
1055 } | |
1056 flowf(level, "\n"); | |
1057 | |
1058 flowf(level, " Configuration Parameters:\n"); | |
1059 flowf(level, " CONF_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_conf_cs5); | |
1060 flowf(level, " EXWS_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_exws_cs5); | |
1061 flowf(level, " EX_CTRL register : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_ex_ctrl); | |
1062 flowf(level, " CS image request : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_cs_img_req); | |
1063 flowf(level, " Flash size : %ld bytes\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_flash_size); | |
1064 flowf(level, " Granularity : %ld words\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_granularity); | |
1065 | |
1066 flowf(level, " Die Id: "); | |
1067 for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) { | |
1068 flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_die_id[d_i]); | |
1069 } | |
1070 flowf(level, "\n"); | |
1071 | |
1072 if (p_certificate->d_manufacturer_certificate.d_Certsize > (sizeof(T_MANUFACTURER_CERTIFICATE) + (C_WORD32LGB * C_MANUF_SIG_SIZE))) { | |
1073 flowf(level, " Platform Data:"); | |
1074 d_j = d_max; | |
1075 for(d_i = 0; d_i < (p_certificate->d_manufacturer_certificate.d_Certsize - sizeof(T_MANUFACTURER_CERTIFICATE) - (C_WORD32LGB * C_MANUF_SIG_SIZE)) / sizeof(UWORD32); d_i++) { | |
1076 if (d_j++ == d_max) { | |
1077 flowf(level, "\n "); | |
1078 d_j = 1; | |
1079 } | |
1080 flowf(level, "0x%8.8lx ", p_certificate->a_platform_data[d_i]); | |
1081 } | |
1082 flowf(level, "\n"); | |
1083 } | |
1084 | |
1085 flowf(level, " Certificate Signature:"); | |
1086 d_j = d_max; | |
1087 for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) { | |
1088 if (d_j++ == d_max) { | |
1089 flowf(level, "\n "); | |
1090 d_j = 1; | |
1091 } | |
1092 flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]); | |
1093 } | |
1094 flowf(level, "\n"); | |
1095 } /* f_print_certificate_platform_data() */ | |
1096 | |
1097 void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate) { | |
1098 UWORD16 d_i, d_j, d_max = 4; | |
1099 | |
1100 flowf(level, "\nFlash Programmer Manufacturer Certificate:\n"); | |
1101 flowf(level, "------------------------------------------\n"); | |
1102 | |
1103 flowf(level, " Size of Certificate: %d bytes\n", p_certificate->d_Certsize); | |
1104 flowf(level, " Type of Certificate: 0x%2.2x\n", p_certificate->d_Certtype); | |
1105 flowf(level, " Emulation Request : 0x%2.2x\n", p_certificate->d_Debugrequest); | |
1106 flowf(level, " Address of Code : 0x%8.8lx\n", p_certificate->d_Addcode); | |
1107 flowf(level, " Size of Code : %ld bytes\n", p_certificate->d_Codesize); | |
1108 flowf(level, " Entry Point Address: 0x%8.8lx\n", p_certificate->d_CodeStartAdd); | |
1109 | |
1110 flowf(level, " Manufacturer Public key:\n"); | |
1111 flowf(level, " Public Modulus:"); | |
1112 d_j = d_max; | |
1113 for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { | |
1114 if (d_j++ == d_max) { | |
1115 flowf(level, "\n "); | |
1116 d_j = 1; | |
1117 } | |
1118 flowf(level, "0x%8.8lx ", p_certificate->d_Manpubkey.a_Modulus[d_i]); | |
1119 } | |
1120 flowf(level, "\n"); | |
1121 flowf(level, " Public Modulus Length:\n"); | |
1122 flowf(level, " 0x%8.8lx\n", p_certificate->d_Manpubkey.d_ModulusLength); | |
1123 flowf(level, " Public Exponent:\n"); | |
1124 flowf(level, " 0x%8.8lx\n", p_certificate->d_Manpubkey.d_Exponent); | |
1125 | |
1126 flowf(level, " Originator Public key:\n"); | |
1127 flowf(level, " Public Modulus:"); | |
1128 d_j = d_max; | |
1129 for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { | |
1130 if (d_j++ == d_max) { | |
1131 flowf(level, "\n "); | |
1132 d_j = 1; | |
1133 } | |
1134 flowf(level, "0x%8.8lx ", p_certificate->d_Origpubkey.a_Modulus[d_i]); | |
1135 } | |
1136 flowf(level, "\n"); | |
1137 flowf(level, " Public Modulus Length:\n"); | |
1138 flowf(level, " 0x%8.8lx\n", p_certificate->d_Origpubkey.d_ModulusLength); | |
1139 flowf(level, " Public Exponent:\n"); | |
1140 flowf(level, " 0x%8.8lx\n", p_certificate->d_Origpubkey.d_Exponent); | |
1141 | |
1142 flowf(level, " Originator Public Key Signature:"); | |
1143 d_j = d_max; | |
1144 for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { | |
1145 if (d_j++ == d_max) { | |
1146 flowf(level, "\n "); | |
1147 d_j = 1; | |
1148 } | |
1149 flowf(level, "0x%8.8lx ", p_certificate->a_Origpubkeysig[d_i]); | |
1150 } | |
1151 flowf(level, "\n"); | |
1152 | |
1153 flowf(level, " Software Signature:"); | |
1154 d_j = d_max; | |
1155 for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { | |
1156 if (d_j++ == d_max) { | |
1157 flowf(level, "\n "); | |
1158 d_j = 1; | |
1159 } | |
1160 flowf(level, "0x%8.8lx ", p_certificate->a_Swsig[d_i]); | |
1161 } | |
1162 flowf(level, "\n"); | |
1163 | |
1164 flowf(level, " Configuration Parameters:\n"); | |
1165 flowf(level, " CONF_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_conf_cs5); | |
1166 flowf(level, " EXWS_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_exws_cs5); | |
1167 flowf(level, " EX_CTRL register : %4.4x\n",p_certificate->d_Confparam.d_ex_ctrl); | |
1168 flowf(level, " CS image request : %4.4x\n",p_certificate->d_Confparam.d_cs_img_req); | |
1169 flowf(level, " Flash size : %ld bytes\n",p_certificate->d_Confparam.d_flash_size); | |
1170 flowf(level, " Granularity : %ld words\n",p_certificate->d_Confparam.d_granularity); | |
1171 | |
1172 flowf(level, " Die Id: "); | |
1173 for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) { | |
1174 flowf(level, "0x%8.8lx ", p_certificate->a_die_id[d_i]); | |
1175 } | |
1176 flowf(level, "\n"); | |
1177 | |
1178 flowf(level, " Certificate Signature:"); | |
1179 d_j = d_max; | |
1180 for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) { | |
1181 if (d_j++ == d_max) { | |
1182 flowf(level, "\n "); | |
1183 d_j = 1; | |
1184 } | |
1185 flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]); | |
1186 } | |
1187 flowf(level, "\n"); | |
1188 } /* f_print_certificate() */ | |
1189 | |
1190 void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts) { | |
1191 flowf(level, "\nParameter NAck Response Status:\n"); | |
1192 flowf(level, " 0x%2.2x", d_parameter_nack_sts); | |
1193 | |
1194 switch(d_parameter_nack_sts) { | |
1195 case 0x01 : { flowf(level, " Incorrect baud rate\n"); break; } | |
1196 case 0x02 : { flowf(level, " Incorrect certificate\n"); break; } | |
1197 case 0x03 : { flowf(level, " Incorrect code address\n"); break; } | |
1198 } | |
1199 | |
1200 flowf(level, "\n"); | |
1201 } /* f_print_parameter_nack_status() */ | |
1202 | |
1203 void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts) { | |
1204 flowf(level, "\nWrite NAck Response Status:\n"); | |
1205 flowf(level, " 0x%2.2x", d_write_nack_sts); | |
1206 | |
1207 switch(d_write_nack_sts) { | |
1208 case 0x01 : { flowf(level, " Incorrect block address\n"); break; } | |
1209 case 0x02 : { flowf(level, " Non-64 bytes block size\n"); break; } | |
1210 case 0x03 : { flowf(level, " First block is not code address\n"); break; } | |
1211 case 0x04 : { flowf(level, " Error in firmware signature check\n"); break; } | |
1212 case 0x05 : { flowf(level, " Received code size does not match the code size in certificate\n"); break; } | |
1213 case 0x06 : { flowf(level, " Error during block hashing\n"); break; } | |
1214 } | |
1215 | |
1216 flowf(level, "\n"); | |
1217 } /* f_print_write_nack_status() */ | |
1218 | |
1219 UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate) { | |
1220 UWORD8 d_converted_baud_rate; | |
1221 | |
1222 switch (d_baud_rate) { | |
1223 case 0: | |
1224 case 812: | |
1225 case 812500: { | |
1226 d_converted_baud_rate = 0x00; | |
1227 arg_uart_baudrate_during_cmd_download = 812500; | |
1228 break; | |
1229 } | |
1230 case 1: | |
1231 case 406: | |
1232 case 406250: { | |
1233 d_converted_baud_rate = 0x01; | |
1234 arg_uart_baudrate_during_cmd_download = 406250; | |
1235 break; | |
1236 } | |
1237 case 2: | |
1238 case 203: | |
1239 case 203125: { | |
1240 d_converted_baud_rate = 0x02; | |
1241 arg_uart_baudrate_during_cmd_download = 203125; | |
1242 break; | |
1243 } | |
1244 case 3: | |
1245 case 115: | |
1246 case 115200: { | |
1247 d_converted_baud_rate = 0x03; | |
1248 arg_uart_baudrate_during_cmd_download = 115200; | |
1249 break; | |
1250 } | |
1251 case 4: | |
1252 case 57: | |
1253 case 57600: { | |
1254 d_converted_baud_rate = 0x04; | |
1255 arg_uart_baudrate_during_cmd_download = 57600; | |
1256 break; | |
1257 } | |
1258 case 5: | |
1259 case 38: | |
1260 case 38400: { | |
1261 d_converted_baud_rate = 0x05; | |
1262 arg_uart_baudrate_during_cmd_download = 38400; | |
1263 break; | |
1264 } | |
1265 case 6: | |
1266 case 28: | |
1267 case 28800: { | |
1268 d_converted_baud_rate = 0x06; | |
1269 arg_uart_baudrate_during_cmd_download = 28800; | |
1270 break; | |
1271 } | |
1272 case 7: | |
1273 case 19: | |
1274 case 19200: { | |
1275 d_converted_baud_rate = 0x07; | |
1276 arg_uart_baudrate_during_cmd_download = 19200; | |
1277 break; | |
1278 } | |
1279 default: { | |
1280 d_converted_baud_rate = 0x03; | |
1281 arg_uart_baudrate_during_cmd_download = 115200; | |
1282 break; | |
1283 } | |
1284 } | |
1285 | |
1286 return d_converted_baud_rate; | |
1287 } /* f_convert_uart_baud_rate() */ | |
1288 | |
1289 void target_imei_protection(void) | |
1290 { | |
1291 uint8 a_imeisv[C_IMEISV_BYTES]; | |
1292 uint8 a_platform_cert_addr[C_PLATFORM_CERT_ADDR_BYTES]; | |
1293 uint8 d_i, d_digit, d_temp; | |
1294 uint8 d_error; | |
1295 | |
1296 flowf(NORMAL, "\nIMEI protection: "); | |
1297 | |
1298 if (arg_dry_run) { | |
1299 flowf(NORMAL, "(dry-run) ok\n"); | |
1300 return; | |
1301 } | |
1302 | |
1303 target_putchar(PROTO_IMEI_PROTECT); | |
1304 | |
1305 // Send IMEI-SV | |
1306 for (d_i = 0; d_i < C_IMEISV_DIGITS; d_i++) { | |
1307 sscanf(arg_imeisv++, "%1d", &d_digit); | |
1308 if (!(d_i & 1)) | |
1309 d_temp = d_digit << 4; | |
1310 else { | |
1311 d_temp |= d_digit; | |
1312 a_imeisv[d_i / 2] = d_temp; | |
1313 } | |
1314 } | |
1315 | |
1316 target_send(a_imeisv, C_IMEISV_BYTES); | |
1317 target_expect_char(PROTO_READY, TARGET_RECV_DELAY); | |
1318 | |
1319 // Send platform certificate address | |
1320 for (d_i = 0; d_i < C_PLATFORM_CERT_ADDR_DIGITS; d_i++) { | |
1321 sscanf(arg_platform_certificate_addr++, "%1x", &d_digit); | |
1322 if (!(d_i & 1)) | |
1323 d_temp = d_digit << 4; | |
1324 else { | |
1325 d_temp |= d_digit; | |
1326 a_platform_cert_addr[d_i / 2] = d_temp; | |
1327 } | |
1328 } | |
1329 | |
1330 target_send(a_platform_cert_addr, C_PLATFORM_CERT_ADDR_BYTES); | |
1331 target_expect_char(PROTO_READY, TARGET_RECV_DELAY); | |
1332 | |
1333 // Check if address range is erased | |
1334 if (target_wait(1, TARGET_RECV_DELAY) < 1) | |
1335 main_fatal(E_RECV_TIMEOUT); | |
1336 | |
1337 d_error = target_getchar(); | |
1338 if (d_error == PROTO_ERROR_VERIFY) { | |
1339 flowf(NORMAL, "\n The address range for platform certificate and IMEI-SV is not erased.\n"); | |
1340 main_fatal(E_FLASH_VERIFY); | |
1341 } | |
1342 | |
1343 if (d_error != PROTO_READY) | |
1344 error_proto(d_error, PROTO_READY); | |
1345 | |
1346 // Verify that the binding service call in target has succeeded | |
1347 if (target_wait(1, TARGET_RECV_DELAY) < 1) | |
1348 main_fatal(E_RECV_TIMEOUT); | |
1349 | |
1350 d_error = target_getchar(); | |
1351 if (d_error == PROTO_ERROR_ROM_SSERVICE) { | |
1352 flowf(NORMAL, "\n The Run-Time Loader (Binding) Service failed.\n"); | |
1353 main_fatal(E_ROM_SSERVICE); | |
1354 } | |
1355 | |
1356 if (d_error != PROTO_FLASH_START) | |
1357 error_proto(d_error, PROTO_FLASH_START); | |
1358 | |
1359 // Receive acknowledgement for programming the platform certificate | |
1360 if (target_wait(1, TARGET_RECV_DELAY) < 1) | |
1361 main_fatal(E_RECV_TIMEOUT); | |
1362 | |
1363 d_error = target_getchar(); | |
1364 if (d_error != PROTO_PROGRAM) { | |
1365 flowf(NORMAL, "\n Platform certificate was not stored correctly in flash.\n"); | |
1366 error_proto(d_error, PROTO_PROGRAM); | |
1367 } | |
1368 | |
1369 // Receive acknowledgement for programming the IMEI-SV | |
1370 if (target_wait(1, TARGET_RECV_DELAY) < 1) | |
1371 main_fatal(E_RECV_TIMEOUT); | |
1372 | |
1373 d_error = target_getchar(); | |
1374 if (d_error != PROTO_PROGRAM) { | |
1375 flowf(NORMAL, "\n IMEI-SV was not stored correctly in flash.\n"); | |
1376 error_proto(d_error, PROTO_PROGRAM); | |
1377 } | |
1378 | |
1379 flowf(NORMAL, "Platform certificate and IMEI-SV stored in flash.\n"); | |
1380 } | |
1381 | |
1382 // End Secure Calypso Plus | |
1383 | |
1384 /****************************************************************************** | |
1385 * Flash Detect | |
1386 ******************************************************************************/ | |
1387 | |
1388 void flash_detect_machine(void) | |
1389 { | |
1390 uint8 data[12]; | |
1391 uint16 m0, d0, m1, d1, d1ex1, d1ex2; | |
1392 | |
1393 flowf(NORMAL, "Flash Detect: "); | |
1394 target_trace_enable(0); | |
1395 | |
1396 if (arg_device_id0 != -1 || arg_device_id1 != -1) { | |
1397 // Device auto-detection is disabled | |
1398 m0 = m1 = arg_device_id0; | |
1399 d0 = d1 = arg_device_id1; | |
1400 flowf(VERBOSE, "(ID override) "); | |
1401 } | |
1402 else { | |
1403 target_putchar(PROTO_DETECT); | |
1404 if (target_wait(12, TARGET_RECV_DELAY) < 12) | |
1405 main_fatal(E_RECV_TIMEOUT); | |
1406 | |
1407 target_recv(data, 12); | |
1408 m0 = data[0] + (data[1] << 8); // Intel manufacturer id | |
1409 d0 = data[2] + (data[3] << 8); // Intel device id | |
1410 m1 = data[4] + (data[5] << 8); // AMD manufacturer id | |
1411 d1 = data[6] + (data[7] << 8); // AMD device di | |
1412 d1ex1 = data[8] + (data[9] << 8); // AMD extended device id | |
1413 d1ex2 = data[10] + (data[11] << 8); // AMD extended device id | |
1414 } | |
1415 | |
1416 // Lookup multi-id device | |
1417 if ((m1 == MANUFACT_AMD || m1 == MANUFACT_FUJITSU) && d1 == 0x227E) { | |
1418 flowf(NORMAL, "Multi-id device detected: (0x%04X, 0x%04X, 0x%04X)\n" | |
1419 , d1, d1ex1, d1ex2); | |
1420 d1 = (d1ex1 << 8) | (d1ex2 & 0xFF); | |
1421 flowf(DEBUG, "Multi-id converted to: 0x%04X\n", d1); | |
1422 | |
1423 if ((device = device_lookup_by_id(m1, d1)) == NULL) { | |
1424 flowf(NORMAL, "Id not found, lookup default multi-id conf.\n"); | |
1425 // Backward compatible/keep default multi-id configuration | |
1426 device = device_lookup_by_id(m1, 0x227E); | |
1427 } | |
1428 } | |
1429 | |
1430 // Lookup device with AMD and Intel ids | |
1431 else if ((device = device_lookup_by_id(m1, d1)) == NULL) | |
1432 device = device_lookup_by_id(m0, d0); | |
1433 | |
1434 if (device == NULL || arg_verbose >= DEBUG) { | |
1435 flowf(NORMAL, "(0x%02X, 0x%04X, 0x%02X, 0x%04X) ", m0, d0, m1, d1); | |
1436 if (device == NULL) | |
1437 main_fatal(E_FLASH_UNKNOWN); | |
1438 } | |
1439 | |
1440 if (arg_verbose >= NORMAL) { | |
1441 device_print(device, 's'); | |
1442 flowf(NORMAL, " ok\n"); | |
1443 } | |
1444 | |
1445 // Note that device_id is only 0x227E if the Multi-id configuration not | |
1446 // is found in device.txt (else device_id will be the 'converted' id) | |
1447 if (arg_device_id0 == -1 && arg_device_id1 == -1 && | |
1448 (device->manufacturer_id == MANUFACT_FUJITSU || | |
1449 device->manufacturer_id == MANUFACT_AMD ) | |
1450 && device->device_id == 0x227E) { | |
1451 flowf(NORMAL, "Warning: Extended device codes are supported when detecting flash devices,\n"); | |
1452 flowf(NORMAL, " but the detected multi-id configuration is not found in device.txt. \n"); | |
1453 flowf(NORMAL, " Update the device.txt manually if the default flash device is invalid.\n"); | |
1454 flowf(NORMAL, " Currently, %s %s is used as default.\n\n", | |
1455 manufacturer_name_lookup_by_id(device->manufacturer_id), device->name); | |
1456 } | |
1457 } | |
1458 | |
1459 | |
1460 /****************************************************************************** | |
1461 * Method Load | |
1462 ******************************************************************************/ | |
1463 | |
1464 void method_download_machine(void) | |
1465 { | |
1466 char sendbuf[1+2+4]; | |
1467 int error; | |
1468 | |
1469 target_program_size = file_read_method(target_program, | |
1470 TARGET_PROGRAM_SIZE_MAX, | |
1471 device); | |
1472 | |
1473 flowf(BLABBER, "Method Download: "); | |
1474 target_trace_enable(0); | |
1475 | |
1476 // Send 'Download' command header. Then wait for acknowledgement. | |
1477 buf_put1(&sendbuf[0], PROTO_DOWNLOAD); | |
1478 buf_put4(&sendbuf[1], target[target_type].method_load_addr); | |
1479 buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2); | |
1480 target_send(sendbuf, 1+4+2); | |
1481 flowf(BLABBER, "(0x%X", target[target_type].method_load_addr); | |
1482 if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) | |
1483 main_fatal(error); | |
1484 | |
1485 // Send data. Then wait for acknowledgement. | |
1486 target_trace_enable(1); | |
1487 target_send(target_program, target_program_size); | |
1488 flowf(BLABBER, ", %d) ", target_program_size); | |
1489 if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) | |
1490 main_fatal(error); | |
1491 | |
1492 flowf(BLABBER, "ok\n"); | |
1493 } | |
1494 | |
1495 | |
1496 /****************************************************************************** | |
1497 * Flash Checksum | |
1498 ******************************************************************************/ | |
1499 | |
1500 int time_checksum; | |
1501 | |
1502 #define CHECKSUMS 8 | |
1503 | |
1504 void flash_checksum_machine(void) | |
1505 { | |
1506 unsigned char sendbuf[1+1+4+4*CHECKSUMS], *buf; | |
1507 uint32 addr, cksum, mycksum; | |
1508 uint16 word; | |
1509 uint8 data[4]; | |
1510 int index = 0, chunks, n, i, j; | |
1511 int line = -1; | |
1512 struct { | |
1513 uint32 index; | |
1514 uint32 addr; | |
1515 uint32 mycksum; | |
1516 } block[CHECKSUMS]; | |
1517 | |
1518 chunks = image_map_count_used_chunks(); | |
1519 flowf(NORMAL, "Checksumming (%d * %dkB = %dkB): ", | |
1520 chunks, image_chunk_size / 1024, | |
1521 chunks * image_chunk_size / 1024); | |
1522 target_trace_enable(0); | |
1523 | |
1524 time_checksum = stopwatch_start(); | |
1525 while (chunks > 0) | |
1526 { | |
1527 n = (chunks > CHECKSUMS ? CHECKSUMS : chunks); | |
1528 | |
1529 buf = sendbuf; | |
1530 buf += buf_put1(buf, PROTO_CHECKSUM); | |
1531 buf += buf_put1(buf, (unsigned char) n); | |
1532 buf += buf_put4(buf, image_chunk_size); | |
1533 | |
1534 for (i = 0; i < n; i++) { | |
1535 // Find next used entry in image_map | |
1536 while (image_map[index] != 'x' && index < image_map_size) | |
1537 index++; | |
1538 | |
1539 if (index == image_map_size) | |
1540 break; | |
1541 | |
1542 addr = index * image_chunk_size; | |
1543 block[i].index = index; | |
1544 block[i].addr = addr; | |
1545 | |
1546 buf += buf_put4(buf, addr); | |
1547 | |
1548 index++; | |
1549 } | |
1550 target_send(sendbuf, buf - sendbuf); | |
1551 | |
1552 // Compute checksums while we wait for reply | |
1553 for (i = 0; i < n; i++) { | |
1554 index = block[i].index; | |
1555 addr = block[i].addr; | |
1556 for (j = 0, mycksum = 0; j < image_chunk_size; j += 2) { | |
1557 word = (image[addr + j + 1] << 8) | image[addr + j + 0]; | |
1558 mycksum += word * ((addr + j) & 0xFFFF); | |
1559 } | |
1560 block[i].mycksum = mycksum; | |
1561 } | |
1562 | |
1563 if (target_wait(4 * n, TARGET_RECV_LONG_DELAY) <= 0) | |
1564 main_fatal(E_RECV_TIMEOUT); | |
1565 | |
1566 for (i = 0; i < n; i++) { | |
1567 target_recv(data, 4); | |
1568 cksum = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); | |
1569 mycksum = block[i].mycksum; | |
1570 index = block[i].index; | |
1571 | |
1572 if (cksum == mycksum) | |
1573 image_map[index] = 'c'; | |
1574 | |
1575 if (arg_checksum_show) { | |
1576 // This is a far from perfect dump of checksums... We don't know | |
1577 // the exact block number of each checksum in a line. | |
1578 if (line != (int) index / 4) { | |
1579 flowf(NORMAL, "\n%4d:", index); | |
1580 line = index / 4; | |
1581 } | |
1582 if (cksum == mycksum) | |
1583 flowf(NORMAL, "%08X ", cksum); | |
1584 else | |
1585 flowf(NORMAL, "%08X/%08X ", cksum, mycksum); | |
1586 | |
1587 } | |
1588 else if (arg_verbose >= VERBOSE) { | |
1589 flowf(VERBOSE, "%c", (image_map[index] == 'c' ? 'c' : '.')); | |
1590 } | |
1591 } | |
1592 index++; | |
1593 chunks -= n; | |
1594 } | |
1595 time_checksum = (stopwatch_stop(time_checksum) + 50) / 100; | |
1596 flowf(BLABBER, " (%d.%ds)", time_checksum / 10, time_checksum % 10); | |
1597 flowf(NORMAL, " ok\n"); | |
1598 } | |
1599 | |
1600 | |
1601 /****************************************************************************** | |
1602 * Flash Program | |
1603 ******************************************************************************/ | |
1604 | |
1605 int time_program; | |
1606 int programs_recv, programs_send, erasures; | |
1607 int index, src_size; | |
1608 uint32 dst; | |
1609 char *src; | |
1610 | |
1611 void flash_erase_machine(void); | |
1612 int flash_operation_wait(int delay); | |
1613 int flash_program_next(void); | |
1614 | |
1615 void flash_program_machine(void) | |
1616 { | |
1617 uint8 cksum, sendbuf[1+4+4]; | |
1618 int i, te, tp, tt; | |
1619 int expected, chunks, total_size, sectors; | |
1620 int image_chunk_size_old = image_chunk_size; | |
1621 char ch; | |
1622 | |
1623 programs_recv = programs_send = erasures = 0; | |
1624 index = 0; | |
1625 | |
1626 // Prepare erase | |
1627 erase_list_size = sectors = sector_map_init(); | |
1628 i = image_map_count_used_chunks(); | |
1629 | |
1630 if (arg_skip_erase) | |
1631 erase_list_size = 0; | |
1632 | |
1633 time_compute(device, erase_list_size, | |
1634 i * image_chunk_size, i, &te, &tp, &tt); | |
1635 | |
1636 flowf(BLABBER, "Estimated time (uncompressed) "); | |
1637 if (te + tp > tt) | |
1638 flowf(BLABBER, "(erase + program = total): %ds + %ds = %ds\n", | |
1639 te/1000, tp/1000, te/1000 + tp/1000); | |
1640 else | |
1641 flowf(BLABBER, "transfer: %ds\n", tt/1000); | |
1642 | |
1643 chunks = image_map_count_used_chunks(); | |
1644 flowf(NORMAL, "Program: (%d sectors, %d*%dk=%dk) ", | |
1645 sectors, | |
1646 chunks, image_chunk_size / 1024, | |
1647 chunks * image_chunk_size / 1024); | |
1648 target_trace_enable(1); | |
1649 | |
1650 // Expected total number of acknowledgements | |
1651 expected = erase_list_size + chunks; | |
1652 | |
1653 if (arg_dry_run) { | |
1654 flowf(NORMAL, "(dry-run) "); | |
1655 if (arg_dry_run == 2) | |
1656 image_chunk_size = 0; | |
1657 } | |
1658 | |
1659 if (arg_skip_erase) | |
1660 flowf(NORMAL, "(skip erase) "); | |
1661 | |
1662 // Start erase | |
1663 flash_erase_machine(); | |
1664 | |
1665 if (arg_dry_run == 0 || arg_dry_run == 2) | |
1666 progress_begin(expected); | |
1667 | |
1668 // Start the flash state machine in the target | |
1669 target_putchar(PROTO_FLASH_START); | |
1670 target_putchar(arg_compress ? PROTO_COMPRESS : 0); | |
1671 ch = flash_operation_wait(TARGET_RECV_DELAY); | |
1672 if (ch != PROTO_READY) | |
1673 error_proto(ch, PROTO_READY); | |
1674 if (arg_compress) { | |
1675 compress_init(); | |
1676 total_size = 0; | |
1677 // Worst case "compressed" buffer is 9/8 of original data size. | |
1678 if ((src = malloc(9 * image_chunk_size / 8)) == NULL) | |
1679 main_fatal(E_MEMORY); | |
1680 } | |
1681 | |
1682 time_program = stopwatch_start(); | |
1683 | |
1684 if (flash_program_next() && *arg_erase_override == 0) { | |
1685 //Nothing to program | |
1686 target_putchar(PROTO_FLASH_END); | |
1687 if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0) | |
1688 main_fatal(ch); | |
1689 } | |
1690 else { | |
1691 while (programs_recv + erasures < expected) { | |
1692 total_size += src_size; | |
1693 | |
1694 if (arg_progress == 'x') | |
1695 flowf(NORMAL, "(0x%06X, %d) ", dst, src_size); | |
1696 | |
1697 if (src_size > 0 && | |
1698 (arg_dry_run == 0 || arg_dry_run == 2)) | |
1699 { | |
1700 buf_put1(&sendbuf[0], PROTO_PROGRAM); | |
1701 buf_put4(&sendbuf[1], src_size); | |
1702 buf_put4(&sendbuf[1+4], dst); | |
1703 target_send(sendbuf, 1+4+4); | |
1704 | |
1705 for (i = 0, cksum = 0; i < src_size; i++) | |
1706 cksum += src[i]; | |
1707 cksum = (0x100 - cksum) & 0xFF; | |
1708 | |
1709 // Wait for acknowledgement of command start | |
1710 //while ((ch = flash_operation_wait(4000)) != PROTO_READY) | |
1711 // ; | |
1712 | |
1713 // Make sure that the target FIFO not is full | |
1714 while (programs_send - programs_recv >= target_fifo_size) | |
1715 flash_operation_wait(4000); | |
1716 | |
1717 // Send data bytes and checksum. | |
1718 target_send(src, src_size); | |
1719 target_putchar(cksum); | |
1720 programs_send++; | |
1721 | |
1722 if (arg_verbose >= DEBUG) | |
1723 progress_update_simple('T'); | |
1724 } | |
1725 | |
1726 // We compress and send next block while sending | |
1727 // current block to target | |
1728 if (arg_dry_run == 0 || arg_dry_run == 2) { | |
1729 if (flash_program_next()) { | |
1730 // Wait for remaining acknowledgements | |
1731 flowf(DEBUG, "W%d", expected - (programs_recv + erasures)); | |
1732 while (programs_recv + erasures < expected) | |
1733 flash_operation_wait(4000); | |
1734 target_putchar(PROTO_FLASH_END); | |
1735 if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0) | |
1736 main_fatal(ch); | |
1737 break; | |
1738 } | |
1739 else { | |
1740 // Wait for acknowledgement of data transfer | |
1741 while ((ch = flash_operation_wait(4000)) != PROTO_READY) | |
1742 ; | |
1743 } | |
1744 } | |
1745 else { | |
1746 if (flash_program_next()) | |
1747 break; | |
1748 } | |
1749 } | |
1750 } | |
1751 | |
1752 if (arg_dry_run == 0 || arg_dry_run == 2) | |
1753 progress_end(programs_recv + erasures); | |
1754 flowf(NORMAL, "ok\n"); | |
1755 | |
1756 time_program = stopwatch_stop(time_program); | |
1757 flowf(VERBOSE, "Used time: "); | |
1758 if (arg_compress && chunks) { | |
1759 image_chunk_size = image_chunk_size_old; | |
1760 flowf(VERBOSE, "(compressed to %d%%) ", | |
1761 100 * total_size / (chunks * image_chunk_size)); | |
1762 } | |
1763 flowf(VERBOSE, "%.1fs ok\n", (double) time_program / 1000); | |
1764 } | |
1765 | |
1766 | |
1767 /****************************************************************************** | |
1768 * Flash Program sub functions | |
1769 ******************************************************************************/ | |
1770 | |
1771 void flash_erase_machine(void) | |
1772 { | |
1773 uint8 sendbuf[1+2+4*256]; // NOTEME: static limit! | |
1774 int i; | |
1775 char ch; | |
1776 | |
1777 if (arg_dry_run) | |
1778 erase_list_size = 0; | |
1779 | |
1780 if (erase_list_size > 0) { | |
1781 buf_put1(&sendbuf[0], PROTO_ERASE); | |
1782 buf_put2(&sendbuf[1], (uint16) erase_list_size); | |
1783 for (i = 0; i < erase_list_size; i++) | |
1784 buf_put4(&sendbuf[1+2+4*i], erase_list[i]); | |
1785 target_send(sendbuf, 1+2+4*erase_list_size); | |
1786 | |
1787 if ((ch = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) | |
1788 main_fatal(ch); | |
1789 } | |
1790 } | |
1791 | |
1792 // Setup address and size of next block to transfer. Also compress the | |
1793 // block. Return non-zero if this was the last block. Otherwise return zero. | |
1794 int flash_program_next(void) | |
1795 { | |
1796 int oldindex; | |
1797 | |
1798 // Find next used entry in image_map | |
1799 while (index < image_map_size && image_map[index] != 'x') | |
1800 index++; | |
1801 | |
1802 oldindex = index; | |
1803 | |
1804 if (index < image_map_size) { | |
1805 dst = index * image_chunk_size; | |
1806 if (arg_compress) { | |
1807 src_size = compress(src, &image[dst], image_chunk_size); | |
1808 } | |
1809 else { | |
1810 src = &image[dst]; | |
1811 src_size = image_chunk_size; | |
1812 } | |
1813 index++; | |
1814 } | |
1815 else { | |
1816 dst = 0xFFFFFFFF; | |
1817 src_size = 0; | |
1818 } | |
1819 | |
1820 return (oldindex >= image_map_size); | |
1821 } | |
1822 | |
1823 int flash_operation_wait(int delay) | |
1824 { | |
1825 int n; | |
1826 char ch; | |
1827 | |
1828 tr(TrMachines, "fow() "); | |
1829 | |
1830 if ((n = target_wait(1, delay)) < 1) | |
1831 main_fatal(E_RECV_TIMEOUT); | |
1832 | |
1833 // Minor optimization to avoid waiting for every char... | |
1834 while (n--) { | |
1835 ch = target_getchar(); | |
1836 | |
1837 if (ch == PROTO_READY) { | |
1838 if (arg_verbose >= DEBUG) | |
1839 progress_update_simple('R'); | |
1840 if (programs_send - programs_recv >= target_fifo_size) | |
1841 progress_update_simple('W'); // Wait target FIFO is full | |
1842 break; | |
1843 } | |
1844 | |
1845 switch (ch) { | |
1846 case PROTO_READY: | |
1847 break; // just return the char | |
1848 case PROTO_PROGRAM: | |
1849 programs_recv++; | |
1850 progress_update_simple('P'); | |
1851 progress_update(programs_recv + erasures); | |
1852 break; // just return the char | |
1853 case PROTO_ERASE: | |
1854 erasures++; | |
1855 progress_update_simple('E'); | |
1856 progress_update(programs_recv + erasures); | |
1857 if (arg_progress == 'x') | |
1858 flowf(NORMAL, "E "); | |
1859 break; // just return the char | |
1860 case PROTO_FLASH_END: | |
1861 progress_update_simple('Z'); | |
1862 break; | |
1863 case PROTO_ERROR_CKSUM: | |
1864 main_fatal(E_SEND_CHECKSUM); | |
1865 case PROTO_ERROR_MEMORY: | |
1866 main_fatal(E_MEMORY); | |
1867 case PROTO_ERROR_VERIFY: | |
1868 main_fatal(E_FLASH_VERIFY); | |
1869 case PROTO_ERROR_FLASH_TIMEOUT: | |
1870 main_fatal(E_FLASH_TIMEOUT); | |
1871 case PROTO_ERROR_FLASH_COMMAND: | |
1872 main_fatal(E_FLASH_COMMAND); | |
1873 case PROTO_ERROR_FLASH_VPP: | |
1874 main_fatal(E_FLASH_VPPRANGE); | |
1875 case PROTO_ERROR_FLASH_LOCKED: | |
1876 main_fatal(E_FLASH_LOCKED); | |
1877 case PROTO_ERROR_FLASH_UNKNOWN: | |
1878 main_fatal(E_FLASH_ERROR); | |
1879 case PROTO_ERROR_INVALID: | |
1880 main_fatal(E_INVALID); | |
1881 case PROTO_ERROR_FIFO_OVERFLOW: | |
1882 main_fatal(E_FIFO_OVERFLOW); | |
1883 case PROTO_ERROR: | |
1884 default: | |
1885 flowf(NORMAL, "flash_operation_wait() got unexpected char '%c' 0x%02X (%d chars waiting)\n", (' ' <= ch && ch < 127 ? ch : '.'), ch, n); | |
1886 // main_fatal(E_PROTO_ERROR); | |
1887 } | |
1888 } | |
1889 | |
1890 return ch; | |
1891 } | |
1892 | |
1893 void target_timers_show(void) | |
1894 { | |
1895 int data[8], i; | |
1896 struct { | |
1897 double erase; | |
1898 double program; | |
1899 double recvonly; | |
1900 double recv; | |
1901 double comm; | |
1902 double setup; | |
1903 double overhead; | |
1904 double dezip; | |
1905 double erase_sector; | |
1906 double program_word; | |
1907 } timer; | |
1908 double tmp, total, resolution = (double) (16 * 32 * 1000 / 13e6); | |
1909 | |
1910 // Use only 14 MHz for D-/E-Sample specific rates (not for e.g. 812.5K). | |
1911 if ((arg_uart_baudrate == 230400) || (arg_uart_baudrate == 460800) || (arg_uart_baudrate == 921600)) | |
1912 resolution = resolution * 13 / 14.746; | |
1913 | |
1914 flowf(NORMAL, | |
1915 "Target Timers:\n" | |
1916 " (erase + program + recvonly + recv + comm + setup + overhead + dezip)\n"); | |
1917 | |
1918 if (arg_dry_run) | |
1919 for (i = 0; i < 8; i++) data[i] = 0; | |
1920 else { | |
1921 target_putchar(PROTO_TIMERS); | |
1922 if (target_wait(sizeof(data), TARGET_RECV_DELAY) <= 0) | |
1923 main_fatal(E_RECV_TIMEOUT); | |
1924 target_recv(&data, sizeof(data)); | |
1925 } | |
1926 | |
1927 // Convert all timers to milliseconds | |
1928 timer.erase = resolution * data[0]; | |
1929 timer.program = resolution * data[1]; | |
1930 timer.recvonly = resolution * data[2]; | |
1931 timer.recv = resolution * data[3]; | |
1932 timer.comm = resolution * data[4]; | |
1933 timer.setup = resolution * data[5]; | |
1934 timer.overhead = resolution * data[6]; | |
1935 timer.dezip = resolution * data[7]; | |
1936 | |
1937 // Because we do erase-while-transfer in the target the reported erase | |
1938 // time has some inherent tolerance, especially at low baudrates. It | |
1939 // might make sense to adjust the sector erase time by half the chunk | |
1940 // transfer time, although this is just another approximation!? | |
1941 | |
1942 // total = timer.erase + timer.program + timer.recvonly + timer.recv + timer.comm + timer.setup; | |
1943 flowf(NORMAL, "%8.0f + %7.0f + %8.0f + %6.0f + %5.0f + %5.0f + %8.0f + %5.0f\n", | |
1944 timer.erase, timer.program, timer.recvonly, timer.recv, | |
1945 timer.comm, timer.setup, timer.overhead, timer.dezip); | |
1946 | |
1947 flowf(DEBUG, "resolution = %f, %d, %d, %d, %d, %d, %d, %d, %d\n", | |
1948 resolution, data[0], data[1], data[2], data[3], data[4], | |
1949 data[5], data[6], data[7]); | |
1950 | |
1951 if (arg_timers_extended_show) { | |
1952 int chunks, size_total, not_zero = 1; | |
1953 flowf(NORMAL, "Target Timers Extended:\n"); | |
1954 | |
1955 if (erase_list_size == 0 || arg_dry_run) | |
1956 flowf(NORMAL, " Erase time = 0.0ms/sector\n"); | |
1957 else { | |
1958 timer.erase_sector = timer.erase / erase_list_size / 1000; | |
1959 flowf(NORMAL, " Erase time = %.1fs / %d sectors = %.0fms/sector\n", | |
1960 timer.erase / 1000, erase_list_size, timer.erase_sector * 1000); | |
1961 } | |
1962 | |
1963 chunks = image_map_count_used_chunks(); | |
1964 size_total = chunks * image_chunk_size; | |
1965 if (size_total == 0 || arg_dry_run) { | |
1966 size_total = 1; | |
1967 not_zero = 0; | |
1968 flowf(NORMAL, " Program time = 0.0us/word = 0ms/MB\n"); | |
1969 } | |
1970 else { | |
1971 timer.program_word = timer.program / 1000 / (size_total / 2); | |
1972 flowf(NORMAL, " Program time = %.1fs / %dkwords = %.2fus/word = %.0fms/MB\n", | |
1973 timer.program / 1000, size_total / 1024 / 2, | |
1974 timer.program_word * 1000000, | |
1975 timer.program_word * 1000 * 512 * 1024); | |
1976 } | |
1977 | |
1978 flowf(NORMAL, " Receive-only time = %.1fs = %.0fms/MB\n", | |
1979 timer.recvonly / 1000, | |
1980 not_zero * timer.recvonly * 1024 * 1024 / size_total); | |
1981 | |
1982 flowf(NORMAL, " Overhead time = %.1fs = %.0fms/MB\n", | |
1983 timer.overhead / 1000, | |
1984 not_zero * timer.overhead * 1024 * 1024 / size_total); | |
1985 | |
1986 flowf(NORMAL, " Setup time = %.1fs = %.0fms/MB\n", | |
1987 timer.setup / 1000, | |
1988 not_zero * timer.setup * 1024 * 1024 / size_total); | |
1989 | |
1990 total = timer.erase + timer.program + timer.recvonly + timer.overhead + | |
1991 timer.setup; | |
1992 flowf(NORMAL, | |
1993 "Total time: (erase + prog + recvonly + overhead + setup) = %.1fs\n", | |
1994 total / 1000); | |
1995 | |
1996 flowf(NORMAL, " Receive time = %.1fs = %.0fms/MB\n", | |
1997 timer.recv / 1000, timer.recv * 1024 * 1024 / size_total); | |
1998 | |
1999 flowf(NORMAL, " Communication time = %.1fs = %.0fms/MB\n", | |
2000 timer.comm / 1000, timer.comm * 1024 * 1024 / size_total); | |
2001 | |
2002 flowf(NORMAL, " Dezip time = %.1fs = %.0fms/MB\n", | |
2003 timer.dezip / 1000, timer.dezip * 1024 * 1024 / size_total); | |
2004 | |
2005 // Now compute the overall performance. Note that the theoretical | |
2006 // limit compuation is somewhat flawed in that it assumes 64kB | |
2007 // sector sizes. | |
2008 | |
2009 tmp = (double) not_zero * total / 1000 * 1024 * 1024 / size_total; | |
2010 flowf(NORMAL, " Performance = %.0fs/MB\n", tmp); | |
2011 #if 0 | |
2012 flowf(BLABBER, " (%.1f * min possible, %.1f * theoretical limit)", | |
2013 time_program / (timer.program + timer.erase), | |
2014 tmp / (16 * timer.erase_sector + 512 * 1024 * timer.program_word)); | |
2015 flowf(NORMAL, "\n"); | |
2016 #endif | |
2017 } | |
2018 } | |
2019 | |
2020 | |
2021 /****************************************************************************** | |
2022 * Flash Read | |
2023 ******************************************************************************/ | |
2024 | |
2025 int time_read; | |
2026 | |
2027 void flash_read_machine(void) | |
2028 { | |
2029 int i; | |
2030 unsigned char sendbuf[1+4+4]; | |
2031 int size, read_size, done_size = 0; | |
2032 int read_size_max = image_chunk_size; | |
2033 uint32 addr, index = 0; | |
2034 uint8 cksum, mycksum; | |
2035 | |
2036 flowf(NORMAL, "Reading Flash: (%dkB) ", read_total_size / 1024); | |
2037 target_trace_enable(0); | |
2038 | |
2039 //read_size_max = 256; | |
2040 time_read = stopwatch_start(); | |
2041 progress_begin(read_total_size / read_size_max); | |
2042 | |
2043 while (read_list[index].size > 0) | |
2044 { | |
2045 // Find next range to read | |
2046 size = read_list[index].size; | |
2047 addr = read_list[index].addr; | |
2048 index++; | |
2049 | |
2050 while (size > 0) | |
2051 { | |
2052 read_size = (size > read_size_max ? read_size_max : size); | |
2053 | |
2054 // Read address interval is [MIN..MAX[ | |
2055 // If odd MAX address was specified round up to next even | |
2056 if ((read_size % 2 == 1) && (read_size < read_size_max)) read_size++; | |
2057 | |
2058 if (arg_progress == 'x') | |
2059 flowf(DEBUG, "(0x%06X, %d) ", addr, read_size); | |
2060 | |
2061 if (!arg_dry_run) | |
2062 { | |
2063 buf_put1(&sendbuf[0], PROTO_READ); | |
2064 buf_put4(&sendbuf[1] , read_size); | |
2065 buf_put4(&sendbuf[1+4], addr); | |
2066 target_send(sendbuf, 1+4+4); | |
2067 | |
2068 if (target_wait(read_size, TARGET_RECV_LONG_DELAY) <= 0) | |
2069 main_fatal(E_RECV_TIMEOUT); | |
2070 // Note that we wrap/mirror memory each 'image_size' bytes | |
2071 target_recv(&image[addr & (image_size - 1)], read_size); | |
2072 for (i = 0, mycksum = 0; i < read_size; i++) | |
2073 mycksum ^= image[(addr + i) & (image_size - 1)]; | |
2074 | |
2075 if (target_wait(1, TARGET_RECV_DELAY) <= 0) | |
2076 main_fatal(E_RECV_TIMEOUT); | |
2077 cksum = target_getchar(); | |
2078 | |
2079 if (cksum != mycksum) | |
2080 main_fatal(E_RECV_CHECKSUM); | |
2081 } | |
2082 done_size += read_size; | |
2083 size -= read_size; | |
2084 addr += read_size; | |
2085 | |
2086 progress_update(done_size / read_size_max); | |
2087 progress_update_simple('0' + read_size / 1024); | |
2088 } | |
2089 } | |
2090 progress_end(done_size / read_size_max); | |
2091 flowf(NORMAL, " ok\n"); | |
2092 | |
2093 time_read = stopwatch_stop(time_read); | |
2094 flowf(VERBOSE, "Used time: %ds ok\n", time_read); | |
2095 } | |
2096 | |
2097 | |
2098 /****************************************************************************** | |
2099 * Flash Reset | |
2100 ******************************************************************************/ | |
2101 | |
2102 void target_reset_machine(void) | |
2103 { | |
2104 int error; | |
2105 | |
2106 flowf(VERBOSE, "Resetting target: "); | |
2107 | |
2108 if (arg_dry_run) { | |
2109 flowf(VERBOSE, "(dry-run) "); | |
2110 } | |
2111 else { | |
2112 target_putchar(PROTO_RESET); | |
2113 target_expect_char(PROTO_READY, TARGET_RECV_DELAY); | |
2114 } | |
2115 flowf(VERBOSE, "ok\n"); | |
2116 } | |
2117 | |
2118 | |
2119 /****************************************************************************** | |
2120 * Show Functions (dump internal data structures) | |
2121 ******************************************************************************/ | |
2122 | |
2123 void image_map_show(void) | |
2124 { | |
2125 uint32 addr; | |
2126 int i; | |
2127 | |
2128 flowf(ALWAYS, "image map of %d * %dkB chunks (x = used, s = skip, c = checksum ok):", | |
2129 image_size_in_chunks, image_chunk_size / 1024); | |
2130 | |
2131 // For each chunk of the image usage map... | |
2132 for (i = 0, addr = 0; i < image_size_in_chunks; i++) | |
2133 { | |
2134 if ((i % 64) == 0) { | |
2135 flowf(ALWAYS, "\n%4dkB: ", (int) addr >> 10); | |
2136 } | |
2137 putchar(image_map[i] != 0 ? image_map[i] : '.'); | |
2138 addr += image_chunk_size; | |
2139 } | |
2140 putchar('\n'); | |
2141 } | |
2142 | |
2143 void sector_map_show(void) | |
2144 { | |
2145 struct sector_s *sectors = device->memmap->sectors; | |
2146 int i; | |
2147 | |
2148 char n; | |
2149 uint32 addr = 0; | |
2150 | |
2151 flowf(ALWAYS, "sector map (x = used, s = skip, X = force erase):"); | |
2152 | |
2153 // For each sector of the device definition... | |
2154 for (i = 0; i < device->memmap->size; i++) | |
2155 { | |
2156 if ((addr & 0xFFFFF) == 0) { | |
2157 flowf(ALWAYS, "\n%2dMB: ", (int) addr >> 20); | |
2158 } | |
2159 n = (sector_map[i] ? sector_map[i] : '.'); | |
2160 putchar(n); | |
2161 | |
2162 addr += sectors[i].size; | |
2163 } | |
2164 putchar('\n'); | |
2165 } | |
2166 | |
2167 | |
2168 /****************************************************************************** | |
2169 * Utility Functions | |
2170 ******************************************************************************/ | |
2171 | |
2172 int image_is_within(int start, int end) | |
2173 { | |
2174 return !(start < 0 || image_size <= start || | |
2175 end < 0 || image_size < end || | |
2176 end < start); | |
2177 } | |
2178 | |
2179 // Set the image usage map in the range [start..end[ as used | |
2180 int image_map_set(int start, int end) | |
2181 { | |
2182 if (!image_is_within(start, end)) | |
2183 return -1; | |
2184 | |
2185 do { | |
2186 image_map[start / image_chunk_size] = 'x'; | |
2187 start += image_chunk_size; | |
2188 } while (start < end); | |
2189 | |
2190 return 0; | |
2191 } | |
2192 | |
2193 int target_type_set(uint16 code) | |
2194 { | |
2195 // If there is an override from the command-line, use that | |
2196 if (arg_target_type != 0) | |
2197 code = arg_target_type; | |
2198 | |
2199 switch (code) | |
2200 { | |
2201 case 'h': // Hercules | |
2202 case 'u': // Ulysses | |
2203 case '3': // Chipset 3 | |
2204 case CHIP_ID_ULYSSES_0: | |
2205 case CHIP_ID_ULYSSES_A: | |
2206 case CHIP_ID_HERCULES_A: | |
2207 case CHIP_ID_HERCULES_B: | |
2208 target_type = 3; | |
2209 break; | |
2210 | |
2211 case 'c': // Calypso | |
2212 case '4': // Chipset 4 | |
2213 // case 's': // Samson | |
2214 case CHIP_ID_CALYPSO_A: | |
2215 case CHIP_ID_CALYPSO_B: | |
2216 case CHIP_ID_CALYPSO_C: | |
2217 target_type = 4; | |
2218 break; | |
2219 | |
2220 case 'l': // Calypso Lite | |
2221 case CHIP_ID_CALYPSO_L: | |
2222 target_type = 5; | |
2223 break; | |
2224 | |
2225 case 'p': // Calypso Plus | |
2226 case CHIP_ID_CALYPSO_PLUS: | |
2227 case CHIP_ID_CALYPSO_PLUS_A: | |
2228 target_type = 6; | |
2229 break; | |
2230 | |
2231 default: | |
2232 target_type = 0; | |
2233 } | |
2234 | |
2235 return target_type; | |
2236 } | |
2237 | |
2238 int image_map_count_used_chunks(void) | |
2239 { | |
2240 int used, i; | |
2241 | |
2242 // For each image chunk | |
2243 for (i = 0, used = 0; i < image_size_in_chunks; i++) { | |
2244 if (image_map[i] == 'x') | |
2245 used++; | |
2246 } | |
2247 return used; | |
2248 } | |
2249 | |
2250 // When the sector_map have been changed, we have to update the image_map | |
2251 // such that we don't attempt to program within sectors that are not going | |
2252 // to be programmed anyway (due to the erase override). We also have to | |
2253 // program chunks contained in sectors that *are* going to be erased, even | |
2254 // though the chunks have been check-summed ok. | |
2255 int image_map_update(void) | |
2256 { | |
2257 struct sector_s *sectors = device->memmap->sectors; | |
2258 int changed, chunks, i, j; | |
2259 int map_index; | |
2260 | |
2261 map_index = 0; | |
2262 changed = 0; | |
2263 | |
2264 // For each sector of the device definition... | |
2265 for (i = 0; i < device->memmap->size; i++) { | |
2266 chunks = sectors[i].size / image_chunk_size; | |
2267 // For each image--map-chunk contained in current sector... | |
2268 for (j = 0; j < chunks; j++) { | |
2269 if (!(sector_map[i] == 'x' || sector_map[i] == 'X') && | |
2270 image_map[map_index + j] == 'x') { | |
2271 image_map[map_index + j] = 's'; // skip | |
2272 changed++; | |
2273 } | |
2274 else if ((sector_map[i] == 'x' || sector_map[i] == 'X') | |
2275 && image_map[map_index + j] == 'c') { | |
2276 image_map[map_index + j] = 'x'; // include! | |
2277 changed++; | |
2278 } | |
2279 } | |
2280 map_index += chunks; | |
2281 } | |
2282 return changed; | |
2283 } | |
2284 | |
2285 int sector_map_init(void) | |
2286 { | |
2287 struct sector_s *sectors = device->memmap->sectors; | |
2288 int map_index; | |
2289 int used_list_index; | |
2290 int used, chunks, i, j; | |
2291 | |
2292 sector_map_size = SECTOR_MAP_SIZE_MAX; | |
2293 | |
2294 memset(sector_map, 0, sector_map_size); | |
2295 | |
2296 // Generate the sector_map from the image_map | |
2297 map_index = 0; | |
2298 | |
2299 // For each sector of the device definition... | |
2300 for (i = 0; i < device->memmap->size; i++) { | |
2301 | |
2302 chunks = sectors[i].size / image_chunk_size; | |
2303 | |
2304 // For each image-usage-map-chunk contained in current sector... | |
2305 for (j = 0, used = 0; j < chunks; j++) | |
2306 if (image_map[map_index + j] == 'x') | |
2307 used++; | |
2308 | |
2309 sector_map[i] = (used ? 'x' : 0); | |
2310 map_index += chunks; | |
2311 } | |
2312 | |
2313 parse_arg_erase_override(arg_erase_override); | |
2314 | |
2315 // Generate the erase_list | |
2316 // For each sector of the device definition... | |
2317 used_list_index = 0; | |
2318 for (i = 0; i < device->memmap->size; i++) { | |
2319 if (sector_map[i] == 'x' || sector_map[i] == 'X') | |
2320 erase_list[used_list_index++] = sectors[i].addr; | |
2321 } | |
2322 | |
2323 if (arg_sector_map_show) | |
2324 sector_map_show(); | |
2325 | |
2326 if (arg_sector_list_show) { | |
2327 flowf(ALWAYS, "sector used list: "); | |
2328 for (i = 0; i < used_list_index; i++) | |
2329 flowf(ALWAYS, "0x%06X ", erase_list[i]); | |
2330 putchar('\n'); | |
2331 } | |
2332 | |
2333 return used_list_index; | |
2334 } | |
2335 | |
2336 int parse_range(char *p, char **p_end, int *n1, int *n2) | |
2337 { | |
2338 char *my_end; | |
2339 int read_offset_calp = (*arg_read != 0 && target[target_type].type == 'P'); | |
2340 | |
2341 *n2 = 0; | |
2342 | |
2343 *n1 = strtol(p, &my_end, 0); | |
2344 if (p == my_end) | |
2345 return 0; // error: no chars converted | |
2346 | |
2347 if (*my_end == 'k' || *my_end == 'K') { | |
2348 *n1 <<= 10; | |
2349 if (read_offset_calp) *n1 += CALP_OFFSET; | |
2350 my_end++; | |
2351 } | |
2352 else if (*my_end == 'M') { | |
2353 *n1 <<= 20; | |
2354 if (read_offset_calp) *n1 += CALP_OFFSET; | |
2355 my_end++; | |
2356 } | |
2357 | |
2358 *p_end = my_end; | |
2359 if (my_end[0] != '.' || my_end[1] != '.') | |
2360 return 1; | |
2361 p = my_end + 2; | |
2362 | |
2363 *n2 = strtol(p, &my_end, 0); | |
2364 if (p == my_end) | |
2365 return 0; // error: no chars converted | |
2366 | |
2367 if (*my_end == 'k' || *my_end == 'K') { | |
2368 *n2 <<= 10; | |
2369 if (read_offset_calp) *n2 += CALP_OFFSET; | |
2370 my_end++; | |
2371 } | |
2372 else if (*my_end == 'M') { | |
2373 *n2 <<= 20; | |
2374 if (read_offset_calp) *n2 += CALP_OFFSET; | |
2375 my_end++; | |
2376 } | |
2377 | |
2378 *p_end = my_end; | |
2379 return 2; | |
2380 } | |
2381 | |
2382 // Parse and decode the erase override command line option string. The | |
2383 // sector_map is updated accordingly. | |
2384 void parse_arg_erase_override(char *p) | |
2385 { | |
2386 struct sector_s *sectors = device->memmap->sectors; | |
2387 int sector_bottom, sector_top; | |
2388 int changed, i; | |
2389 | |
2390 tr(TrBegin| TrArgParser, "erase_override:\n"); | |
2391 while (*p) | |
2392 { | |
2393 char *p_end; | |
2394 int num, sign, n1 = 0, n2 = 0; | |
2395 | |
2396 if (*p != '-' && *p != '+') | |
2397 main_error(E_ERASE_SPEC); | |
2398 | |
2399 sign = (*p == '-' ? -1 : +1); | |
2400 p++; | |
2401 | |
2402 if (*p == '*') { | |
2403 sign = sign * 2; | |
2404 p++; | |
2405 } | |
2406 else { | |
2407 num = parse_range(p, &p_end, &n1, &n2); | |
2408 if (num == 0) | |
2409 main_error(E_ERASE_SPEC); | |
2410 p = p_end; | |
2411 } | |
2412 | |
2413 switch (sign) { | |
2414 case -1: | |
2415 case +1: | |
2416 if (num == 1) { | |
2417 // Support for absolute addresses on Calypso Plus | |
2418 if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET; | |
2419 | |
2420 if (n1 > sector_map_size) { | |
2421 // For all sectors... | |
2422 for (i = 0; i < device->memmap->size; i++) { | |
2423 sector_bottom = sectors[i].addr; | |
2424 sector_top = sector_bottom + sectors[i].size - 1; | |
2425 | |
2426 if (n1 >= sector_bottom && n1 < sector_top) { | |
2427 sector_map[i] = (sign > 0 ? 'X' : 's'); | |
2428 break; | |
2429 } | |
2430 } | |
2431 } | |
2432 else | |
2433 sector_map[n1] = (sign > 0 ? 'X' : 's'); | |
2434 tr(TrArgParser, "%c%d\n", sign > 0 ? '+' : '-', n1); | |
2435 } | |
2436 else { | |
2437 // Support for absolute addresses on Calypso Plus | |
2438 if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) { | |
2439 n1 -= CALP_OFFSET; | |
2440 n2 -= CALP_OFFSET; | |
2441 } | |
2442 | |
2443 if (n1 > sector_map_size || n2 > sector_map_size) { | |
2444 // n1 and n2 must respresent an address range | |
2445 if (n1 >= n2) | |
2446 main_error(E_ERASE_SPEC); | |
2447 | |
2448 // For all sectors... | |
2449 for (i = 0; i < device->memmap->size; i++) | |
2450 { | |
2451 sector_bottom = sectors[i].addr; | |
2452 sector_top = sector_bottom + sectors[i].size - 1; | |
2453 | |
2454 // If either sector bottom or top is contained in | |
2455 // [n1..n2[ | |
2456 if ((n1 <= sector_bottom && sector_bottom < n2) || | |
2457 (n1 <= sector_top && sector_top < n2)) { | |
2458 sector_map[i] = (sign > 0 ? 'X' : 's'); | |
2459 } | |
2460 } | |
2461 } | |
2462 else { | |
2463 // n1 and n2 must respresent a sector range | |
2464 for (i = n1; i < n2; i++) | |
2465 sector_map[i] = (sign > 0 ? 'X' : 's'); | |
2466 } | |
2467 tr(TrArgParser, | |
2468 "%c%d..%d\n", sign > 0 ? '+' : '-', n1, n2); | |
2469 } | |
2470 break; | |
2471 case -2: | |
2472 case +2: | |
2473 // Fill whole sector_map... | |
2474 for (i = 0; i < device->memmap->size; i++) | |
2475 sector_map[i] = (sign > 0 ? 'X' : 's'); | |
2476 tr(TrArgParser, "%c*\n", sign > 0 ? '+' : '-'); | |
2477 break; | |
2478 } | |
2479 // skip optional comma | |
2480 if (*p == ',') | |
2481 p++; | |
2482 } | |
2483 tr(TrEnd| TrArgParser, ""); | |
2484 | |
2485 changed = image_map_update(); | |
2486 | |
2487 // If image map was changed, we trace it again. | |
2488 if (changed && arg_image_map_show) | |
2489 image_map_show(); | |
2490 } | |
2491 | |
2492 void parse_arg_read(char *p) | |
2493 { | |
2494 read_total_size = 0; | |
2495 read_list_size = 0; | |
2496 | |
2497 tr(TrArgParser, "parse_arg_read() {\n"); | |
2498 while (*p) | |
2499 { | |
2500 char *p_end; | |
2501 int num, n1, n2; | |
2502 | |
2503 if (*p == '*') { | |
2504 n1 = 0; | |
2505 n2 = 0x1000000; // sufficiently large (16MB) | |
2506 p++; | |
2507 } | |
2508 else { | |
2509 num = parse_range(p, &p_end, &n1, &n2); | |
2510 tr(TrArgParser, "parse_range('%s', ...)\n" | |
2511 " { #%d, p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n", | |
2512 p, read_list_size, p_end, n1, n2, num); | |
2513 if (num != 2 || n1 > n2) | |
2514 main_error(E_ADDR_RANGE); | |
2515 p = p_end; | |
2516 } | |
2517 read_list[read_list_size].addr = n1; | |
2518 read_list[read_list_size].size = n2 - n1; | |
2519 read_total_size += n2 - n1; | |
2520 read_list_size++; | |
2521 if (read_list_size >= READ_LIST_SIZE_MAX) | |
2522 main_error(E_ARG_TOOMANY); | |
2523 | |
2524 if (*p == 0) | |
2525 break; | |
2526 | |
2527 if (*p == ',') | |
2528 p++; | |
2529 else | |
2530 main_error(E_READ_SPEC); | |
2531 } | |
2532 // Terminate the read_list with zeroes. | |
2533 read_list[read_list_size].addr = 0; | |
2534 read_list[read_list_size].size = 0; | |
2535 | |
2536 tr(TrArgParser, "}\n"); | |
2537 } | |
2538 | |
2539 void parse_arg_write(char *p) | |
2540 { | |
2541 tr(TrArgParser, "parse_arg_write() {\n"); | |
2542 | |
2543 while (*p) | |
2544 { | |
2545 char bytes[1024]; | |
2546 char *p_end; | |
2547 int num, n1, n2; | |
2548 int index, value, size, i; | |
2549 | |
2550 num = parse_range(p, &p_end, &n1, &n2); | |
2551 tr(TrArgParser, "parse_range('%s', ...)\n" | |
2552 " { p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n", | |
2553 p, p_end, n1, n2, num); | |
2554 | |
2555 if (num < 1 || num > 2) | |
2556 main_error(E_ADDR_RANGE); | |
2557 | |
2558 p = p_end; | |
2559 | |
2560 if (*p++ != '=') | |
2561 main_error(E_WRITE_SPEC); | |
2562 | |
2563 tr(TrArgParser, " { "); | |
2564 if (*p == 0) | |
2565 main_error(E_WRITE_SPEC); | |
2566 | |
2567 index = 0; | |
2568 while (*p) { | |
2569 if (*p == '\"') { | |
2570 // Collect text string | |
2571 p++; | |
2572 tr(TrCont|TrArgParser, "'"); | |
2573 while (*p) { | |
2574 if (*p == '\"') | |
2575 break; | |
2576 if (p[0] == '\\' && p[1] == '\"') | |
2577 p++; // skip leading backslash | |
2578 if (p[0] == '\\' && p[1] == '\\') | |
2579 p++; // skip leading backslash | |
2580 tr(TrCont|TrArgParser, "%c", *p); | |
2581 bytes[index] = *p++; | |
2582 if (index++ >= sizeof(bytes)) | |
2583 main_error(E_WRITE_SPEC); | |
2584 } | |
2585 if (*p++ != '\"') | |
2586 main_error(E_WRITE_SPEC); | |
2587 tr(TrCont|TrArgParser, "' "); | |
2588 } | |
2589 else { | |
2590 // Collect byte string | |
2591 value = strtol(p, &p_end, 0); | |
2592 if (p == p_end) | |
2593 main_error(E_WRITE_SPEC); | |
2594 if (value < 0 || 255 < value) | |
2595 main_error(E_WRITE_SPEC); | |
2596 bytes[index] = value; | |
2597 if (index++ >= sizeof(bytes)) | |
2598 main_error(E_WRITE_SPEC); | |
2599 p = p_end; | |
2600 | |
2601 tr(TrCont|TrArgParser, "0x%x ", value); | |
2602 } | |
2603 if (*p == ':' || *p == 0) | |
2604 break; | |
2605 if (*p == ',') | |
2606 p++; | |
2607 } | |
2608 size = index; | |
2609 tr(TrArgParser, "} %d\n", size); | |
2610 | |
2611 if (num == 1) { | |
2612 // Support for absolute addresses on Calypso Plus | |
2613 if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET; | |
2614 | |
2615 n2 = n1 + size; | |
2616 } | |
2617 else if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) { | |
2618 n1 -= CALP_OFFSET; | |
2619 n2 -= CALP_OFFSET; | |
2620 } | |
2621 | |
2622 if (image_map_set(n1, n2) < 0) | |
2623 main_error(E_ADDR_RANGE); | |
2624 | |
2625 index = 0; | |
2626 for (i = n1; i < n2; i++) { | |
2627 image[i] = bytes[index++]; | |
2628 if (index >= size) | |
2629 index = 0; | |
2630 } | |
2631 if (*p == ':') | |
2632 p++; | |
2633 } | |
2634 tr(TrArgParser, "}\n"); | |
2635 } |