FreeCalypso > hg > freecalypso-reveng
view fluid-mnf/machine.c @ 342:6ff231195905
fluid-mnf/serial.[ch]: beginning of Linux port
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 13 Mar 2020 05:39:37 +0000 |
parents | 435e041897f2 |
children | 37b5f94de802 |
line wrap: on
line source
/****************************************************************************** * FLUID (Flash Loader Utility Independent of Device) * * Copyright Texas Instruments, 2001. * Mads Meisner-Jensen, mmj@ti.com. * Original state-machine logic by Delta Technologies, Copyright, 2001. * * Core functionality. State machines and support functions. * * $Id: machine.c 1.35.1.37 Mon, 28 Apr 2003 08:49:16 +0200 tsj $ * ******************************************************************************/ #include "fluid.h" #include "flash.h" #include "target.h" #include "fileio.h" #include "protocol.h" #include "misc.h" #include "lz.h" #include "trace.h" // Secure Calypso Plus #include "calplus/ram_load.h" #include "calplus/secure_types.h" #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <string.h> /****************************************************************************** * Constants and typedefs ******************************************************************************/ // Due to memory wrap/mirror used in flash_read_machine(), IMAGE_SIZE_MAX // *must* be a power of two. #define IMAGE_SIZE_MAX (8 * 1024 * 1024) #define IMAGE_CHUNK_SIZE 8192 #define ERASE_LIST_SIZE_MAX 256 #define SECTOR_MAP_SIZE_MAX 256 #define TARGET_PROGRAM_SIZE_MAX (8 * 1024) #define READ_LIST_SIZE_MAX 40 #define RETRIES_MAX 30 // Default target receive delay in milli-seconds. #define TARGET_RECV_DELAY 250 #define TARGET_RECV_LONG_DELAY 1000 // Default target reset delay in milli-seconds. #define TARGET_RESET_DELAY 200 // CS_MODE 0: Flash at 0x04000000 @ CS5 on E-Sample #define CALP_OFFSET 0x04000000 /****************************************************************************** * Globals ******************************************************************************/ // Secure Calypso Plus T_RAM_LOADER d_ram_loader; T_FRAME d_frame; UWORD16 d_certificate_length = 0; char a_certified_cmd_file_name[] = "cmdp_cert.m0"; struct target_s { uint32 cmd_load_addr; uint32 method_load_addr; const char type; const char *name; const char *prefix; }; // Note that the ROM bootloader of Calypso rev. A devices are unable to // write the bottom 128kB of internal RAM. Therefore the address have been // changed from 0x804000 to 0x0820000 const struct target_s target[] = { { 0x0000000, 0x0000000, 'u', "Unknown", "oops" }, { 0x0000000, 0x0000000, 'u', "Unknown1", "oops1" }, { 0x0000000, 0x0000000, 'G', "Gemini?", "gem?" }, { 0x3004000, 0x3000000, 'U', "Ulysses", "uly" }, { 0x0820000, 0x0800000, 'C', "Calypso", "cal" }, { 0x0804000, 0x0800000, 'c', "Calypso Lite", "cal_l" }, { 0x8020000, 0x8000100, 'P', "Calypso Plus", "cal_p" } }; int target_type; int target_clk; // 13000000 or 14745600 struct device_s *device; uint8 target_program[TARGET_PROGRAM_SIZE_MAX]; int target_program_size; int target_fifo_size; uint8 image[IMAGE_SIZE_MAX]; int image_size; // size of image buffer int image_chunk_size; // number of bytes in each chunk int image_size_in_chunks; // size of image buffer in chunks // Each byte in the image_map represents one chunk of the image. Each byte // can have one of the following values: // '\0' = no data in this chunk // 's' = skip this chunk when programming // 'c' = chunk checksum ok, skip this chunk when programming // 'x' = used uint8 image_map[IMAGE_SIZE_MAX / IMAGE_CHUNK_SIZE]; int image_map_size; // number of entries in image_map // Each byte in the sector_map represents one sector. Each byte can have one // of the following values: // '\0' = sector unused (don't erase) // 'c' = sector already empty/erased (don't erase) (not used) // 's' = skip this sector when erasing (due to erase override) // 'X' = force erase this sector (due to erase override) // 'x' = erase this sector (normal case --- sector is covered by image) int sector_map[SECTOR_MAP_SIZE_MAX]; int sector_map_size; int erase_list[ERASE_LIST_SIZE_MAX]; int erase_list_size; struct image_part_s read_list[READ_LIST_SIZE_MAX]; int read_list_size; int read_total_size; int image_map_count_used_chunks(void); int image_map_update(void); int sector_map_init(void); void image_map_show(void); void sector_map_show(void); void target_timers_show(void); void parse_arg_erase_override(char *p); void parse_arg_read(char *p); void parse_arg_write(char *p); void error_proto(char ch, char ch_expected); int target_type_set(uint16 code); // Secure Calypso Plus void f_print_signalling_response(int level); void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate); void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate); void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts); void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts); UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate); void target_imei_protection(void); /****************************************************************************** * Main ******************************************************************************/ void bootloader_machine(void); void cmd_machine(void); void flash_checksum_machine(void); void flash_detect_machine(void); void method_download_machine(void); void flash_program_machine(void); void flash_read_machine(void); void target_reset_machine(void); void fluid_machine(void) { int error; // If user has specifically asked fluid just to reset the target, we do // that and only that! This way, we can use fluid just to reset the // target without doing anything else! if (arg_target_reset == 2 && arg_dry_run) { flowf(VERBOSE, "Resetting target: "); target_reset(0); target_wait(0, TARGET_RESET_DELAY); target_reset(1); flowf(VERBOSE, "ok\n"); } file_read_devices("devices.txt"); if (arg_list_devices) { devices_list(); exit(0); } image_size = IMAGE_SIZE_MAX; image_chunk_size = IMAGE_CHUNK_SIZE; image_map_size = IMAGE_SIZE_MAX / image_chunk_size; image_size_in_chunks = (image_size + image_chunk_size - 1) / image_chunk_size; // Read the flash image file(s) unless user wants to read from the flash if (*arg_read == 0) { file_read_image(image, IMAGE_SIZE_MAX, image_map, image_chunk_size); // Optionally overwrite image with values given on the command-line parse_arg_write(arg_write); if (arg_image_map_show) image_map_show(); } if ((error = target_driver_init(arg_uart_port, 115200, arg_uart_flowcontrol)) < 0) main_fatal(error); if (target_type_set(arg_target_type) != 0) flowf(VERBOSE, "Target type '%s' selected.\n", target[target_type].name); // Conditionally disable tracing if (arg_debug_trace_pe) tr_enable(0); if (arg_debug_resume) { // If resuming in command interpreter, we should set the baudrate // because we do not pass through the code that normally sets it. if ((error = target_driver_baudrate(arg_uart_baudrate)) < 0) main_fatal(error); } else { bootloader_machine(); cmd_machine(); } if (*arg_read != 0) { parse_arg_read(arg_read); flash_read_machine(); file_write_image(image, image_size, read_list); } else { if (arg_checksum) flash_checksum_machine(); flash_detect_machine(); if (!arg_debug_resume) { method_download_machine(); } tr_enable(1); // Ensure full tracing is on flash_program_machine(); if (*arg_imeisv && *arg_platform_certificate_addr) target_imei_protection(); if (arg_timers_show) target_timers_show(); if (arg_target_reset == 1) target_reset_machine(); } } /****************************************************************************** * Bootloader (TI Target Monitor) Access ******************************************************************************/ // Invoke the Fluid bootloader embedded in the TI bootloader/target-monitor // code. The command to enter the loader is 0xAA 0x01 0xDD, which must be // received by the phone within 50ms from reset. int bootloader_is_rom; int bootloader_is_secure_rom; // Secure Calypso Plus int bootloader_blocksize_max; void bootloader_fluid_init(void); void bootloader_rom_init(void); void bootloader_secure_rom_init(void); // Secure Calypso Plus void bootloader_machine(void) { // FIXME: why do we have to send an additional char (0) ? uint8 sendbuf_rom[3] = { '<', 'i', 0x0 }; uint8 sendbuf_fluid[3] = { 0xAA, 0x01, 0xDD }; int i, error; char ch1, ch2; // Secure Calypso Plus UWORD16 d_j; target_trace_enable(0); flowf(NORMAL, "Bootloader: "); // Wait a short while with power removed, then flush receive buffer. target_power(1); target_reset(0); target_wait(0, TARGET_RESET_DELAY); target_reset(1); target_recv_reset(); // Continuously send Fluid Bootloader escape sequence until we get an // acknowledgement. Note that we have to establish contact within 50ms // from reset, otherwise we lose our chance! Note that we actually wait // up to 500ms because the target may take some time to reset. i = 0; flowf(DEBUG, "(ROM/fluid-delay = %d/%d, ", arg_boot_delay_rom, arg_boot_delay_fluid); switch (arg_rom_bootloader) { case -1: if ((error = target_driver_baudrate(115200)) < 0) main_fatal(error); break; case +1: if ((error = target_driver_baudrate(19200)) < 0) main_fatal(error); break; } while (1) { target_recv_reset(); // If we are allowed to try fluid bootloader... if (arg_rom_bootloader != +1) { // If we should ONLY try fluid bootloader... flowf(DEBUG, "F"); if (arg_rom_bootloader == 0) if ((error = target_driver_baudrate(115200)) < 0) main_fatal(error); target_send(sendbuf_fluid, 3); if (target_wait(1, arg_boot_delay_fluid) > 0 && target_getchar() == PROTO_HELLO) { bootloader_is_rom = 0; bootloader_is_secure_rom = 0; // Secure Calypso Plus break; } } // If we are allowed to try ROM bootloader... if (arg_rom_bootloader != -1) { flowf(DEBUG, "R"); if (arg_rom_bootloader == 0) if ((error = target_driver_baudrate(19200)) < 0) main_fatal(error); target_send(sendbuf_rom, 3); if (target_wait(1, arg_boot_delay_rom) >= 1) { ch1 = target_getchar(); if (ch1 == '>') { if (target_wait(1, arg_boot_delay_rom) >= 1) { ch2 = target_getchar(); if (ch2 == 'i') { bootloader_is_rom = 1; // Secure Calypso Plus if (target_wait(2, arg_boot_delay_rom) < 2) flowf(DEBUG, ", Non-secure boot ROM code"); else { flowf(DEBUG, ", Secure Calypso Plus ROM)"); ch1 = target_getchar(); ch2 = target_getchar(); d_ram_loader.d_romcode_version = (UWORD16)(ch1) & 0xFF; d_ram_loader.d_romcode_version |= ((UWORD16)(ch2 & 0xFF)) << 8; //d_ram_loader.d_romcode_version |= (((UWORD16)ch2) << 8) & 0xFF00; if (d_ram_loader.d_romcode_version == 0x0410 || d_ram_loader.d_romcode_version == 0x0411) { bootloader_is_secure_rom = 1; if (target_wait((C_WORD32LGB * C_MD5HASHLG), TARGET_RECV_DELAY) < (C_WORD32LGB * C_MD5HASHLG)) main_fatal(E_RECV_TIMEOUT); for (d_j = 0 ; d_j < (C_WORD32LGB * C_MD5HASHLG) ; d_j++) d_ram_loader.a_hash_man_pub_key[d_j] = target_getchar(); if (target_wait((C_WORD32LGB * C_DIE_ID_SIZE), TARGET_RECV_DELAY) < (C_WORD32LGB * C_DIE_ID_SIZE)) main_fatal(E_RECV_TIMEOUT); for (d_j = 0 ; d_j < (C_WORD32LGB * C_DIE_ID_SIZE) ; d_j++) d_ram_loader.a_die_id[d_j] = target_getchar(); // SIGNALLING RESPONSE f_print_signalling_response(VERBOSE); if (*arg_die_id_file_name != 0) { if ((error = file_write_die_id(&d_ram_loader.a_die_id[0], arg_die_id_file_name)) < 0) { flowf(NORMAL, "\n"); main_fatal(error); } flowf(NORMAL, "\nDie id retrieved and written to %s.\n", arg_die_id_file_name); exit(0); } } else { flowf(NORMAL, "\nSecure Calypso Plus ROM Code Version 0x%4.4x is not supported by FLUID.\n", d_ram_loader.d_romcode_version); main_fatal(E_BOOTLOADER); } } // End Secure Calypso Plus break; } else flowf(DEBUG, "?"); } } } } // If target is still not responding, we could not control the reset // line, so we ask the user to reset the target if (i++ == RETRIES_MAX) flowf (NORMAL, "(reset target) "); } if (!bootloader_is_secure_rom) flowf(DEBUG, ") "); // Read the command interpreter image file. if (bootloader_is_secure_rom) target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, a_certified_cmd_file_name); else target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, "cmd.m0"); if (target_program_size == 0) main_error(E_FILE_EMPTY); if (bootloader_is_secure_rom) bootloader_secure_rom_init(); else if (bootloader_is_rom) bootloader_rom_init(); else bootloader_fluid_init(); flowf(NORMAL, ") ok\n"); } void bootloader_fluid_init(void) { int divider; char version; uint8 data[4]; uint16 chip_id_code; flowf(NORMAL, "(fluid"); target_clk = 13000000; // Now send baudrate to make the target stop sending 'H'ello. divider = target_uart_baudrate_divider_get(target_clk, 115200); flowf(DEBUG, ", baudrate = "); target_putchar(0); target_putchar((char) divider); flowf(DEBUG, "%d, ", 115200); // Wait a short while before flushing receive buffer. Then make sure // that the target is indeed silent target_wait(0, 10); target_recv_reset(); if (target_wait(1, 50) > 0) main_fatal(E_RECV_ANTITIMEOUT); // NOTEME: The sequence below to query the Bootloader VERSION *has* to // have 100ms + 100ms delays. It seems as unnecessarily large delays but // practice shows that they cannot be shorter. To be investigated... // Get version of bootloader target_putchar(PROTO_VERSION); if (target_wait(1, TARGET_RECV_DELAY) < 1) main_fatal(E_RECV_TIMEOUT); version = target_getchar(); flowf(NORMAL, ", version %c", version); // Bootloader revision 3 and upwards supports generic query if (version < '3') { main_fatal(E_BOOTLOADER); } target_trace_enable(1); target_putchar(PROTO_QUERY); target_putchar(PROTO_QUERY_CHIP); if (target_wait(4, TARGET_RECV_DELAY) < 4) main_fatal(E_RECV_TIMEOUT); target_recv(data, 4); chip_id_code = data[0] + (data[1] << 8); if (target_type_set(chip_id_code) == 0 || arg_verbose >= VERBOSE) { flowf(VERBOSE, ", chipid = 0x%04X", chip_id_code); if (target_type_set(chip_id_code) == 0) main_fatal(E_TARGET_TYPE); } flowf(VERBOSE, ", %s", target[target_type].name); } void bootloader_rom_init(void) { int error; char ch, version = '?'; // Initialization: 115200 bps, 39 MHz DPLL, no timeout uint8 sendbuf[11] = { '<', 'p', 0x00, 0x0D, 0x14, 0x25, 0x22, 0x00, 0x00, 0x00, 0x00}; // Initialization: 115200 bps, 13 MHz DPLL, no timeout. //uint8 sendbuf[11] = { '<', 'p', 0x00, 0x00, 0x1C, 0xE7, // 0x22, 0x00, 0x00, 0x00, 0x00 }; flowf(NORMAL, "(ROM"); // Configure/init the ROM bootloader flowf(VERBOSE, ", baudrate = %d", 115200); target_send(sendbuf, 11); // Wait until DPLL is settled and target responds if (target_wait(4, 300) < 4) main_fatal(E_RECV_TIMEOUT); if ((ch = target_getchar ()) != '>') error_proto(ch, '>'); if ((ch = target_getchar ()) != 'p') error_proto(ch, 'p'); // Receive maximum blocksize bootloader_blocksize_max = target_getchar(); bootloader_blocksize_max += target_getchar() << 8; bootloader_blocksize_max -= 10; // Subtract the block header flowf(DEBUG, ", blocksize = %iB", bootloader_blocksize_max); if ((error = target_driver_baudrate (115200)) < 0) main_fatal(error); flowf(NORMAL, ", version %c", version); // NOTEME: Can we be sure that it is always a Calypso type? target_type_set('c'); } // Secure Calypso Plus void bootloader_secure_rom_init(void) { int error; UWORD8 d_char; UWORD16 d_j; // cmdp_cert.m0 has been 16 bit aligned using hex470, so the memory width // parameter is set to 2 bytes. buffer_endian_convert(target_program, target_program_size, 2); // Check if firmware manufacturer certificate stored in flash is requested if (arg_request_certificate) { // Clear the request arg_request_certificate = 0; d_ram_loader.b_certificate_request = C_FALSE; // Certificate Request d_frame.a_data[0] = '<'; d_frame.a_data[1] = 'c'; d_frame.d_max_byte = 2; target_send(&d_frame.a_data[0], d_frame.d_max_byte); // Certificate Response target_expect_char('>', arg_boot_delay_rom); target_expect_char('c', arg_boot_delay_rom); if (target_wait(2, TARGET_RECV_DELAY) < 2) main_fatal(E_RECV_TIMEOUT); d_ram_loader.u_firm_cert.a_firm_cert[0] = target_getchar (); d_ram_loader.u_firm_cert.a_firm_cert[1] = target_getchar (); d_certificate_length = (UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[0]) & 0xFF; d_certificate_length |= ((UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[1]) << 8) & 0xFF00; // We have already read two bytes of the certificate for the CERT_SIZE // and the certificate signature is handled later. for (d_j = 2 ; d_j < d_certificate_length - (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) { if (target_wait(1, arg_boot_delay_rom * 4) > 0) d_ram_loader.u_firm_cert.a_firm_cert[d_j] = target_getchar (); else main_fatal(E_RECV_TIMEOUT); } for (d_j = 0; d_j < (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) { if (target_wait(1, arg_boot_delay_rom * 4) > 0) d_ram_loader.a_Certsig[d_j] = target_getchar (); else main_fatal(E_RECV_TIMEOUT); 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]; } f_print_certificate_platform_data(NORMAL, &d_ram_loader.u_firm_cert.d_firm_cert); } // Parameter Request d_ram_loader.d_baud_rate = f_convert_uart_baud_rate(arg_uart_baudrate_during_cmd_download); d_ram_loader.d_uart_timeout = arg_uart_timeout_configuration; // TODO: Verify that MSB byte is sent in first position. d_frame.a_data[0] = '<'; d_frame.a_data[1] = 'p'; d_frame.a_data[2] = d_ram_loader.d_baud_rate; memcpy(&d_frame.a_data[3], &d_ram_loader.d_uart_timeout, sizeof(UWORD32)); d_frame.d_max_byte = 3 + sizeof(UWORD32); d_certificate_length = (UWORD16)(target_program[0]) & 0xFF; d_certificate_length |= ((UWORD16)(target_program[1]) & 0xFF) << 8; for (d_j = 0 ; d_j < d_certificate_length; d_j++) d_ram_loader.u_code_certificate.a_code_certificate[d_j] = target_program[d_j]; f_print_certificate(DEBUG, &d_ram_loader.u_code_certificate.d_code_certificate); // Send the data target_send(&d_frame.a_data[0], d_frame.d_max_byte); target_send(&target_program[0], d_certificate_length); // Parameter Response if (target_wait(2, TARGET_RECV_DELAY) < 2) main_fatal(E_RECV_TIMEOUT); if ((d_char = target_getchar ()) != '>') error_proto(d_char, '>'); if ((d_char = target_getchar ()) != 'p') { if (d_char == 'P') { // PARAMETER_NACK_RESPONSE if (target_wait(1, arg_boot_delay_rom) >= 1) { d_ram_loader.d_param_req_sts = target_getchar(); f_print_parameter_nack_status(NORMAL, d_ram_loader.d_param_req_sts); } } error_proto(d_char, 'p'); } // PARAMETER_ACK_RESPONSE flowf(NORMAL, "\n(Secure ROM"); if ((error = target_driver_baudrate (arg_uart_baudrate_during_cmd_download)) < 0) main_fatal(error); // Configure/init the ROM bootloader flowf(VERBOSE, ", UART baud rate during download of flash programmer, %s = %d Kbps", a_certified_cmd_file_name, arg_uart_baudrate_during_cmd_download); } // End Secure Calypso Plus /****************************************************************************** * Command Interpreter Download ******************************************************************************/ int cmd_baudrate(int baudrate); void cmd_machine_fluid(void); void cmd_machine_rom(void); void cmd_machine_secure_rom(void); // Secure Calypso Plus void cmd_machine(void) { char ramcs0, ch; uint8 count = 0; uint16 chip_id; flowf(VERBOSE, "Command Interpreter: ("); target_trace_enable(0); // Secure Calypso Plus if (bootloader_is_secure_rom) cmd_machine_secure_rom(); else if (bootloader_is_rom) cmd_machine_rom(); else cmd_machine_fluid(); // Now send 'H'ello command to target and get the response, such as // hardware type etc. while (count < RETRIES_MAX) { target_putchar(PROTO_HELLO); if (target_wait(1, TARGET_RECV_DELAY) >= 1) { ch = target_getchar(); flowf(DEBUG, ", received %c (0x%2.2x)", ch, ch); if (ch == PROTO_READY) break; } count++; } if (count == RETRIES_MAX) main_fatal(E_RECV_TIMEOUT); if (target_wait(5, TARGET_RECV_DELAY) < 4) main_fatal(E_RECV_TIMEOUT); chip_id = (target_getchar() & 0xFF); chip_id |= (target_getchar() & 0xFF) << 8; ramcs0 = (target_getchar() == 'R'); ch = target_getchar(); flowf(BLABBER, ", SRAM = %dk", (1 << ch) / 1024); target_fifo_size = target_getchar(); flowf(DEBUG, ", fifo = %d", target_fifo_size); if (target_type_set(chip_id) == 0 || arg_verbose >= VERBOSE) { flowf(BLABBER, ", "); flowf(VERBOSE, "chipid = 0x%04X", chip_id); if (target_type_set(chip_id) == 0) main_fatal(E_TARGET_TYPE); } flowf(VERBOSE, ", %s", target[target_type].name); if (ramcs0) flowf(VERBOSE, ", RAM"); // Configure target target_putchar(PROTO_INIT); target_putchar(target[target_type].type); target_expect_char(PROTO_READY, TARGET_RECV_DELAY); // Change baudrate. First try to change to new baudrate. If this fails, // try 115.2 Kbps. If this also fails, panic and bail out. if (arg_uart_baudrate != 115200) { flowf(VERBOSE, ", baudrate = "); flowf(VERBOSE, "%d", arg_uart_baudrate); if (!cmd_baudrate(arg_uart_baudrate)) { arg_uart_baudrate = 115200; flowf(VERBOSE, " %d", arg_uart_baudrate); if (!cmd_baudrate(arg_uart_baudrate)) main_fatal(E_RECV_TIMEOUT); } } flowf(VERBOSE, ") "); flowf(VERBOSE, "ok\n"); // Secure Calypso Plus // There is a bug in ROM code 0x0410 which means that the secure boot // loader cannot boot if the firmware certificate size is greater than the // max size of 0xFFF8. A workaround is to change the memory mapping on CS5 // by initially setting DIP switches 9 and 10 to ON and thereby exchanging // the mapping of RAM and flash. While waiting, set the DIP switches back // to OFF. See SECURITY.txt and BUG03314 in CALPLUS228. if (arg_delay_for_changing_cs5 != 0) { flowf(NORMAL, "\nWaiting %d seconds for changing memory mapping on CS5 or connecting via JTAG...\n", arg_delay_for_changing_cs5); target_wait(0, arg_delay_for_changing_cs5 * 1000); } } int cmd_baudrate(int baudrate) { int error; int divider; char xxo; target_putchar(PROTO_BAUDRATE); if (baudrate == 230400 || baudrate == 460800 || baudrate == 921600) { // Changing the target clock frequency to 14 MHz target_clk = 14745600; // If we are using a 14 MHz compatible baud rate, we should enable the // eXternal Xtal Oscillator of the target xxo = PROTO_BAUDRATE_XXO; } else { target_clk = 13000000; xxo = 0; } divider = target_uart_baudrate_divider_get(target_clk, baudrate); target_putchar(xxo); target_putchar((char) divider); if ((error = target_driver_baudrate(baudrate)) < 0) main_fatal(error); // Wait for acknowledgement if (target_wait(1, 2 * TARGET_RECV_DELAY) >= 1 && target_getchar() == PROTO_READY) { return 1; } else { if ((error = target_driver_baudrate(115200)) < 0) main_fatal(error); return 0; } } void cmd_machine_fluid(void) { uint8 sendbuf[1+4+2]; int error; // Send 'Download' command header. Then wait for acknowledgement. buf_put1(&sendbuf[0], PROTO_DOWNLOAD); buf_put4(&sendbuf[1], target[target_type].cmd_load_addr); buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2); target_send(sendbuf, 1+4+2); flowf(BLABBER, "0x%X", target[target_type].cmd_load_addr); if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) main_fatal(error); // Send data. Then wait for acknowledgement. target_trace_enable(1); target_send(target_program, target_program_size); flowf(BLABBER, ", %d", target_program_size); } void cmd_machine_rom(void) { uint8 sendbuf[10], *buf; int error, i; int block_addr; int block_offset = 0; int block_size; uint8 ch, blksum, cksum = 0; // NOTEME: Can we be sure that it is always a Calypso type? target_type_set('c'); block_addr = target[target_type].cmd_load_addr; buffer_endian_convert(target_program, target_program_size, 2); flowf(BLABBER, "0x%X, ", target[target_type].cmd_load_addr); // Transfer the target program as blocks while (block_offset < target_program_size) { block_size = target_program_size - block_offset; if (block_size > bootloader_blocksize_max) block_size = bootloader_blocksize_max; // Initialize block transfer buf = sendbuf; buf += buf_put1(buf, '<'); buf += buf_put1(buf, 'w'); buf += buf_put1(buf, 0x01); // block index - just use #1 - not important buf += buf_put1(buf, 0x01); // block number - just use #1 - not important buf += buf_put2no(buf, (uint16) block_size); buf += buf_put4no(buf, block_addr + block_offset); target_send(sendbuf, 10); // Send the data target_send(&target_program[block_offset], block_size); // Calculate block check-sum blksum = 5; blksum += block_size & 0x00ff; blksum += (((block_addr + block_offset) & 0xff000000) >> 24); blksum += (((block_addr + block_offset) & 0x00ff0000) >> 16); blksum += (((block_addr + block_offset) & 0x0000ff00) >> 8); blksum += ( (block_addr + block_offset) & 0x000000ff); for (i = block_offset; i < (block_offset + block_size); i++) blksum += target_program[i]; cksum += ~blksum; block_offset = block_offset + block_size; if ((error = target_expect_char ('>', TARGET_RECV_DELAY)) < 0) main_fatal (error); if ((error = target_expect_char ('w', TARGET_RECV_DELAY)) < 0) main_fatal (error); flowf(BLABBER, "."); } flowf(BLABBER, ", %d", target_program_size); target_wait(0, 100); // Request compare of checksum target_putchar('<'); target_putchar('c'); target_putchar((char) ~cksum); if ((error = target_expect_char('>', TARGET_RECV_DELAY)) < 0) main_fatal(error); if ((error = target_expect_char('c', TARGET_RECV_DELAY)) < 0) main_fatal(error); if ((error = target_wait(1, TARGET_RECV_DELAY)) < 1) main_fatal(error); ch = target_getchar(); flowf(DEBUG, ", cksum = 0x%x (0x%x)", ch, cksum); if (ch != cksum) main_fatal(E_SEND_CHECKSUM); // Branch to code buf = sendbuf; buf += buf_put1(buf, '<'); buf += buf_put1(buf, 'b'); buf += buf_put4no(buf, target[target_type].cmd_load_addr); target_send(sendbuf, 6); if (target_wait(2, TARGET_RECV_DELAY) < 2) main_fatal(E_RECV_TIMEOUT); if ((ch = target_getchar()) != '>') error_proto(ch, '>'); if ((ch = target_getchar()) != 'b') error_proto(ch, 'b'); target_wait(0, 100); } // Secure Calypso Plus void cmd_machine_secure_rom(void) { UWORD8 d_char; UWORD16 d_i; target_type_set('p'); flowf(BLABBER, "0x%X", d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode); flowf(DEBUG, ")"); // Prepare the write command d_ram_loader.d_nb_byte_in_block = (UWORD32) arg_block_size; d_ram_loader.d_nb_byte_sent = 0; d_ram_loader.d_block_address = d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode; while (d_ram_loader.d_nb_byte_sent < d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize) { flowf(DEBUG, "\nCurrent write parameters:\n"); flowf(DEBUG, " Max Number of Bytes in Block: %ld\n", d_ram_loader.d_nb_byte_in_block); flowf(DEBUG, " Block Address : 0x%8.8lx\n", d_ram_loader.d_block_address); flowf(DEBUG, " Code Size : %ld\n", d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize); flowf(DEBUG, " Bytes sent : %ld\n", d_ram_loader.d_nb_byte_sent); // Set block size d_ram_loader.d_block_size = d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize - d_ram_loader.d_nb_byte_sent; if (d_ram_loader.d_block_size > d_ram_loader.d_nb_byte_in_block) d_ram_loader.d_block_size = d_ram_loader.d_nb_byte_in_block; flowf(DEBUG, " Block Size : %ld\n", d_ram_loader.d_block_size); // Write Request d_frame.a_data[0] = '<'; d_frame.a_data[1] = 'w'; // Send block size for (d_i = 0; d_i < 32; d_i += 8) d_frame.a_data[2 + d_i / 8] = (UWORD8)(d_ram_loader.d_block_size >> (24 - d_i)); // Send block address for (d_i = 0; d_i < 32; d_i += 8) d_frame.a_data[2 + sizeof(UWORD32) + d_i / 8] = (UWORD8)(d_ram_loader.d_block_address >> (24 - d_i)); d_frame.d_max_byte = 2 + sizeof(UWORD32) + sizeof(UWORD32); // Send the data target_send(&d_frame.a_data[0], d_frame.d_max_byte); target_send(&target_program[d_certificate_length + d_ram_loader.d_nb_byte_sent], d_ram_loader.d_block_size); // Update next block address d_ram_loader.d_block_address += d_ram_loader.d_block_size; d_ram_loader.d_nb_byte_sent += d_ram_loader.d_block_size; // Write Response if (target_wait(2, TARGET_RECV_DELAY) < 2) main_fatal(E_RECV_TIMEOUT); if ((d_char = target_getchar ()) != '>') error_proto(d_char, '>'); if ((d_char = target_getchar ()) != 'w') { if (d_char == 'W') { // WRITE_NACK_RESPONSE if (target_wait(1, arg_boot_delay_rom) >= 1) { d_ram_loader.d_write_status = target_getchar(); f_print_write_nack_status(NORMAL, d_ram_loader.d_write_status); } } error_proto(d_char, 'w'); } // WRITE_ACK_RESPONSE } // End while if (arg_verbose == BLABBER) flowf(BLABBER, ", "); else flowf(DEBUG, "("); flowf(BLABBER, "%d", d_ram_loader.d_nb_byte_sent); target_wait(0, 100); // Abort Request d_frame.a_data[0] = '<'; d_frame.a_data[1] = 'a'; d_frame.d_max_byte = 2; target_send(&d_frame.a_data[0], d_frame.d_max_byte); target_wait(0, 100); } void f_print_signalling_response(int level) { UWORD16 d_i; flowf(level, "\nSignalling Response:\n"); flowf(level, " ROM Code Version: 0x%4.4x\n", d_ram_loader.d_romcode_version); flowf(level, " Hash (ManPubKey): "); for (d_i = 0; d_i < (C_WORD32LGB * C_MD5HASHLG); d_i++) { if (d_i == (C_WORD32LGB * C_MD5HASHLG) / 2) flowf(level, "\n "); flowf(level, "0x%2.2x ", d_ram_loader.a_hash_man_pub_key[d_i]); } flowf(level, "\n"); flowf(level, " Die Id : "); for (d_i = 0; d_i < (C_WORD32LGB * C_DIE_ID_SIZE); d_i++) flowf(level, "0x%2.2x ", d_ram_loader.a_die_id[d_i]); flowf(level, "\n"); } /* f_print_signalling_response() */ void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate) { UWORD16 d_i, d_j, d_max = 4; flowf(level, "\nFirmware Manufacturer Certificate:\n"); flowf(level, "----------------------------------\n"); flowf(level, " Size of Certificate: %d bytes\n", p_certificate->d_manufacturer_certificate.d_Certsize); flowf(level, " Type of Certificate: 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Certtype); flowf(level, " Emulation Request : 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Debugrequest); flowf(level, " Address of Code : 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Addcode); flowf(level, " Size of Code : %ld bytes\n", p_certificate->d_manufacturer_certificate.d_Codesize); flowf(level, " Entry Point Address: 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_CodeStartAdd); flowf(level, " Manufacturer Public Key:\n"); flowf(level, " Public Modulus:"); d_j = d_max; for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Manpubkey.a_Modulus[d_i]); } flowf(level, "\n"); flowf(level, " Public Modulus Length:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_ModulusLength); flowf(level, " Public Exponent:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_Exponent); flowf(level, " Originator Public Key:\n"); flowf(level, " Public Modulus:"); d_j = d_max; for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Origpubkey.a_Modulus[d_i]); } flowf(level, "\n"); flowf(level, " Public Modulus Length:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_ModulusLength); flowf(level, " Public Exponent:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_Exponent); flowf(level, " Originator Public Key Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Origpubkeysig[d_i]); } flowf(level, "\n"); flowf(level, " Software Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Swsig[d_i]); } flowf(level, "\n"); flowf(level, " Configuration Parameters:\n"); flowf(level, " CONF_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_conf_cs5); flowf(level, " EXWS_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_exws_cs5); flowf(level, " EX_CTRL register : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_ex_ctrl); flowf(level, " CS image request : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_cs_img_req); flowf(level, " Flash size : %ld bytes\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_flash_size); flowf(level, " Granularity : %ld words\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_granularity); flowf(level, " Die Id: "); for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) { flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_die_id[d_i]); } flowf(level, "\n"); if (p_certificate->d_manufacturer_certificate.d_Certsize > (sizeof(T_MANUFACTURER_CERTIFICATE) + (C_WORD32LGB * C_MANUF_SIG_SIZE))) { flowf(level, " Platform Data:"); d_j = d_max; 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++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->a_platform_data[d_i]); } flowf(level, "\n"); } flowf(level, " Certificate Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]); } flowf(level, "\n"); } /* f_print_certificate_platform_data() */ void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate) { UWORD16 d_i, d_j, d_max = 4; flowf(level, "\nFlash Programmer Manufacturer Certificate:\n"); flowf(level, "------------------------------------------\n"); flowf(level, " Size of Certificate: %d bytes\n", p_certificate->d_Certsize); flowf(level, " Type of Certificate: 0x%2.2x\n", p_certificate->d_Certtype); flowf(level, " Emulation Request : 0x%2.2x\n", p_certificate->d_Debugrequest); flowf(level, " Address of Code : 0x%8.8lx\n", p_certificate->d_Addcode); flowf(level, " Size of Code : %ld bytes\n", p_certificate->d_Codesize); flowf(level, " Entry Point Address: 0x%8.8lx\n", p_certificate->d_CodeStartAdd); flowf(level, " Manufacturer Public key:\n"); flowf(level, " Public Modulus:"); d_j = d_max; for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_Manpubkey.a_Modulus[d_i]); } flowf(level, "\n"); flowf(level, " Public Modulus Length:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_Manpubkey.d_ModulusLength); flowf(level, " Public Exponent:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_Manpubkey.d_Exponent); flowf(level, " Originator Public key:\n"); flowf(level, " Public Modulus:"); d_j = d_max; for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->d_Origpubkey.a_Modulus[d_i]); } flowf(level, "\n"); flowf(level, " Public Modulus Length:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_Origpubkey.d_ModulusLength); flowf(level, " Public Exponent:\n"); flowf(level, " 0x%8.8lx\n", p_certificate->d_Origpubkey.d_Exponent); flowf(level, " Originator Public Key Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->a_Origpubkeysig[d_i]); } flowf(level, "\n"); flowf(level, " Software Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_RSASIGLG); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->a_Swsig[d_i]); } flowf(level, "\n"); flowf(level, " Configuration Parameters:\n"); flowf(level, " CONF_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_conf_cs5); flowf(level, " EXWS_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_exws_cs5); flowf(level, " EX_CTRL register : %4.4x\n",p_certificate->d_Confparam.d_ex_ctrl); flowf(level, " CS image request : %4.4x\n",p_certificate->d_Confparam.d_cs_img_req); flowf(level, " Flash size : %ld bytes\n",p_certificate->d_Confparam.d_flash_size); flowf(level, " Granularity : %ld words\n",p_certificate->d_Confparam.d_granularity); flowf(level, " Die Id: "); for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) { flowf(level, "0x%8.8lx ", p_certificate->a_die_id[d_i]); } flowf(level, "\n"); flowf(level, " Certificate Signature:"); d_j = d_max; for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) { if (d_j++ == d_max) { flowf(level, "\n "); d_j = 1; } flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]); } flowf(level, "\n"); } /* f_print_certificate() */ void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts) { flowf(level, "\nParameter NAck Response Status:\n"); flowf(level, " 0x%2.2x", d_parameter_nack_sts); switch(d_parameter_nack_sts) { case 0x01 : { flowf(level, " Incorrect baud rate\n"); break; } case 0x02 : { flowf(level, " Incorrect certificate\n"); break; } case 0x03 : { flowf(level, " Incorrect code address\n"); break; } } flowf(level, "\n"); } /* f_print_parameter_nack_status() */ void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts) { flowf(level, "\nWrite NAck Response Status:\n"); flowf(level, " 0x%2.2x", d_write_nack_sts); switch(d_write_nack_sts) { case 0x01 : { flowf(level, " Incorrect block address\n"); break; } case 0x02 : { flowf(level, " Non-64 bytes block size\n"); break; } case 0x03 : { flowf(level, " First block is not code address\n"); break; } case 0x04 : { flowf(level, " Error in firmware signature check\n"); break; } case 0x05 : { flowf(level, " Received code size does not match the code size in certificate\n"); break; } case 0x06 : { flowf(level, " Error during block hashing\n"); break; } } flowf(level, "\n"); } /* f_print_write_nack_status() */ UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate) { UWORD8 d_converted_baud_rate; switch (d_baud_rate) { case 0: case 812: case 812500: { d_converted_baud_rate = 0x00; arg_uart_baudrate_during_cmd_download = 812500; break; } case 1: case 406: case 406250: { d_converted_baud_rate = 0x01; arg_uart_baudrate_during_cmd_download = 406250; break; } case 2: case 203: case 203125: { d_converted_baud_rate = 0x02; arg_uart_baudrate_during_cmd_download = 203125; break; } case 3: case 115: case 115200: { d_converted_baud_rate = 0x03; arg_uart_baudrate_during_cmd_download = 115200; break; } case 4: case 57: case 57600: { d_converted_baud_rate = 0x04; arg_uart_baudrate_during_cmd_download = 57600; break; } case 5: case 38: case 38400: { d_converted_baud_rate = 0x05; arg_uart_baudrate_during_cmd_download = 38400; break; } case 6: case 28: case 28800: { d_converted_baud_rate = 0x06; arg_uart_baudrate_during_cmd_download = 28800; break; } case 7: case 19: case 19200: { d_converted_baud_rate = 0x07; arg_uart_baudrate_during_cmd_download = 19200; break; } default: { d_converted_baud_rate = 0x03; arg_uart_baudrate_during_cmd_download = 115200; break; } } return d_converted_baud_rate; } /* f_convert_uart_baud_rate() */ void target_imei_protection(void) { uint8 a_imeisv[C_IMEISV_BYTES]; uint8 a_platform_cert_addr[C_PLATFORM_CERT_ADDR_BYTES]; uint8 d_i, d_digit, d_temp; uint8 d_error; flowf(NORMAL, "\nIMEI protection: "); if (arg_dry_run) { flowf(NORMAL, "(dry-run) ok\n"); return; } target_putchar(PROTO_IMEI_PROTECT); // Send IMEI-SV for (d_i = 0; d_i < C_IMEISV_DIGITS; d_i++) { sscanf(arg_imeisv++, "%1d", &d_digit); if (!(d_i & 1)) d_temp = d_digit << 4; else { d_temp |= d_digit; a_imeisv[d_i / 2] = d_temp; } } target_send(a_imeisv, C_IMEISV_BYTES); target_expect_char(PROTO_READY, TARGET_RECV_DELAY); // Send platform certificate address for (d_i = 0; d_i < C_PLATFORM_CERT_ADDR_DIGITS; d_i++) { sscanf(arg_platform_certificate_addr++, "%1x", &d_digit); if (!(d_i & 1)) d_temp = d_digit << 4; else { d_temp |= d_digit; a_platform_cert_addr[d_i / 2] = d_temp; } } target_send(a_platform_cert_addr, C_PLATFORM_CERT_ADDR_BYTES); target_expect_char(PROTO_READY, TARGET_RECV_DELAY); // Check if address range is erased if (target_wait(1, TARGET_RECV_DELAY) < 1) main_fatal(E_RECV_TIMEOUT); d_error = target_getchar(); if (d_error == PROTO_ERROR_VERIFY) { flowf(NORMAL, "\n The address range for platform certificate and IMEI-SV is not erased.\n"); main_fatal(E_FLASH_VERIFY); } if (d_error != PROTO_READY) error_proto(d_error, PROTO_READY); // Verify that the binding service call in target has succeeded if (target_wait(1, TARGET_RECV_DELAY) < 1) main_fatal(E_RECV_TIMEOUT); d_error = target_getchar(); if (d_error == PROTO_ERROR_ROM_SSERVICE) { flowf(NORMAL, "\n The Run-Time Loader (Binding) Service failed.\n"); main_fatal(E_ROM_SSERVICE); } if (d_error != PROTO_FLASH_START) error_proto(d_error, PROTO_FLASH_START); // Receive acknowledgement for programming the platform certificate if (target_wait(1, TARGET_RECV_DELAY) < 1) main_fatal(E_RECV_TIMEOUT); d_error = target_getchar(); if (d_error != PROTO_PROGRAM) { flowf(NORMAL, "\n Platform certificate was not stored correctly in flash.\n"); error_proto(d_error, PROTO_PROGRAM); } // Receive acknowledgement for programming the IMEI-SV if (target_wait(1, TARGET_RECV_DELAY) < 1) main_fatal(E_RECV_TIMEOUT); d_error = target_getchar(); if (d_error != PROTO_PROGRAM) { flowf(NORMAL, "\n IMEI-SV was not stored correctly in flash.\n"); error_proto(d_error, PROTO_PROGRAM); } flowf(NORMAL, "Platform certificate and IMEI-SV stored in flash.\n"); } // End Secure Calypso Plus /****************************************************************************** * Flash Detect ******************************************************************************/ void flash_detect_machine(void) { uint8 data[12]; uint16 m0, d0, m1, d1, d1ex1, d1ex2; flowf(NORMAL, "Flash Detect: "); target_trace_enable(0); if (arg_device_id0 != -1 || arg_device_id1 != -1) { // Device auto-detection is disabled m0 = m1 = arg_device_id0; d0 = d1 = arg_device_id1; flowf(VERBOSE, "(ID override) "); } else { target_putchar(PROTO_DETECT); if (target_wait(12, TARGET_RECV_DELAY) < 12) main_fatal(E_RECV_TIMEOUT); target_recv(data, 12); m0 = data[0] + (data[1] << 8); // Intel manufacturer id d0 = data[2] + (data[3] << 8); // Intel device id m1 = data[4] + (data[5] << 8); // AMD manufacturer id d1 = data[6] + (data[7] << 8); // AMD device di d1ex1 = data[8] + (data[9] << 8); // AMD extended device id d1ex2 = data[10] + (data[11] << 8); // AMD extended device id } // Lookup multi-id device if ((m1 == MANUFACT_AMD || m1 == MANUFACT_FUJITSU) && d1 == 0x227E) { flowf(NORMAL, "Multi-id device detected: (0x%04X, 0x%04X, 0x%04X)\n" , d1, d1ex1, d1ex2); d1 = (d1ex1 << 8) | (d1ex2 & 0xFF); flowf(DEBUG, "Multi-id converted to: 0x%04X\n", d1); if ((device = device_lookup_by_id(m1, d1)) == NULL) { flowf(NORMAL, "Id not found, lookup default multi-id conf.\n"); // Backward compatible/keep default multi-id configuration device = device_lookup_by_id(m1, 0x227E); } } // Lookup device with AMD and Intel ids else if ((device = device_lookup_by_id(m1, d1)) == NULL) device = device_lookup_by_id(m0, d0); if (device == NULL || arg_verbose >= DEBUG) { flowf(NORMAL, "(0x%02X, 0x%04X, 0x%02X, 0x%04X) ", m0, d0, m1, d1); if (device == NULL) main_fatal(E_FLASH_UNKNOWN); } if (arg_verbose >= NORMAL) { device_print(device, 's'); flowf(NORMAL, " ok\n"); } // Note that device_id is only 0x227E if the Multi-id configuration not // is found in device.txt (else device_id will be the 'converted' id) if (arg_device_id0 == -1 && arg_device_id1 == -1 && (device->manufacturer_id == MANUFACT_FUJITSU || device->manufacturer_id == MANUFACT_AMD ) && device->device_id == 0x227E) { flowf(NORMAL, "Warning: Extended device codes are supported when detecting flash devices,\n"); flowf(NORMAL, " but the detected multi-id configuration is not found in device.txt. \n"); flowf(NORMAL, " Update the device.txt manually if the default flash device is invalid.\n"); flowf(NORMAL, " Currently, %s %s is used as default.\n\n", manufacturer_name_lookup_by_id(device->manufacturer_id), device->name); } } /****************************************************************************** * Method Load ******************************************************************************/ void method_download_machine(void) { char sendbuf[1+2+4]; int error; target_program_size = file_read_method(target_program, TARGET_PROGRAM_SIZE_MAX, device); flowf(BLABBER, "Method Download: "); target_trace_enable(0); // Send 'Download' command header. Then wait for acknowledgement. buf_put1(&sendbuf[0], PROTO_DOWNLOAD); buf_put4(&sendbuf[1], target[target_type].method_load_addr); buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2); target_send(sendbuf, 1+4+2); flowf(BLABBER, "(0x%X", target[target_type].method_load_addr); if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) main_fatal(error); // Send data. Then wait for acknowledgement. target_trace_enable(1); target_send(target_program, target_program_size); flowf(BLABBER, ", %d) ", target_program_size); if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) main_fatal(error); flowf(BLABBER, "ok\n"); } /****************************************************************************** * Flash Checksum ******************************************************************************/ int time_checksum; #define CHECKSUMS 8 void flash_checksum_machine(void) { unsigned char sendbuf[1+1+4+4*CHECKSUMS], *buf; uint32 addr, cksum, mycksum; uint16 word; uint8 data[4]; int img_index = 0, chunks, n, i, j; int line = -1; struct { uint32 index; uint32 addr; uint32 mycksum; } block[CHECKSUMS]; chunks = image_map_count_used_chunks(); flowf(NORMAL, "Checksumming (%d * %dkB = %dkB): ", chunks, image_chunk_size / 1024, chunks * image_chunk_size / 1024); target_trace_enable(0); time_checksum = stopwatch_start(); while (chunks > 0) { n = (chunks > CHECKSUMS ? CHECKSUMS : chunks); buf = sendbuf; buf += buf_put1(buf, PROTO_CHECKSUM); buf += buf_put1(buf, (unsigned char) n); buf += buf_put4(buf, image_chunk_size); for (i = 0; i < n; i++) { // Find next used entry in image_map while (image_map[img_index] != 'x' && img_index < image_map_size) img_index++; if (img_index == image_map_size) break; addr = img_index * image_chunk_size; block[i].index = img_index; block[i].addr = addr; buf += buf_put4(buf, addr); img_index++; } target_send(sendbuf, buf - sendbuf); // Compute checksums while we wait for reply for (i = 0; i < n; i++) { img_index = block[i].index; addr = block[i].addr; for (j = 0, mycksum = 0; j < image_chunk_size; j += 2) { word = (image[addr + j + 1] << 8) | image[addr + j + 0]; mycksum += word * ((addr + j) & 0xFFFF); } block[i].mycksum = mycksum; } if (target_wait(4 * n, TARGET_RECV_LONG_DELAY) <= 0) main_fatal(E_RECV_TIMEOUT); for (i = 0; i < n; i++) { target_recv(data, 4); cksum = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); mycksum = block[i].mycksum; img_index = block[i].index; if (cksum == mycksum) image_map[img_index] = 'c'; if (arg_checksum_show) { // This is a far from perfect dump of checksums... We don't know // the exact block number of each checksum in a line. if (line != (int) img_index / 4) { flowf(NORMAL, "\n%4d:", img_index); line = img_index / 4; } if (cksum == mycksum) flowf(NORMAL, "%08X ", cksum); else flowf(NORMAL, "%08X/%08X ", cksum, mycksum); } else if (arg_verbose >= VERBOSE) { flowf(VERBOSE, "%c", (image_map[img_index] == 'c' ? 'c' : '.')); } } img_index++; chunks -= n; } time_checksum = (stopwatch_stop(time_checksum) + 50) / 100; flowf(BLABBER, " (%d.%ds)", time_checksum / 10, time_checksum % 10); flowf(NORMAL, " ok\n"); } /****************************************************************************** * Flash Program ******************************************************************************/ int time_program; int programs_recv, programs_send, erasures; int img_index, src_size; uint32 dst; char *src; void flash_erase_machine(void); int flash_operation_wait(int delay); int flash_program_next(void); void flash_program_machine(void) { uint8 cksum, sendbuf[1+4+4]; int i, te, tp, tt; int expected, chunks, total_size, sectors; int image_chunk_size_old = image_chunk_size; char ch; programs_recv = programs_send = erasures = 0; img_index = 0; // Prepare erase erase_list_size = sectors = sector_map_init(); i = image_map_count_used_chunks(); if (arg_skip_erase) erase_list_size = 0; time_compute(device, erase_list_size, i * image_chunk_size, i, &te, &tp, &tt); flowf(BLABBER, "Estimated time (uncompressed) "); if (te + tp > tt) flowf(BLABBER, "(erase + program = total): %ds + %ds = %ds\n", te/1000, tp/1000, te/1000 + tp/1000); else flowf(BLABBER, "transfer: %ds\n", tt/1000); chunks = image_map_count_used_chunks(); flowf(NORMAL, "Program: (%d sectors, %d*%dk=%dk) ", sectors, chunks, image_chunk_size / 1024, chunks * image_chunk_size / 1024); target_trace_enable(1); // Expected total number of acknowledgements expected = erase_list_size + chunks; if (arg_dry_run) { flowf(NORMAL, "(dry-run) "); if (arg_dry_run == 2) image_chunk_size = 0; } if (arg_skip_erase) flowf(NORMAL, "(skip erase) "); // Start erase flash_erase_machine(); if (arg_dry_run == 0 || arg_dry_run == 2) progress_begin(expected); // Start the flash state machine in the target target_putchar(PROTO_FLASH_START); target_putchar(arg_compress ? PROTO_COMPRESS : 0); ch = flash_operation_wait(TARGET_RECV_DELAY); if (ch != PROTO_READY) error_proto(ch, PROTO_READY); if (arg_compress) { compress_init(); total_size = 0; // Worst case "compressed" buffer is 9/8 of original data size. if ((src = malloc(9 * image_chunk_size / 8)) == NULL) main_fatal(E_MEMORY); } time_program = stopwatch_start(); if (flash_program_next() && *arg_erase_override == 0) { //Nothing to program target_putchar(PROTO_FLASH_END); if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0) main_fatal(ch); } else { while (programs_recv + erasures < expected) { total_size += src_size; if (arg_progress == 'x') flowf(NORMAL, "(0x%06X, %d) ", dst, src_size); if (src_size > 0 && (arg_dry_run == 0 || arg_dry_run == 2)) { buf_put1(&sendbuf[0], PROTO_PROGRAM); buf_put4(&sendbuf[1], src_size); buf_put4(&sendbuf[1+4], dst); target_send(sendbuf, 1+4+4); for (i = 0, cksum = 0; i < src_size; i++) cksum += src[i]; cksum = (0x100 - cksum) & 0xFF; // Wait for acknowledgement of command start //while ((ch = flash_operation_wait(4000)) != PROTO_READY) // ; // Make sure that the target FIFO not is full while (programs_send - programs_recv >= target_fifo_size) flash_operation_wait(4000); // Send data bytes and checksum. target_send(src, src_size); target_putchar(cksum); programs_send++; if (arg_verbose >= DEBUG) progress_update_simple('T'); } // We compress and send next block while sending // current block to target if (arg_dry_run == 0 || arg_dry_run == 2) { if (flash_program_next()) { // Wait for remaining acknowledgements flowf(DEBUG, "W%d", expected - (programs_recv + erasures)); while (programs_recv + erasures < expected) flash_operation_wait(4000); target_putchar(PROTO_FLASH_END); if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0) main_fatal(ch); break; } else { // Wait for acknowledgement of data transfer while ((ch = flash_operation_wait(4000)) != PROTO_READY) ; } } else { if (flash_program_next()) break; } } } if (arg_dry_run == 0 || arg_dry_run == 2) progress_end(programs_recv + erasures); flowf(NORMAL, "ok\n"); time_program = stopwatch_stop(time_program); flowf(VERBOSE, "Used time: "); if (arg_compress && chunks) { image_chunk_size = image_chunk_size_old; flowf(VERBOSE, "(compressed to %d%%) ", 100 * total_size / (chunks * image_chunk_size)); } flowf(VERBOSE, "%.1fs ok\n", (double) time_program / 1000); } /****************************************************************************** * Flash Program sub functions ******************************************************************************/ void flash_erase_machine(void) { uint8 sendbuf[1+2+4*256]; // NOTEME: static limit! int i; char ch; if (arg_dry_run) erase_list_size = 0; if (erase_list_size > 0) { buf_put1(&sendbuf[0], PROTO_ERASE); buf_put2(&sendbuf[1], (uint16) erase_list_size); for (i = 0; i < erase_list_size; i++) buf_put4(&sendbuf[1+2+4*i], erase_list[i]); target_send(sendbuf, 1+2+4*erase_list_size); if ((ch = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0) main_fatal(ch); } } // Setup address and size of next block to transfer. Also compress the // block. Return non-zero if this was the last block. Otherwise return zero. int flash_program_next(void) { int oldindex; // Find next used entry in image_map while (img_index < image_map_size && image_map[img_index] != 'x') img_index++; oldindex = img_index; if (img_index < image_map_size) { dst = img_index * image_chunk_size; if (arg_compress) { src_size = compress(src, &image[dst], image_chunk_size); } else { src = &image[dst]; src_size = image_chunk_size; } img_index++; } else { dst = 0xFFFFFFFF; src_size = 0; } return (oldindex >= image_map_size); } int flash_operation_wait(int delay) { int n; char ch; tr(TrMachines, "fow() "); if ((n = target_wait(1, delay)) < 1) main_fatal(E_RECV_TIMEOUT); // Minor optimization to avoid waiting for every char... while (n--) { ch = target_getchar(); if (ch == PROTO_READY) { if (arg_verbose >= DEBUG) progress_update_simple('R'); if (programs_send - programs_recv >= target_fifo_size) progress_update_simple('W'); // Wait target FIFO is full break; } switch (ch) { case PROTO_READY: break; // just return the char case PROTO_PROGRAM: programs_recv++; progress_update_simple('P'); progress_update(programs_recv + erasures); break; // just return the char case PROTO_ERASE: erasures++; progress_update_simple('E'); progress_update(programs_recv + erasures); if (arg_progress == 'x') flowf(NORMAL, "E "); break; // just return the char case PROTO_FLASH_END: progress_update_simple('Z'); break; case PROTO_ERROR_CKSUM: main_fatal(E_SEND_CHECKSUM); case PROTO_ERROR_MEMORY: main_fatal(E_MEMORY); case PROTO_ERROR_VERIFY: main_fatal(E_FLASH_VERIFY); case PROTO_ERROR_FLASH_TIMEOUT: main_fatal(E_FLASH_TIMEOUT); case PROTO_ERROR_FLASH_COMMAND: main_fatal(E_FLASH_COMMAND); case PROTO_ERROR_FLASH_VPP: main_fatal(E_FLASH_VPPRANGE); case PROTO_ERROR_FLASH_LOCKED: main_fatal(E_FLASH_LOCKED); case PROTO_ERROR_FLASH_UNKNOWN: main_fatal(E_FLASH_ERROR); case PROTO_ERROR_INVALID: main_fatal(E_INVALID); case PROTO_ERROR_FIFO_OVERFLOW: main_fatal(E_FIFO_OVERFLOW); case PROTO_ERROR: default: flowf(NORMAL, "flash_operation_wait() got unexpected char '%c' 0x%02X (%d chars waiting)\n", (' ' <= ch && ch < 127 ? ch : '.'), ch, n); // main_fatal(E_PROTO_ERROR); } } return ch; } void target_timers_show(void) { int data[8], i; struct { double erase; double program; double recvonly; double recv; double comm; double setup; double overhead; double dezip; double erase_sector; double program_word; } timer; double tmp, total, resolution = (double) (16 * 32 * 1000 / 13e6); // Use only 14 MHz for D-/E-Sample specific rates (not for e.g. 812.5K). if ((arg_uart_baudrate == 230400) || (arg_uart_baudrate == 460800) || (arg_uart_baudrate == 921600)) resolution = resolution * 13 / 14.746; flowf(NORMAL, "Target Timers:\n" " (erase + program + recvonly + recv + comm + setup + overhead + dezip)\n"); if (arg_dry_run) for (i = 0; i < 8; i++) data[i] = 0; else { target_putchar(PROTO_TIMERS); if (target_wait(sizeof(data), TARGET_RECV_DELAY) <= 0) main_fatal(E_RECV_TIMEOUT); target_recv(&data, sizeof(data)); } // Convert all timers to milliseconds timer.erase = resolution * data[0]; timer.program = resolution * data[1]; timer.recvonly = resolution * data[2]; timer.recv = resolution * data[3]; timer.comm = resolution * data[4]; timer.setup = resolution * data[5]; timer.overhead = resolution * data[6]; timer.dezip = resolution * data[7]; // Because we do erase-while-transfer in the target the reported erase // time has some inherent tolerance, especially at low baudrates. It // might make sense to adjust the sector erase time by half the chunk // transfer time, although this is just another approximation!? // total = timer.erase + timer.program + timer.recvonly + timer.recv + timer.comm + timer.setup; flowf(NORMAL, "%8.0f + %7.0f + %8.0f + %6.0f + %5.0f + %5.0f + %8.0f + %5.0f\n", timer.erase, timer.program, timer.recvonly, timer.recv, timer.comm, timer.setup, timer.overhead, timer.dezip); flowf(DEBUG, "resolution = %f, %d, %d, %d, %d, %d, %d, %d, %d\n", resolution, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); if (arg_timers_extended_show) { int chunks, size_total, not_zero = 1; flowf(NORMAL, "Target Timers Extended:\n"); if (erase_list_size == 0 || arg_dry_run) flowf(NORMAL, " Erase time = 0.0ms/sector\n"); else { timer.erase_sector = timer.erase / erase_list_size / 1000; flowf(NORMAL, " Erase time = %.1fs / %d sectors = %.0fms/sector\n", timer.erase / 1000, erase_list_size, timer.erase_sector * 1000); } chunks = image_map_count_used_chunks(); size_total = chunks * image_chunk_size; if (size_total == 0 || arg_dry_run) { size_total = 1; not_zero = 0; flowf(NORMAL, " Program time = 0.0us/word = 0ms/MB\n"); } else { timer.program_word = timer.program / 1000 / (size_total / 2); flowf(NORMAL, " Program time = %.1fs / %dkwords = %.2fus/word = %.0fms/MB\n", timer.program / 1000, size_total / 1024 / 2, timer.program_word * 1000000, timer.program_word * 1000 * 512 * 1024); } flowf(NORMAL, " Receive-only time = %.1fs = %.0fms/MB\n", timer.recvonly / 1000, not_zero * timer.recvonly * 1024 * 1024 / size_total); flowf(NORMAL, " Overhead time = %.1fs = %.0fms/MB\n", timer.overhead / 1000, not_zero * timer.overhead * 1024 * 1024 / size_total); flowf(NORMAL, " Setup time = %.1fs = %.0fms/MB\n", timer.setup / 1000, not_zero * timer.setup * 1024 * 1024 / size_total); total = timer.erase + timer.program + timer.recvonly + timer.overhead + timer.setup; flowf(NORMAL, "Total time: (erase + prog + recvonly + overhead + setup) = %.1fs\n", total / 1000); flowf(NORMAL, " Receive time = %.1fs = %.0fms/MB\n", timer.recv / 1000, timer.recv * 1024 * 1024 / size_total); flowf(NORMAL, " Communication time = %.1fs = %.0fms/MB\n", timer.comm / 1000, timer.comm * 1024 * 1024 / size_total); flowf(NORMAL, " Dezip time = %.1fs = %.0fms/MB\n", timer.dezip / 1000, timer.dezip * 1024 * 1024 / size_total); // Now compute the overall performance. Note that the theoretical // limit compuation is somewhat flawed in that it assumes 64kB // sector sizes. tmp = (double) not_zero * total / 1000 * 1024 * 1024 / size_total; flowf(NORMAL, " Performance = %.0fs/MB\n", tmp); #if 0 flowf(BLABBER, " (%.1f * min possible, %.1f * theoretical limit)", time_program / (timer.program + timer.erase), tmp / (16 * timer.erase_sector + 512 * 1024 * timer.program_word)); flowf(NORMAL, "\n"); #endif } } /****************************************************************************** * Flash Read ******************************************************************************/ int time_read; void flash_read_machine(void) { int i; unsigned char sendbuf[1+4+4]; int size, read_size, done_size = 0; int read_size_max = image_chunk_size; uint32 addr, index = 0; uint8 cksum, mycksum; flowf(NORMAL, "Reading Flash: (%dkB) ", read_total_size / 1024); target_trace_enable(0); //read_size_max = 256; time_read = stopwatch_start(); progress_begin(read_total_size / read_size_max); while (read_list[index].size > 0) { // Find next range to read size = read_list[index].size; addr = read_list[index].addr; index++; while (size > 0) { read_size = (size > read_size_max ? read_size_max : size); // Read address interval is [MIN..MAX[ // If odd MAX address was specified round up to next even if ((read_size % 2 == 1) && (read_size < read_size_max)) read_size++; if (arg_progress == 'x') flowf(DEBUG, "(0x%06X, %d) ", addr, read_size); if (!arg_dry_run) { buf_put1(&sendbuf[0], PROTO_READ); buf_put4(&sendbuf[1] , read_size); buf_put4(&sendbuf[1+4], addr); target_send(sendbuf, 1+4+4); if (target_wait(read_size, TARGET_RECV_LONG_DELAY) <= 0) main_fatal(E_RECV_TIMEOUT); // Note that we wrap/mirror memory each 'image_size' bytes target_recv(&image[addr & (image_size - 1)], read_size); for (i = 0, mycksum = 0; i < read_size; i++) mycksum ^= image[(addr + i) & (image_size - 1)]; if (target_wait(1, TARGET_RECV_DELAY) <= 0) main_fatal(E_RECV_TIMEOUT); cksum = target_getchar(); if (cksum != mycksum) main_fatal(E_RECV_CHECKSUM); } done_size += read_size; size -= read_size; addr += read_size; progress_update(done_size / read_size_max); progress_update_simple('0' + read_size / 1024); } } progress_end(done_size / read_size_max); flowf(NORMAL, " ok\n"); time_read = stopwatch_stop(time_read); flowf(VERBOSE, "Used time: %ds ok\n", time_read); } /****************************************************************************** * Flash Reset ******************************************************************************/ void target_reset_machine(void) { int error; flowf(VERBOSE, "Resetting target: "); if (arg_dry_run) { flowf(VERBOSE, "(dry-run) "); } else { target_putchar(PROTO_RESET); target_expect_char(PROTO_READY, TARGET_RECV_DELAY); } flowf(VERBOSE, "ok\n"); } /****************************************************************************** * Show Functions (dump internal data structures) ******************************************************************************/ void image_map_show(void) { uint32 addr; int i; flowf(ALWAYS, "image map of %d * %dkB chunks (x = used, s = skip, c = checksum ok):", image_size_in_chunks, image_chunk_size / 1024); // For each chunk of the image usage map... for (i = 0, addr = 0; i < image_size_in_chunks; i++) { if ((i % 64) == 0) { flowf(ALWAYS, "\n%4dkB: ", (int) addr >> 10); } putchar(image_map[i] != 0 ? image_map[i] : '.'); addr += image_chunk_size; } putchar('\n'); } void sector_map_show(void) { struct sector_s *sectors = device->memmap->sectors; int i; char n; uint32 addr = 0; flowf(ALWAYS, "sector map (x = used, s = skip, X = force erase):"); // For each sector of the device definition... for (i = 0; i < device->memmap->size; i++) { if ((addr & 0xFFFFF) == 0) { flowf(ALWAYS, "\n%2dMB: ", (int) addr >> 20); } n = (sector_map[i] ? sector_map[i] : '.'); putchar(n); addr += sectors[i].size; } putchar('\n'); } /****************************************************************************** * Utility Functions ******************************************************************************/ int image_is_within(int start, int end) { return !(start < 0 || image_size <= start || end < 0 || image_size < end || end < start); } // Set the image usage map in the range [start..end[ as used int image_map_set(int start, int end) { if (!image_is_within(start, end)) return -1; do { image_map[start / image_chunk_size] = 'x'; start += image_chunk_size; } while (start < end); return 0; } int target_type_set(uint16 code) { // If there is an override from the command-line, use that if (arg_target_type != 0) code = arg_target_type; switch (code) { case 'h': // Hercules case 'u': // Ulysses case '3': // Chipset 3 case CHIP_ID_ULYSSES_0: case CHIP_ID_ULYSSES_A: case CHIP_ID_HERCULES_A: case CHIP_ID_HERCULES_B: target_type = 3; break; case 'c': // Calypso case '4': // Chipset 4 // case 's': // Samson case CHIP_ID_CALYPSO_A: case CHIP_ID_CALYPSO_B: case CHIP_ID_CALYPSO_C: target_type = 4; break; case 'l': // Calypso Lite case CHIP_ID_CALYPSO_L: target_type = 5; break; case 'p': // Calypso Plus case CHIP_ID_CALYPSO_PLUS: case CHIP_ID_CALYPSO_PLUS_A: target_type = 6; break; default: target_type = 0; } return target_type; } int image_map_count_used_chunks(void) { int used, i; // For each image chunk for (i = 0, used = 0; i < image_size_in_chunks; i++) { if (image_map[i] == 'x') used++; } return used; } // When the sector_map have been changed, we have to update the image_map // such that we don't attempt to program within sectors that are not going // to be programmed anyway (due to the erase override). We also have to // program chunks contained in sectors that *are* going to be erased, even // though the chunks have been check-summed ok. int image_map_update(void) { struct sector_s *sectors = device->memmap->sectors; int changed, chunks, i, j; int map_index; map_index = 0; changed = 0; // For each sector of the device definition... for (i = 0; i < device->memmap->size; i++) { chunks = sectors[i].size / image_chunk_size; // For each image--map-chunk contained in current sector... for (j = 0; j < chunks; j++) { if (!(sector_map[i] == 'x' || sector_map[i] == 'X') && image_map[map_index + j] == 'x') { image_map[map_index + j] = 's'; // skip changed++; } else if ((sector_map[i] == 'x' || sector_map[i] == 'X') && image_map[map_index + j] == 'c') { image_map[map_index + j] = 'x'; // include! changed++; } } map_index += chunks; } return changed; } int sector_map_init(void) { struct sector_s *sectors = device->memmap->sectors; int map_index; int used_list_index; int used, chunks, i, j; sector_map_size = SECTOR_MAP_SIZE_MAX; memset(sector_map, 0, sector_map_size); // Generate the sector_map from the image_map map_index = 0; // For each sector of the device definition... for (i = 0; i < device->memmap->size; i++) { chunks = sectors[i].size / image_chunk_size; // For each image-usage-map-chunk contained in current sector... for (j = 0, used = 0; j < chunks; j++) if (image_map[map_index + j] == 'x') used++; sector_map[i] = (used ? 'x' : 0); map_index += chunks; } parse_arg_erase_override(arg_erase_override); // Generate the erase_list // For each sector of the device definition... used_list_index = 0; for (i = 0; i < device->memmap->size; i++) { if (sector_map[i] == 'x' || sector_map[i] == 'X') erase_list[used_list_index++] = sectors[i].addr; } if (arg_sector_map_show) sector_map_show(); if (arg_sector_list_show) { flowf(ALWAYS, "sector used list: "); for (i = 0; i < used_list_index; i++) flowf(ALWAYS, "0x%06X ", erase_list[i]); putchar('\n'); } return used_list_index; } int parse_range(char *p, char **p_end, int *n1, int *n2) { char *my_end; int read_offset_calp = (*arg_read != 0 && target[target_type].type == 'P'); *n2 = 0; *n1 = strtol(p, &my_end, 0); if (p == my_end) return 0; // error: no chars converted if (*my_end == 'k' || *my_end == 'K') { *n1 <<= 10; if (read_offset_calp) *n1 += CALP_OFFSET; my_end++; } else if (*my_end == 'M') { *n1 <<= 20; if (read_offset_calp) *n1 += CALP_OFFSET; my_end++; } *p_end = my_end; if (my_end[0] != '.' || my_end[1] != '.') return 1; p = my_end + 2; *n2 = strtol(p, &my_end, 0); if (p == my_end) return 0; // error: no chars converted if (*my_end == 'k' || *my_end == 'K') { *n2 <<= 10; if (read_offset_calp) *n2 += CALP_OFFSET; my_end++; } else if (*my_end == 'M') { *n2 <<= 20; if (read_offset_calp) *n2 += CALP_OFFSET; my_end++; } *p_end = my_end; return 2; } // Parse and decode the erase override command line option string. The // sector_map is updated accordingly. void parse_arg_erase_override(char *p) { struct sector_s *sectors = device->memmap->sectors; int sector_bottom, sector_top; int changed, i; tr(TrBegin| TrArgParser, "erase_override:\n"); while (*p) { char *p_end; int num, sign, n1 = 0, n2 = 0; if (*p != '-' && *p != '+') main_error(E_ERASE_SPEC); sign = (*p == '-' ? -1 : +1); p++; if (*p == '*') { sign = sign * 2; p++; } else { num = parse_range(p, &p_end, &n1, &n2); if (num == 0) main_error(E_ERASE_SPEC); p = p_end; } switch (sign) { case -1: case +1: if (num == 1) { // Support for absolute addresses on Calypso Plus if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET; if (n1 > sector_map_size) { // For all sectors... for (i = 0; i < device->memmap->size; i++) { sector_bottom = sectors[i].addr; sector_top = sector_bottom + sectors[i].size - 1; if (n1 >= sector_bottom && n1 < sector_top) { sector_map[i] = (sign > 0 ? 'X' : 's'); break; } } } else sector_map[n1] = (sign > 0 ? 'X' : 's'); tr(TrArgParser, "%c%d\n", sign > 0 ? '+' : '-', n1); } else { // Support for absolute addresses on Calypso Plus if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) { n1 -= CALP_OFFSET; n2 -= CALP_OFFSET; } if (n1 > sector_map_size || n2 > sector_map_size) { // n1 and n2 must respresent an address range if (n1 >= n2) main_error(E_ERASE_SPEC); // For all sectors... for (i = 0; i < device->memmap->size; i++) { sector_bottom = sectors[i].addr; sector_top = sector_bottom + sectors[i].size - 1; // If either sector bottom or top is contained in // [n1..n2[ if ((n1 <= sector_bottom && sector_bottom < n2) || (n1 <= sector_top && sector_top < n2)) { sector_map[i] = (sign > 0 ? 'X' : 's'); } } } else { // n1 and n2 must respresent a sector range for (i = n1; i < n2; i++) sector_map[i] = (sign > 0 ? 'X' : 's'); } tr(TrArgParser, "%c%d..%d\n", sign > 0 ? '+' : '-', n1, n2); } break; case -2: case +2: // Fill whole sector_map... for (i = 0; i < device->memmap->size; i++) sector_map[i] = (sign > 0 ? 'X' : 's'); tr(TrArgParser, "%c*\n", sign > 0 ? '+' : '-'); break; } // skip optional comma if (*p == ',') p++; } tr(TrEnd| TrArgParser, ""); changed = image_map_update(); // If image map was changed, we trace it again. if (changed && arg_image_map_show) image_map_show(); } void parse_arg_read(char *p) { read_total_size = 0; read_list_size = 0; tr(TrArgParser, "parse_arg_read() {\n"); while (*p) { char *p_end; int num, n1, n2; if (*p == '*') { n1 = 0; n2 = 0x1000000; // sufficiently large (16MB) p++; } else { num = parse_range(p, &p_end, &n1, &n2); tr(TrArgParser, "parse_range('%s', ...)\n" " { #%d, p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n", p, read_list_size, p_end, n1, n2, num); if (num != 2 || n1 > n2) main_error(E_ADDR_RANGE); p = p_end; } read_list[read_list_size].addr = n1; read_list[read_list_size].size = n2 - n1; read_total_size += n2 - n1; read_list_size++; if (read_list_size >= READ_LIST_SIZE_MAX) main_error(E_ARG_TOOMANY); if (*p == 0) break; if (*p == ',') p++; else main_error(E_READ_SPEC); } // Terminate the read_list with zeroes. read_list[read_list_size].addr = 0; read_list[read_list_size].size = 0; tr(TrArgParser, "}\n"); } void parse_arg_write(char *p) { tr(TrArgParser, "parse_arg_write() {\n"); while (*p) { char bytes[1024]; char *p_end; int num, n1, n2; int index, value, size, i; num = parse_range(p, &p_end, &n1, &n2); tr(TrArgParser, "parse_range('%s', ...)\n" " { p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n", p, p_end, n1, n2, num); if (num < 1 || num > 2) main_error(E_ADDR_RANGE); p = p_end; if (*p++ != '=') main_error(E_WRITE_SPEC); tr(TrArgParser, " { "); if (*p == 0) main_error(E_WRITE_SPEC); index = 0; while (*p) { if (*p == '\"') { // Collect text string p++; tr(TrCont|TrArgParser, "'"); while (*p) { if (*p == '\"') break; if (p[0] == '\\' && p[1] == '\"') p++; // skip leading backslash if (p[0] == '\\' && p[1] == '\\') p++; // skip leading backslash tr(TrCont|TrArgParser, "%c", *p); bytes[index] = *p++; if (index++ >= sizeof(bytes)) main_error(E_WRITE_SPEC); } if (*p++ != '\"') main_error(E_WRITE_SPEC); tr(TrCont|TrArgParser, "' "); } else { // Collect byte string value = strtol(p, &p_end, 0); if (p == p_end) main_error(E_WRITE_SPEC); if (value < 0 || 255 < value) main_error(E_WRITE_SPEC); bytes[index] = value; if (index++ >= sizeof(bytes)) main_error(E_WRITE_SPEC); p = p_end; tr(TrCont|TrArgParser, "0x%x ", value); } if (*p == ':' || *p == 0) break; if (*p == ',') p++; } size = index; tr(TrArgParser, "} %d\n", size); if (num == 1) { // Support for absolute addresses on Calypso Plus if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET; n2 = n1 + size; } else if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) { n1 -= CALP_OFFSET; n2 -= CALP_OFFSET; } if (image_map_set(n1, n2) < 0) main_error(E_ADDR_RANGE); index = 0; for (i = n1; i < n2; i++) { image[i] = bytes[index++]; if (index >= size) index = 0; } if (*p == ':') p++; } tr(TrArgParser, "}\n"); }