From 40f1e00090e429f87aa5bf1a3dfb887f707bb23f Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Thu, 13 Jun 2024 17:10:05 +0300 Subject: [PATCH 01/46] add 290 support --- sonixflasher.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 422f06c..fab8635 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -12,6 +12,7 @@ #define RESPONSE_LEN 64 #define MAX_FIRMWARE_SN32F260 (30 * 1024) //30k #define MAX_FIRMWARE_SN32F240 (64 * 1024) //64k +#define MAX_FIRMWARE_SN32F290 (256 * 1024) //256k #define QMK_OFFSET_DEFAULT 0x200 #define CMD_BASE 0x55AA0000 @@ -23,6 +24,7 @@ #define SN268_PID 0x7010 #define SN248B_PID 0x7040 #define SN248_PID 0x7900 +#define SN299_PID 0x7140 #define EVISION_VID 0x320F #define APPLE_VID 0x05ac @@ -470,7 +472,7 @@ int main(int argc, char* argv[]) printf("Device opened successfully...\n"); // Check VID/PID - if(vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN268_PID)) + if(vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN268_PID && pid !=SN299_PID)) { if(vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); if(vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); @@ -492,7 +494,9 @@ int main(int argc, char* argv[]) case SN248B_PID: MAX_FIRMWARE = MAX_FIRMWARE_SN32F240; break; - + case SN299_PID: + MAX_FIRMWARE = MAX_FIRMWARE_SN32F290; + break; case SN268_PID: MAX_FIRMWARE = MAX_FIRMWARE_SN32F260; From dfd004f3461514c5d5bbf6d5730237f3943f6def Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 23 Aug 2024 13:56:17 +0300 Subject: [PATCH 02/46] add 240C support --- sonixflasher.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index fab8635..492f74a 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -12,6 +12,7 @@ #define RESPONSE_LEN 64 #define MAX_FIRMWARE_SN32F260 (30 * 1024) //30k #define MAX_FIRMWARE_SN32F240 (64 * 1024) //64k +#define MAX_FIRMWARE_SN32F240C (128 * 1024) //128k #define MAX_FIRMWARE_SN32F290 (256 * 1024) //256k #define QMK_OFFSET_DEFAULT 0x200 @@ -23,6 +24,7 @@ #define SONIX_VID 0x0c45 #define SN268_PID 0x7010 #define SN248B_PID 0x7040 +#define SN248C_PID 0x7145 #define SN248_PID 0x7900 #define SN299_PID 0x7140 @@ -472,7 +474,7 @@ int main(int argc, char* argv[]) printf("Device opened successfully...\n"); // Check VID/PID - if(vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN268_PID && pid !=SN299_PID)) + if(vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid!= SN248C_PID && pid != SN268_PID && pid !=SN299_PID)) { if(vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); if(vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); @@ -494,6 +496,8 @@ int main(int argc, char* argv[]) case SN248B_PID: MAX_FIRMWARE = MAX_FIRMWARE_SN32F240; break; + case SN248C_PID: + MAX_FIRMWARE = MAX_FIRMWARE_SN32F240C; case SN299_PID: MAX_FIRMWARE = MAX_FIRMWARE_SN32F290; break; From 9206e7e602537854a7ed258bc17c5d26c0fbd214 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 23 Aug 2024 14:26:48 +0300 Subject: [PATCH 03/46] abstract buffer size --- sonixflasher.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 492f74a..851cae4 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -9,7 +9,8 @@ #include -#define RESPONSE_LEN 64 +#define REPORT_SIZE 64 +#define REPORT_LENGTH (REPORT_SIZE + 1) #define MAX_FIRMWARE_SN32F260 (30 * 1024) //30k #define MAX_FIRMWARE_SN32F240 (64 * 1024) //64k #define MAX_FIRMWARE_SN32F240C (128 * 1024) //128k @@ -98,9 +99,9 @@ void write_buffer_32(unsigned char *data, uint32_t cmd) bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { - if(length > 65) + if(length > REPORT_LENGTH) { - fprintf(stderr, "ERROR: Report cant be more than 65 bytes!!\n"); + fprintf(stderr, "ERROR: Report can't be more than %d bytes!! (Attempted: %zu bytes)\n", REPORT_SIZE, length); return false; } @@ -117,12 +118,12 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) int hid_get_feature(hid_device *dev, unsigned char *data) { - return hid_get_feature_report(dev, data, RESPONSE_LEN + 1); + return hid_get_feature_report(dev, data, REPORT_LENGTH); } bool send_magic_command(hid_device *dev, const uint32_t *command) { - unsigned char buf[65]; + unsigned char buf[REPORT_LENGTH]; clear_buffer(buf, sizeof(buf)); write_buffer_32(buf,command[0]); @@ -156,7 +157,7 @@ bool reboot_to_bootloader(hid_device *dev, char *oem_option) bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip_size_check, bool oem_reboot, char *oem_option) { - unsigned char buf[65]; + unsigned char buf[REPORT_LENGTH]; int read_bytes; uint32_t resp = 0; uint32_t status = 0; @@ -187,10 +188,10 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Initializing flash...\n"); - clear_buffer(buf, 65); + clear_buffer(buf, REPORT_LENGTH); write_buffer_32(buf, CMD_INIT); uint8_t attempt_no = 1; - while(!hid_set_feature(dev, buf, 65) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. + while(!hid_set_feature(dev, buf, REPORT_LENGTH) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { printf("Flash failed to init, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); sleep(3); @@ -198,11 +199,11 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip } if(attempt_no > MAX_ATTEMPTS) return false; - clear_buffer(buf, 65); + clear_buffer(buf, REPORT_LENGTH); read_bytes = hid_get_feature(dev, buf); - if(read_bytes != RESPONSE_LEN + 1) + if(read_bytes != REPORT_LENGTH) { - fprintf(stderr, "ERROR: Failed to initialize: got response of length %d, expected %d.\n", read_bytes, RESPONSE_LEN); + fprintf(stderr, "ERROR: Failed to initialize: got response of length %d, expected %d.\n", read_bytes, REPORT_SIZE); return false; } bool reboot_fail = !read_response_32(buf, 0, &resp); @@ -220,13 +221,13 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Preparing for flash...\n"); - clear_buffer(buf, 65); + clear_buffer(buf, REPORT_LENGTH); write_buffer_32(buf, CMD_PREPARE); write_buffer_32(buf+5, (uint32_t)offset); - write_buffer_32(buf+9, (uint32_t)(fw_size/64)); - if(!hid_set_feature(dev, buf, 65)) return false; + write_buffer_32(buf+9, (uint32_t)(fw_size/REPORT_SIZE)); + if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; - clear_buffer(buf, 65); + clear_buffer(buf, REPORT_LENGTH); read_bytes = hid_get_feature(dev, buf); if(!read_response_32(buf, CMD_PREPARE, &resp)) // Read cmd { @@ -244,20 +245,20 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Flashing device, please wait...\n"); size_t bytes_read = 0; - clear_buffer(buf, 65); - while ((bytes_read = fread(buf+1, 1, 64, firmware)) > 0) + clear_buffer(buf, REPORT_LENGTH); + while ((bytes_read = fread(buf+1, 1, REPORT_SIZE, firmware)) > 0) { - if(!hid_set_feature(dev, buf, 65)) return false; - clear_buffer(buf, 65); + if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; + clear_buffer(buf, REPORT_LENGTH); } printf("Flashing done. Rebooting.\n"); // // 4) reboot - clear_buffer(buf, 65); + clear_buffer(buf, REPORT_LENGTH); write_buffer_32(buf, CMD_REBOOT); - if(!hid_set_feature(dev, buf, 65)) return false; + if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; return true; @@ -519,7 +520,7 @@ int main(int argc, char* argv[]) } } - while (file_size % 64 != 0) file_size++; // Add padded zereos (if any) to file_size, since we are using a fixed 64 + 1 buffer, we need to take in consideration when the file doesnt fill the buffer. + while (file_size % REPORT_SIZE != 0) file_size++; // Add padded zereos (if any) to file_size, since we are using a fixed 64 + 1 buffer, we need to take in consideration when the file doesnt fill the buffer. if( ((flash_jumploader && sanity_check_jumploader_firmware(file_size)) || (!flash_jumploader && sanity_check_firmware(file_size, offset))) && From 8c3fd324d696f45c7f57278e5df11ecf14d02228 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 23 Aug 2024 17:47:43 +0300 Subject: [PATCH 04/46] abstract hid reports size from actual payload --- sonixflasher.c | 63 +++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 851cae4..2ea07d7 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -17,10 +17,10 @@ #define MAX_FIRMWARE_SN32F290 (256 * 1024) //256k #define QMK_OFFSET_DEFAULT 0x200 -#define CMD_BASE 0x55AA0000 -#define CMD_INIT (CMD_BASE + 0x100) -#define CMD_PREPARE (CMD_BASE + 0x500) -#define CMD_REBOOT (CMD_BASE + 0x700) +#define CMD_BASE 0x55AA00 +#define CMD_INIT (CMD_BASE + 0x1) +#define CMD_PREPARE (CMD_BASE + 0x5) +#define CMD_REBOOT (CMD_BASE + 0x7) #define SONIX_VID 0x0c45 #define SN268_PID 0x7010 @@ -99,13 +99,18 @@ void write_buffer_32(unsigned char *data, uint32_t cmd) bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { - if(length > REPORT_LENGTH) + if(length > REPORT_SIZE) { fprintf(stderr, "ERROR: Report can't be more than %d bytes!! (Attempted: %zu bytes)\n", REPORT_SIZE, length); return false; } + unsigned char buf[REPORT_LENGTH]; + + // Set the Report ID byte (first byte of data) + buf[0] = 0x0; + memcpy(buf + 1, data, length); - int res = hid_send_feature_report(dev, data, length); + int res = hid_send_feature_report(dev, data, length + 1); if(res < 0) { @@ -118,12 +123,22 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) int hid_get_feature(hid_device *dev, unsigned char *data) { - return hid_get_feature_report(dev, data, REPORT_LENGTH); + int res = hid_get_feature_report(dev, data, REPORT_LENGTH); + // If the read was successful and data length is greater than 0 + if (res > 0) { + // Shift the data buffer to remove the first byte + memmove(data, data + 1, res - 1); + // Return the length of the data excluding the removed first byte + return res - 1; + } + + // Return 0 if the read was not successful or the buffer length is not sufficient + return 0; } bool send_magic_command(hid_device *dev, const uint32_t *command) { - unsigned char buf[REPORT_LENGTH]; + unsigned char buf[REPORT_SIZE]; clear_buffer(buf, sizeof(buf)); write_buffer_32(buf,command[0]); @@ -157,7 +172,7 @@ bool reboot_to_bootloader(hid_device *dev, char *oem_option) bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip_size_check, bool oem_reboot, char *oem_option) { - unsigned char buf[REPORT_LENGTH]; + unsigned char buf[REPORT_SIZE]; int read_bytes; uint32_t resp = 0; uint32_t status = 0; @@ -188,10 +203,10 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Initializing flash...\n"); - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_INIT); uint8_t attempt_no = 1; - while(!hid_set_feature(dev, buf, REPORT_LENGTH) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. + while(!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { printf("Flash failed to init, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); sleep(3); @@ -199,9 +214,9 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip } if(attempt_no > MAX_ATTEMPTS) return false; - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); read_bytes = hid_get_feature(dev, buf); - if(read_bytes != REPORT_LENGTH) + if(read_bytes != REPORT_SIZE) { fprintf(stderr, "ERROR: Failed to initialize: got response of length %d, expected %d.\n", read_bytes, REPORT_SIZE); return false; @@ -221,20 +236,20 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Preparing for flash...\n"); - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_PREPARE); - write_buffer_32(buf+5, (uint32_t)offset); - write_buffer_32(buf+9, (uint32_t)(fw_size/REPORT_SIZE)); - if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; + write_buffer_32(buf+4, (uint32_t)offset); + write_buffer_32(buf+8, (uint32_t)(fw_size/REPORT_SIZE)); + if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); read_bytes = hid_get_feature(dev, buf); if(!read_response_32(buf, CMD_PREPARE, &resp)) // Read cmd { fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_PREPARE); return false; } - if(!read_response_32(buf + 5, EXPECTED_STATUS, &status))// Read status + if(!read_response_32(buf + 4, EXPECTED_STATUS, &status))// Read status { fprintf(stderr, "ERROR: Failed to initialize: response status is 0x%08x, expected 0x%08x.\n", status, EXPECTED_STATUS); return false; @@ -245,20 +260,20 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Flashing device, please wait...\n"); size_t bytes_read = 0; - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); while ((bytes_read = fread(buf+1, 1, REPORT_SIZE, firmware)) > 0) { - if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; - clear_buffer(buf, REPORT_LENGTH); + if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + clear_buffer(buf, REPORT_SIZE); } printf("Flashing done. Rebooting.\n"); // // 4) reboot - clear_buffer(buf, REPORT_LENGTH); + clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_REBOOT); - if(!hid_set_feature(dev, buf, REPORT_LENGTH)) return false; + if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; return true; From 523b35ef01da0b8695df45ee9e778133b88d7e30 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 23 Aug 2024 17:55:59 +0300 Subject: [PATCH 05/46] rename commands to properly reflect ISP protocol --- sonixflasher.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 2ea07d7..a48f23d 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -18,9 +18,11 @@ #define QMK_OFFSET_DEFAULT 0x200 #define CMD_BASE 0x55AA00 -#define CMD_INIT (CMD_BASE + 0x1) -#define CMD_PREPARE (CMD_BASE + 0x5) -#define CMD_REBOOT (CMD_BASE + 0x7) +#define CMD_GET_FW_VERSION (CMD_BASE + 0x1) +#define CMD_ENABLE_PROGRAM (CMD_BASE + 0x5) +#define CMD_RETURN_USER_MODE (CMD_BASE + 0x7) + +#define CMD_OK 0xFAFAFAFA #define SONIX_VID 0x0c45 #define SN268_PID 0x7010 @@ -32,8 +34,6 @@ #define EVISION_VID 0x320F #define APPLE_VID 0x05ac -#define EXPECTED_STATUS 0xFAFAFAFA - #define MAX_ATTEMPTS 5 #define PROJECT_NAME "sonixflasher" @@ -204,7 +204,7 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Initializing flash...\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_INIT); + write_buffer_32(buf, CMD_GET_FW_VERSION); uint8_t attempt_no = 1; while(!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { @@ -222,14 +222,14 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip return false; } bool reboot_fail = !read_response_32(buf, 0, &resp); - bool init_fail = !read_response_32(buf, CMD_INIT, &resp); + bool init_fail = !read_response_32(buf, CMD_GET_FW_VERSION, &resp); if(init_fail) { if(oem_reboot && reboot_fail) { fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, 0); } - else fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_INIT); + else fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_GET_FW_VERSION); return false; } // // 2) Prepare for flash @@ -237,21 +237,21 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Preparing for flash...\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_PREPARE); + write_buffer_32(buf, CMD_ENABLE_PROGRAM); write_buffer_32(buf+4, (uint32_t)offset); write_buffer_32(buf+8, (uint32_t)(fw_size/REPORT_SIZE)); if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); read_bytes = hid_get_feature(dev, buf); - if(!read_response_32(buf, CMD_PREPARE, &resp)) // Read cmd + if(!read_response_32(buf, CMD_ENABLE_PROGRAM, &resp)) // Read cmd { - fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_PREPARE); + fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_ENABLE_PROGRAM); return false; } - if(!read_response_32(buf + 4, EXPECTED_STATUS, &status))// Read status + if(!read_response_32(buf + 4, CMD_OK, &status))// Read status { - fprintf(stderr, "ERROR: Failed to initialize: response status is 0x%08x, expected 0x%08x.\n", status, EXPECTED_STATUS); + fprintf(stderr, "ERROR: Failed to initialize: response status is 0x%08x, expected 0x%08x.\n", status, CMD_OK); return false; } @@ -272,7 +272,7 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip // // 4) reboot clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_REBOOT); + write_buffer_32(buf, CMD_RETURN_USER_MODE); if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; return true; From 7dbb528a8f2844c2f69301c879037a20b1e0d236 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 24 Aug 2024 21:48:50 +0300 Subject: [PATCH 06/46] v2.0.1 abstract functions from the flash function further compliment the api, introduce support for new chips actually validate the flash status new options fix various bugs --- sonixflasher.c | 697 ++++++++++++++++++++++++++++--------------------- 1 file changed, 406 insertions(+), 291 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index a48f23d..9df05b9 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -11,25 +11,46 @@ #define REPORT_SIZE 64 #define REPORT_LENGTH (REPORT_SIZE + 1) -#define MAX_FIRMWARE_SN32F260 (30 * 1024) //30k -#define MAX_FIRMWARE_SN32F240 (64 * 1024) //64k -#define MAX_FIRMWARE_SN32F240C (128 * 1024) //128k -#define MAX_FIRMWARE_SN32F290 (256 * 1024) //256k +#define USER_ROM_SIZE_SN32F260 30 // in KB +#define USER_ROM_SIZE_SN32F240 64 // in KB +#define USER_ROM_SIZE_SN32F240B 64 // in KB +#define USER_ROM_SIZE_SN32F240C 128 // in KB +#define USER_ROM_SIZE_SN32F290 256 // in KB +#define USER_ROM_SIZE_KB(x) ((x) * 1024) + #define QMK_OFFSET_DEFAULT 0x200 #define CMD_BASE 0x55AA00 #define CMD_GET_FW_VERSION (CMD_BASE + 0x1) +#define CMD_COMPARE_ISP_PASSWORD (CMD_BASE + 0x2) +#define CMD_SET_ENCRYPTION_ALGO (CMD_BASE + 0x3) +#define CMD_ENABLE_ERASE (CMD_BASE + 0x4) #define CMD_ENABLE_PROGRAM (CMD_BASE + 0x5) +#define CMD_GET_CHECKSUM (CMD_BASE + 0x6) #define CMD_RETURN_USER_MODE (CMD_BASE + 0x7) +#define CMD_SET_CS (CMD_BASE + 0x8) +#define CMD_GET_CS (CMD_BASE + 0x9) #define CMD_OK 0xFAFAFAFA +#define VALID_FW 0xAAAA5555 +#define ISP_PASSWORD 0xFEFF + +#define SN240 1 +#define SN260 2 +#define SN240B 3 +#define SN290 5 +#define SN240C 6 + +#define CS1 0x5A5A +#define CS2 0xA5A5 +#define CS3 0x55AA -#define SONIX_VID 0x0c45 -#define SN268_PID 0x7010 +#define SONIX_VID 0x0c45 +#define SN268_PID 0x7010 #define SN248B_PID 0x7040 #define SN248C_PID 0x7145 -#define SN248_PID 0x7900 -#define SN299_PID 0x7140 +#define SN248_PID 0x7900 +#define SN299_PID 0x7140 #define EVISION_VID 0x320F #define APPLE_VID 0x05ac @@ -37,288 +58,429 @@ #define MAX_ATTEMPTS 5 #define PROJECT_NAME "sonixflasher" -#define PROJECT_VER "1.1.0" +#define PROJECT_VER "2.0.1" -long MAX_FIRMWARE = MAX_FIRMWARE_SN32F260; +uint16_t CS0 = 0; +uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; +long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); +bool flash_jumploader = false; +bool debug = false; +int chip; +uint16_t cs_level; -static void print_usage(char *m_name) -{ +static void print_usage(char *m_name) { fprintf(stderr, - "Usage: \n" - " %s [options]\n" - "where is one of:\n" - " --vidpid -v Set VID for device to flash\n" - " --offset -o Set flashing offset (default: 0)\n" - " --file -f Binary of the firmware to flash (*.bin extension) \n" - " --jumploader -j Define if we are flashing a jumploader \n" - " --reboot -r Request bootloader reboot in OEM firmware (options: evision, hfd) \n" - " --version -V Print version information\n" - "\n" - "Examples: \n" - ". Flash jumploader to device w/ vid/pid 0x0c45/0x7040 \n" - " sonixflasher --vidpid 0c45/7040 --file fw.bin -j\n" - ". Flash fw to device w/ vid/pid 0x0c45/0x7040 and offset 0x200\n" - " sonixflasher --vidpid 0c45/7040 --file fw.bin -o 0x200\n" - "\n" - "" - "", m_name); + "Usage: \n" + " %s [options]\n" + "where is one of:\n" + " --vidpid -v Set VID for device to flash \n" + " --offset -o Set flashing offset (default: 0)\n" + " --file -f Binary of the firmware to flash (*.bin extension) \n" + " --jumploader -j Define if we are flashing a jumploader \n" + " --reboot -r Request bootloader reboot in OEM firmware (options: evision, hfd) \n" + " --debug -d Enable debug mode \n" + " --version -V Print version information \n" + "\n" + "Examples: \n" + ". Flash jumploader to device w/ vid/pid 0x0c45/0x7040 \n" + " sonixflasher --vidpid 0c45/7040 --file fw.bin -j\n" + ". Flash fw to device w/ vid/pid 0x0c45/0x7040 and offset 0x200\n" + " sonixflasher --vidpid 0c45/7040 --file fw.bin -o 0x200\n" + "\n" + "" + "", + m_name); } -//Display program version -static void display_version(char *m_name) -{ - fprintf(stderr,"%s " PROJECT_VER "\n",m_name); +// Display program version +static void display_version(char *m_name) { + fprintf(stderr, "%s " PROJECT_VER "\n", m_name); } -void clear_buffer(unsigned char *data, size_t lenght) -{ - for(int i = 0; i < lenght; i++) data[i] = 0; +void clear_buffer(unsigned char *data, size_t length) { + for (int i = 0; i < length; i++) + data[i] = 0; } -void print_buffer(unsigned char *data, size_t lenght) -{ +void print_buffer(unsigned char *data, size_t length) { printf("Sending Report...\n"); - for(int i = 0; i < lenght; i++) printf("%02x", data[i]); + for (int i = 0; i < length; i++) + printf("%02x", data[i]); printf("\n"); } -bool read_response_32(unsigned char *data, uint32_t expected_result, uint32_t *resp) -{ +bool read_response_32(unsigned char *data, uint32_t offset, uint32_t expected_result, uint32_t *resp) { uint32_t r = *resp; - memcpy(&r, data, 4); + memcpy(&r, data + offset, sizeof(uint32_t)); *resp = r; return r == expected_result; } -void write_buffer_32(unsigned char *data, uint32_t cmd) -{ +void write_buffer_32(unsigned char *data, uint32_t cmd) { memcpy(data, &cmd, 4); } -bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) -{ - if(length > REPORT_SIZE) - { +void print_data(const unsigned char *data, int length) { + for (int i = 0; i < length; i++) { + if (i % 16 == 0) { + if (i > 0) { + printf("\n"); + } + printf("%04x: ", i); // Print address offset + } + printf("%02x ", data[i]); + } + printf("\n"); + printf("\n"); +} + +bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { + if (length > REPORT_SIZE) { fprintf(stderr, "ERROR: Report can't be more than %d bytes!! (Attempted: %zu bytes)\n", REPORT_SIZE, length); return false; } + + if (debug) { + printf("Sending payload...\n"); + print_data(data, length); + } + unsigned char buf[REPORT_LENGTH]; // Set the Report ID byte (first byte of data) buf[0] = 0x0; memcpy(buf + 1, data, length); - int res = hid_send_feature_report(dev, data, length + 1); - - if(res < 0) - { + if (hid_send_feature_report(dev, data, length + 1) < 0) { fprintf(stderr, "ERROR: Error while writing!\n"); return false; } return true; } +int sn32_decode_chip(unsigned char *data) { + if (data[8] == 32) { + printf("Sonix SN32 Detected.\n"); + printf("Checking variant...\n"); + sleep(2); + int sn32_variant; + switch (data[9]) { + case SN240: + printf("240 Detected.\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN240; + break; + case SN260: + printf("260 Detected.\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0; + sn32_variant = SN260; + break; + case SN240B: + printf("240B Detected.\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240B; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0; + sn32_variant = SN240B; + break; + case SN290: + printf("290 Detected.\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN290; + break; + case SN240C: + printf("240C Detected. \n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240C; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN240C; + break; + default: + fprintf(stderr, "ERROR: Unsupported bootloader version: %d, we don't support this chip.\n", data[9]); + sn32_variant = 0; + break; + } + + return sn32_variant; + } else { + fprintf(stderr, "ERROR: Unsupported family version: %d, we don't support this chip.\n", data[8]); + return 0; + } +} +uint16_t sn32_get_cs_level(unsigned char *data) { + cs_level = 0; + uint16_t combined_cs = (data[12] << 8) | data[13]; + + if (combined_cs == CS0) { + printf("Current Security level: CS0. \n"); + } else { + switch (combined_cs) { + case CS1: + printf("Current Security level: CS1. \n"); + break; + case CS2: + printf("Current Security level: CS2. \n"); + break; + case CS3: + printf("Current Security level: CS3. \n"); + break; + default: + fprintf(stderr, "ERROR: Unsupported Security level: %04x, we don't support this chip.\n", combined_cs); + break; + } + } + return combined_cs; +} -int hid_get_feature(hid_device *dev, unsigned char *data) -{ +bool hid_get_feature(hid_device *dev, unsigned char *data) { + clear_buffer(data, sizeof(data)); int res = hid_get_feature_report(dev, data, REPORT_LENGTH); - // If the read was successful and data length is greater than 0 - if (res > 0) { + + if (res == REPORT_LENGTH) { // Shift the data buffer to remove the first byte memmove(data, data + 1, res - 1); - // Return the length of the data excluding the removed first byte - return res - 1; - } - // Return 0 if the read was not successful or the buffer length is not sufficient - return 0; + if (debug) { + printf("Received payload...\n"); + print_data(data, res - 1); + } + + // Check the status directly in the data buffer + unsigned int status = *((unsigned int *)(data + 4)); + if (status != CMD_OK) { + fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x.\n", status, CMD_OK); + return false; + } + // Success + return true; + + } else { + fprintf(stderr, "ERROR: Failed to get feature report: got response of length %d, expected %d.\n", res, REPORT_LENGTH); + return false; + } } -bool send_magic_command(hid_device *dev, const uint32_t *command) -{ +bool send_magic_command(hid_device *dev, const uint32_t *command) { unsigned char buf[REPORT_SIZE]; clear_buffer(buf, sizeof(buf)); - write_buffer_32(buf,command[0]); - write_buffer_32(buf + sizeof(uint32_t),command[1]); - if(!hid_set_feature(dev,buf, sizeof(buf))) return false; + write_buffer_32(buf, command[0]); + write_buffer_32(buf + sizeof(uint32_t), command[1]); + if (!hid_set_feature(dev, buf, sizeof(buf))) return false; clear_buffer(buf, sizeof(buf)); return true; } -bool reboot_to_bootloader(hid_device *dev, char *oem_option) -{ - uint32_t evision_reboot[2] = { 0x5AA555AA, 0xCC3300FF }; - uint32_t hfd_reboot[2] = { 0x5A8942AA, 0xCC6271FF }; +bool reboot_to_bootloader(hid_device *dev, char *oem_option) { + uint32_t evision_reboot[2] = {0x5AA555AA, 0xCC3300FF}; + uint32_t hfd_reboot[2] = {0x5A8942AA, 0xCC6271FF}; - if (oem_option == NULL) - { + if (oem_option == NULL) { printf("ERROR: reboot option cannot be null.\n"); return false; } - if(strcmp(oem_option, "evision") == 0) - { - return send_magic_command(dev,evision_reboot); - } - else if(strcmp(oem_option, "hfd") == 0) - { - return send_magic_command(dev,hfd_reboot); + if (strcmp(oem_option, "evision") == 0) { + return send_magic_command(dev, evision_reboot); + } else if (strcmp(oem_option, "hfd") == 0) { + return send_magic_command(dev, hfd_reboot); } printf("ERROR: unsupported reboot option selected.\n"); return false; } -bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip_size_check, bool oem_reboot, char *oem_option) -{ +bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { unsigned char buf[REPORT_SIZE]; - int read_bytes; - uint32_t resp = 0; - uint32_t status = 0; - - if(skip_size_check == false) - { - if(fw_size + offset > MAX_FIRMWARE) - { - printf("ERROR: Firmware is too large too flash.\n"); - return false; - } - } - + uint32_t resp = 0; + chip = 0; // 0) Request bootloader reboot - - if(oem_reboot) - { + if (oem_reboot) { printf("Requesting bootloader reboot...\n"); - if(reboot_to_bootloader(dev, oem_option)) printf("Bootloader reboot succesfull.\n"); - else - { + if (reboot_to_bootloader(dev, oem_option)) + printf("Bootloader reboot succesfull.\n"); + else { printf("ERROR: Bootloader reboot failed.\n"); return false; } } - - // 1) Initialize - - printf("Initializing flash...\n"); + // 01) Initialize + printf("Fetching flash version...\n"); + sleep(2); clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_GET_FW_VERSION); uint8_t attempt_no = 1; - while(!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. + while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { - printf("Flash failed to init, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); + printf("Flash failed to fetch flash version, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); sleep(3); attempt_no++; } - if(attempt_no > MAX_ATTEMPTS) return false; - - clear_buffer(buf, REPORT_SIZE); - read_bytes = hid_get_feature(dev, buf); - if(read_bytes != REPORT_SIZE) - { - fprintf(stderr, "ERROR: Failed to initialize: got response of length %d, expected %d.\n", read_bytes, REPORT_SIZE); - return false; - } - bool reboot_fail = !read_response_32(buf, 0, &resp); - bool init_fail = !read_response_32(buf, CMD_GET_FW_VERSION, &resp); - if(init_fail) - { - if(oem_reboot && reboot_fail) - { + if (attempt_no > MAX_ATTEMPTS) return false; + + if (!hid_get_feature(dev, buf)) return false; + chip = sn32_decode_chip(buf); + cs_level = sn32_get_cs_level(buf); + bool reboot_fail = !read_response_32(buf, 0, 0, &resp); + bool init_fail = !read_response_32(buf, 0, CMD_GET_FW_VERSION, &resp); + if (init_fail) { + if (oem_reboot && reboot_fail) { fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, 0); - } - else fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_GET_FW_VERSION); + } else + fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_GET_FW_VERSION); return false; } - // // 2) Prepare for flash + return true; +} - printf("Preparing for flash...\n"); +bool protocol_blank_check(hid_device *dev) { + unsigned char buf[REPORT_SIZE]; + // 02) Prepare for ISP password check + printf("Checking ISP password...\n"); // aka Blank Check + clear_buffer(buf, REPORT_SIZE); + write_buffer_32(buf, CMD_COMPARE_ISP_PASSWORD); + if (chip == SN240) write_buffer_32(buf + 4, ISP_PASSWORD); + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + clear_buffer(buf, REPORT_SIZE); + return true; +} +bool protocol_reset_cs(hid_device *dev) { + unsigned char buf[REPORT_SIZE]; + // 03) Reset ISP password + printf("Resetting ISP password...\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_ENABLE_PROGRAM); - write_buffer_32(buf+4, (uint32_t)offset); - write_buffer_32(buf+8, (uint32_t)(fw_size/REPORT_SIZE)); - if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + write_buffer_32(buf, CMD_SET_ENCRYPTION_ALGO); + write_buffer_32(buf + 6, CS0); // WARNING THIS SETS CS + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + if (!hid_get_feature(dev, buf)) return false; + clear_buffer(buf, REPORT_SIZE); + return true; +} +bool erase_flash(hid_device *dev) { + unsigned char buf[REPORT_SIZE]; + // 04) Erase flash + printf("Erasing flash...\n"); clear_buffer(buf, REPORT_SIZE); - read_bytes = hid_get_feature(dev, buf); - if(!read_response_32(buf, CMD_ENABLE_PROGRAM, &resp)) // Read cmd - { - fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_ENABLE_PROGRAM); - return false; - } - if(!read_response_32(buf + 4, CMD_OK, &status))// Read status + write_buffer_32(buf, CMD_ENABLE_ERASE); + write_buffer_32(buf + 8, USER_ROM_SIZE); + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + if (!hid_get_feature(dev, buf)) return false; + clear_buffer(buf, REPORT_SIZE); + return true; +} + +bool protocol_reboot_user(hid_device *dev) { + unsigned char buf[REPORT_SIZE]; + // 08) Reboot to User Mode + printf("Flashing done. Rebooting.\n"); + clear_buffer(buf, REPORT_SIZE); + write_buffer_32(buf, CMD_RETURN_USER_MODE); + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + clear_buffer(buf, REPORT_SIZE); + return true; +} + +bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip_offset_check) { + unsigned char buf[REPORT_SIZE]; + uint32_t resp = 0; + + if (chip == SN260 && !flash_jumploader && offset == 0) // Failsafe when flashing a 268 w/o jumploader and offset { - fprintf(stderr, "ERROR: Failed to initialize: response status is 0x%08x, expected 0x%08x.\n", status, CMD_OK); - return false; + printf("Warning: 26X flashing without offset.\n"); + printf("Warning: POTENTIALLY DANGEROUS OPERATION.\n"); + sleep(3); + if (skip_offset_check) { + printf("Warning: Flashing 26X without offset. Operation will continue after 10s...\n"); + sleep(10); + } else { + printf("Fail safing to offset 0x%04x\n", QMK_OFFSET_DEFAULT); + offset = QMK_OFFSET_DEFAULT; + } } - // // 3) Flash + // 05) Enable program + printf("\n"); + printf("Enabling Program mode...\n"); + sleep(2); + clear_buffer(buf, REPORT_SIZE); + write_buffer_32(buf, CMD_ENABLE_PROGRAM); + write_buffer_32(buf + 4, (uint32_t)offset); + write_buffer_32(buf + 8, (uint32_t)(fw_size / REPORT_SIZE)); + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + + if (!hid_get_feature(dev, buf)) return false; + clear_buffer(buf, REPORT_SIZE); + // return true; + // 06) Flash printf("Flashing device, please wait...\n"); size_t bytes_read = 0; clear_buffer(buf, REPORT_SIZE); - while ((bytes_read = fread(buf+1, 1, REPORT_SIZE, firmware)) > 0) - { - if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + while ((bytes_read = fread(buf + 1, 1, REPORT_SIZE, firmware)) > 0) { + if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); } - - printf("Flashing done. Rebooting.\n"); - - // // 4) reboot - clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_RETURN_USER_MODE); - if(!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - - return true; + // 07) Verify flash complete + printf("\n"); + printf("Verifying flash completion...\n"); + if (!hid_get_feature(dev, buf)) return false; + if (read_response_32(buf, (sizeof(buf) - sizeof(VALID_FW)), VALID_FW, &resp)) { + printf("Flash completion verified. \n"); + return true; + } else { + fprintf(stderr, "ERROR: Failed to verify flash completion: response is 0x%08x, expected 0x%08x.\n", resp, VALID_FW); + return false; + } + return false; } -int str2buf(void* buffer, char* delim_str, char* string, int buflen, int bufelem_size) -{ - char *s; - int pos = 0; - if( string==NULL ) return -1; - memset(buffer,0,buflen); // bzero() not defined on Win32? - while((s = strtok(string, delim_str)) != NULL && pos < buflen){ +int str2buf(void *buffer, char *delim_str, char *string, int buflen, int bufelem_size) { + char *s; + int pos = 0; + if (string == NULL) return -1; + memset(buffer, 0, buflen); // bzero() not defined on Win32? + while ((s = strtok(string, delim_str)) != NULL && pos < buflen) { string = NULL; - switch(bufelem_size) { - case 1: - ((uint8_t*)buffer)[pos++] = (uint8_t)strtol(s, NULL, 0); break; - case 2: - ((int*)buffer)[pos++] = (int)strtol(s, NULL, 0); break; + switch (bufelem_size) { + case 1: + ((uint8_t *)buffer)[pos++] = (uint8_t)strtol(s, NULL, 0); + break; + case 2: + ((int *)buffer)[pos++] = (int)strtol(s, NULL, 0); + break; } } return pos; } -bool sanity_check_firmware(long fw_size, long offset) -{ - if(fw_size + offset > MAX_FIRMWARE) - { +bool sanity_check_firmware(long fw_size, long offset) { + if (fw_size + offset > MAX_FIRMWARE) { fprintf(stderr, "ERROR: Firmware is too large too flash: 0x%08lx max allowed is 0x%08lx.\n", fw_size, MAX_FIRMWARE - offset); return false; } - if(fw_size < 0x100) - { + if (fw_size < 0x100) { fprintf(stderr, "ERROR: Firmware is too small."); return false; } return true; - //TODO check pointer validity + // TODO check pointer validity } -bool sanity_check_jumploader_firmware(long fw_size) -{ - if(fw_size > QMK_OFFSET_DEFAULT) - { +bool sanity_check_jumploader_firmware(long fw_size) { + if (fw_size > QMK_OFFSET_DEFAULT) { fprintf(stderr, "ERROR: Jumper loader is too large: 0x%08lx max allowed is 0x%08lx.\n", fw_size, MAX_FIRMWARE - QMK_OFFSET_DEFAULT); return false; } @@ -326,68 +488,55 @@ bool sanity_check_jumploader_firmware(long fw_size) return true; } -int main(int argc, char* argv[]) -{ - int opt, opt_index, res; +int main(int argc, char *argv[]) { + int opt, opt_index, res; hid_device *handle; - uint16_t vid = 0; - uint16_t pid = 0; - long offset = 0; - char* file_name = NULL; - char* endptr = NULL; - char* reboot_opt = NULL; - - bool reboot_requested = false; - bool flash_jumploader = false; - - if(argc < 2) - { + uint16_t vid = 0; + uint16_t pid = 0; + long offset = 0; + char *file_name = NULL; + char *endptr = NULL; + char *reboot_opt = NULL; + bool reboot_requested = false; + debug = false; + bool no_offset_check = false; + + if (argc < 2) { print_usage(PROJECT_NAME); exit(1); } - struct option longoptions[] = - { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"vidpid", required_argument, NULL, 'v'}, - {"offset", optional_argument, NULL, 'o'}, - {"file", required_argument, NULL, 'f'}, - {"jumploader", required_argument, NULL, 'j'}, - {"reboot", required_argument, NULL, 'r'}, - {NULL,0,0,0} - }; - - while ((opt = getopt_long(argc, argv, "hVv:o:r:f:j", longoptions, &opt_index)) != -1) - { - switch (opt) - { + struct option longoptions[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"vidpid", required_argument, NULL, 'v'}, {"offset", optional_argument, NULL, 'o'}, {"file", required_argument, NULL, 'f'}, {"jumploader", no_argument, NULL, 'j'}, {"reboot", required_argument, NULL, 'r'}, {"debug", no_argument, NULL, 'd'}, {"nooffset", no_argument, NULL, 'k'}, {NULL, 0, 0, 0}}; + + while ((opt = getopt_long(argc, argv, "hVv:o:r:f:jdk", longoptions, &opt_index)) != -1) { + switch (opt) { case 'h': // Show help print_usage(PROJECT_NAME); break; case 'V': // version display_version(PROJECT_NAME); break; - case 'v': // Set vid/pid - if( sscanf(optarg, "%4hx/%4hx", &vid,&pid) !=2 ) { // match "23FE/AB12" - if( !sscanf(optarg, "%4hx:%4hx", &vid,&pid) ) { // match "23FE:AB12" + case 'v': // Set vid/pid + if (sscanf(optarg, "%4hx/%4hx", &vid, &pid) != 2) { // match "23FE/AB12" + if (!sscanf(optarg, "%4hx:%4hx", &vid, &pid)) { // match "23FE:AB12" // else try parsing standard dec/hex values int wordbuf[4]; // a little extra space str2buf(wordbuf, ":/, ", optarg, sizeof(wordbuf), 2); - vid = wordbuf[0]; pid = wordbuf[1]; + vid = wordbuf[0]; + pid = wordbuf[1]; } } // make sure we have the correct vidpid - if(vid == 0 || pid == 0) { - fprintf(stderr, "ERROR: invalid vidpid -'%s'.\n",optarg); + if (vid == 0 || pid == 0) { + fprintf(stderr, "ERROR: invalid vidpid -'%s'.\n", optarg); exit(1); } break; case 'f': // file name file_name = optarg; break; - case 'o': // offset + case 'o': // offset offset = strtol(optarg, &endptr, 0); if (errno == ERANGE || *endptr != '\0') { fprintf(stderr, "ERROR: invalid offset value -'%s'.\n", optarg); @@ -395,16 +544,21 @@ int main(int argc, char* argv[]) } break; case 'r': // reboot - reboot_opt = optarg; + reboot_opt = optarg; reboot_requested = true; break; case 'j': // Jumploader flash_jumploader = true; break; + case 'd': // debug + debug = true; + break; + case 'k': // skip offset check + no_offset_check = true; + break; case '?': default: - switch (optopt) - { + switch (optopt) { case 'f': case 'v': case 'o': @@ -421,49 +575,44 @@ int main(int argc, char* argv[]) exit(1); } // exit clean after printing - if(opt == 'h' || opt == 'V') exit(1); + if (opt == 'h' || opt == 'V') exit(1); } - if (file_name == NULL) - { + if (file_name == NULL) { fprintf(stderr, "ERROR: filename cannot be null.\n"); exit(1); } printf("Firmware to flash: %s with offset 0x%04lx, device: 0x%04x/0x%04x.\n", file_name, offset, vid, pid); - FILE* fp = fopen(file_name, "rb"); + FILE *fp = fopen(file_name, "rb"); - if(fp == NULL) - { + if (fp == NULL) { fprintf(stderr, "ERROR: Could not open file (Does the file exist?).\n"); fclose(fp); exit(1); } // Get file size - fseek(fp, 0 , SEEK_END); + fseek(fp, 0, SEEK_END); long file_size = ftell(fp); - fseek(fp, 0 , SEEK_SET); + fseek(fp, 0, SEEK_SET); // if jumploader is not 0x200 in length, add padded zeroes to file - if(flash_jumploader && file_size < QMK_OFFSET_DEFAULT) - { + if (flash_jumploader && file_size < QMK_OFFSET_DEFAULT) { printf("Warning: jumploader binary doesnt have a size of: 0x%04x bytes.\n", QMK_OFFSET_DEFAULT); printf("Truncating jumploader binary to: 0x%04x.\n", QMK_OFFSET_DEFAULT); // Close device before truncating it fclose(fp); - if (truncate(file_name, QMK_OFFSET_DEFAULT) != 0) - { + if (truncate(file_name, QMK_OFFSET_DEFAULT) != 0) { fprintf(stderr, "ERROR: Could not truncate file.\n"); exit(1); } - + // Try open the file again. fp = fopen(file_name, "rb"); - if(fp == NULL) - { + if (fp == NULL) { fprintf(stderr, "ERROR: Could not open file.\n"); fclose(fp); exit(1); @@ -472,84 +621,51 @@ int main(int argc, char* argv[]) // Try to open the device res = hid_init(); - + printf("\n"); + printf("\n"); printf("Opening device...\n"); handle = hid_open(vid, pid, NULL); uint8_t attempt_no = 1; - while(handle == NULL && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to connect to device. - { + while (handle == NULL && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to connect to device. + { printf("Device failed to open, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); sleep(3); handle = hid_open(vid, pid, NULL); attempt_no++; } - if(handle) - { + if (handle) { + printf("\n"); printf("Device opened successfully...\n"); // Check VID/PID - if(vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid!= SN248C_PID && pid != SN268_PID && pid !=SN299_PID)) - { - if(vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); - if(vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); + if (vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN248C_PID && pid != SN268_PID && pid != SN299_PID)) { + if (vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); + if (vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); printf("Warning: Flashing a non-sonix bootloader device, you are now on your own.\n"); sleep(3); - - // Set max firmware to 64k, useful when flashing a Sonix Board that isnt in BL mode (Redragons, Keychrons) - MAX_FIRMWARE = MAX_FIRMWARE_SN32F240; // Maybe add a param to override this (?) - printf("Warning: We assume a ROM size of 64k.\n"); - sleep(3); - } - - // Set max fw size depending on VID/PID - if(vid == SONIX_VID) - { - switch (pid) - { - case SN248_PID: - case SN248B_PID: - MAX_FIRMWARE = MAX_FIRMWARE_SN32F240; - break; - case SN248C_PID: - MAX_FIRMWARE = MAX_FIRMWARE_SN32F240C; - case SN299_PID: - MAX_FIRMWARE = MAX_FIRMWARE_SN32F290; - break; - case SN268_PID: - MAX_FIRMWARE = MAX_FIRMWARE_SN32F260; - - if(!flash_jumploader && offset == 0) // Failsafe when flashing a 268 w/o jumploader and offset - { - printf("Warning: Flashing 26X without offset.\n"); - printf("Fail safing to offset 0x%04x\n", QMK_OFFSET_DEFAULT); - - offset = QMK_OFFSET_DEFAULT; - } - break; - - default: - fprintf(stderr, "ERROR: Unsupported sonix bootloader device. Quitting.\n"); - exit(1); - } } + protocol_init(handle, reboot_requested, reboot_opt); + sleep(3); + if (chip == SN240 || chip == SN290) protocol_blank_check(handle); // 240 and 290 + sleep(1); + if (cs_level != CS0) protocol_reset_cs(handle); + sleep(1); + if (chip == SN240 || chip == SN290) erase_flash(handle); + sleep(1); - while (file_size % REPORT_SIZE != 0) file_size++; // Add padded zereos (if any) to file_size, since we are using a fixed 64 + 1 buffer, we need to take in consideration when the file doesnt fill the buffer. + while (file_size % REPORT_SIZE != 0) + file_size++; // Add padded zereos (if any) to file_size, since we are using a fixed 64 + 1 buffer, we need to take in consideration when the file doesnt fill the buffer. - if( ((flash_jumploader && sanity_check_jumploader_firmware(file_size)) || - (!flash_jumploader && sanity_check_firmware(file_size, offset))) && - (flash(handle, offset, fp, file_size, false, reboot_requested, reboot_opt))) - { + if (((flash_jumploader && sanity_check_jumploader_firmware(file_size)) || (!flash_jumploader && sanity_check_firmware(file_size, offset))) && (flash(handle, offset, fp, file_size, no_offset_check))) { printf("Device succesfully flashed!\n"); - } - else - { + sleep(3); + protocol_reboot_user(handle); + } else { fprintf(stderr, "ERROR: Could not flash the device. Try again.\n"); } - } - else - { + } else { fprintf(stderr, "ERROR: Could not open the device (Is the device connected?).\n"); } @@ -557,10 +673,9 @@ int main(int argc, char* argv[]) hid_close(handle); res = hid_exit(); - if(res < 0) - { + if (res < 0) { fprintf(stderr, "ERROR: Could not close the device.\n"); } - exit(0); + exit(0); } From 4276fed5c4ebe608438b9d29f1ea2a4a46dc88e7 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 16:59:11 +0300 Subject: [PATCH 07/46] debug: print out verbose fails --- sonixflasher.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 9df05b9..ece5bd8 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -239,7 +239,7 @@ uint16_t sn32_get_cs_level(unsigned char *data) { return combined_cs; } -bool hid_get_feature(hid_device *dev, unsigned char *data) { +bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { clear_buffer(data, sizeof(data)); int res = hid_get_feature_report(dev, data, REPORT_LENGTH); @@ -255,14 +255,14 @@ bool hid_get_feature(hid_device *dev, unsigned char *data) { // Check the status directly in the data buffer unsigned int status = *((unsigned int *)(data + 4)); if (status != CMD_OK) { - fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x.\n", status, CMD_OK); + fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02X.\n", status, CMD_OK, command & 0xFF); return false; } // Success return true; } else { - fprintf(stderr, "ERROR: Failed to get feature report: got response of length %d, expected %d.\n", res, REPORT_LENGTH); + fprintf(stderr, "ERROR: Failed to get feature report for command 0x%02X: got response of length %d, expected %d.\n", command & 0xFF, res, REPORT_LENGTH); return false; } } @@ -324,7 +324,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { } if (attempt_no > MAX_ATTEMPTS) return false; - if (!hid_get_feature(dev, buf)) return false; + if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; chip = sn32_decode_chip(buf); cs_level = sn32_get_cs_level(buf); bool reboot_fail = !read_response_32(buf, 0, 0, &resp); @@ -359,7 +359,7 @@ bool protocol_reset_cs(hid_device *dev) { write_buffer_32(buf, CMD_SET_ENCRYPTION_ALGO); write_buffer_32(buf + 6, CS0); // WARNING THIS SETS CS if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf)) return false; + if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); return true; } @@ -372,7 +372,7 @@ bool erase_flash(hid_device *dev) { write_buffer_32(buf, CMD_ENABLE_ERASE); write_buffer_32(buf + 8, USER_ROM_SIZE); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf)) return false; + if (!hid_get_feature(dev, buf, CMD_ENABLE_ERASE)) return false; clear_buffer(buf, REPORT_SIZE); return true; } @@ -416,7 +416,7 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip write_buffer_32(buf + 8, (uint32_t)(fw_size / REPORT_SIZE)); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf)) return false; + if (!hid_get_feature(dev, buf, CMD_ENABLE_PROGRAM)) return false; clear_buffer(buf, REPORT_SIZE); // return true; @@ -434,7 +434,7 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip // 07) Verify flash complete printf("\n"); printf("Verifying flash completion...\n"); - if (!hid_get_feature(dev, buf)) return false; + if (!hid_get_feature(dev, buf, CMD_ENABLE_PROGRAM)) return false; if (read_response_32(buf, (sizeof(buf) - sizeof(VALID_FW)), VALID_FW, &resp)) { printf("Flash completion verified. \n"); return true; From e841dc910158adf0dc9a1287b1ba6515fe97889d Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 17:31:49 +0300 Subject: [PATCH 08/46] debug: try to print error states this is platform dependent - not implemented in all platforms --- sonixflasher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index ece5bd8..17037ea 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -154,7 +154,8 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { memcpy(buf + 1, data, length); if (hid_send_feature_report(dev, data, length + 1) < 0) { - fprintf(stderr, "ERROR: Error while writing!\n"); + unsigned char command = data[0]; + fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", command, hid_error(dev)); return false; } From b444a43be7b0f16f1990c29d0a86921753c9ded4 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 17:54:23 +0300 Subject: [PATCH 09/46] correct cs location --- sonixflasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index 17037ea..3f00822 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -217,7 +217,7 @@ int sn32_decode_chip(unsigned char *data) { } uint16_t sn32_get_cs_level(unsigned char *data) { cs_level = 0; - uint16_t combined_cs = (data[12] << 8) | data[13]; + uint16_t combined_cs = (data[14] << 8) | data[15]; if (combined_cs == CS0) { printf("Current Security level: CS0. \n"); From fe329aa6fdf3be15d993e9ee173bb1129d1faebf Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 18:46:40 +0300 Subject: [PATCH 10/46] add better password checks and bail if any part fails --- sonixflasher.c | 60 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 3f00822..fd6b307 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -33,7 +33,6 @@ #define CMD_OK 0xFAFAFAFA #define VALID_FW 0xAAAA5555 -#define ISP_PASSWORD 0xFEFF #define SN240 1 #define SN260 2 @@ -60,13 +59,14 @@ #define PROJECT_NAME "sonixflasher" #define PROJECT_VER "2.0.1" -uint16_t CS0 = 0; -uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; -long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); -bool flash_jumploader = false; -bool debug = false; -int chip; -uint16_t cs_level; +uint16_t CS0 = 0; +uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; +long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); +bool flash_jumploader = false; +bool debug = false; +static uint16_t password = 0x0000; // Initial ISP password +int chip; +uint16_t cs_level; static void print_usage(char *m_name) { fprintf(stderr, @@ -215,6 +215,19 @@ int sn32_decode_chip(unsigned char *data) { return 0; } } + +bool sn32_get_isp_password(unsigned char *data) { + uint16_t received_password = (data[12] << 8) | data[13]; + printf("Expected password: 0x%04X\n", password); + printf("Received password: 0x%04X\n", received_password); + if (received_password != password) { + printf("Updating password from 0x%04X to 0x%04X\n", password, received_password); + password = received_password; + return false; + } + return true; +} + uint16_t sn32_get_cs_level(unsigned char *data) { cs_level = 0; uint16_t combined_cs = (data[14] << 8) | data[15]; @@ -316,6 +329,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { sleep(2); clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_GET_FW_VERSION); + write_buffer_32(buf + 4, password); uint8_t attempt_no = 1; while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { @@ -326,8 +340,10 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (attempt_no > MAX_ATTEMPTS) return false; if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; - chip = sn32_decode_chip(buf); - cs_level = sn32_get_cs_level(buf); + chip = sn32_decode_chip(buf); + cs_level = sn32_get_cs_level(buf); + if (!sn32_get_isp_password(buf)) return false; + bool reboot_fail = !read_response_32(buf, 0, 0, &resp); bool init_fail = !read_response_32(buf, 0, CMD_GET_FW_VERSION, &resp); if (init_fail) { @@ -346,7 +362,7 @@ bool protocol_blank_check(hid_device *dev) { printf("Checking ISP password...\n"); // aka Blank Check clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_COMPARE_ISP_PASSWORD); - if (chip == SN240) write_buffer_32(buf + 4, ISP_PASSWORD); + write_buffer_32(buf + 4, password); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); return true; @@ -358,6 +374,7 @@ bool protocol_reset_cs(hid_device *dev) { printf("Resetting ISP password...\n"); clear_buffer(buf, REPORT_SIZE); write_buffer_32(buf, CMD_SET_ENCRYPTION_ALGO); + write_buffer_32(buf + 4, password); write_buffer_32(buf + 6, CS0); // WARNING THIS SETS CS if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; @@ -647,13 +664,24 @@ int main(int argc, char *argv[]) { printf("Warning: Flashing a non-sonix bootloader device, you are now on your own.\n"); sleep(3); } - protocol_init(handle, reboot_requested, reboot_opt); + attempt_no = 1; + bool ok = protocol_init(handle, reboot_requested, reboot_opt); + while (!ok && attempt_no <= MAX_ATTEMPTS) { + printf("Device failed to init, re-trying in 3 seconds. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); + sleep(3); + ok = protocol_init(handle, reboot_requested, reboot_opt); + attempt_no++; + } + if (!ok) exit(1); sleep(3); - if (chip == SN240 || chip == SN290) protocol_blank_check(handle); // 240 and 290 + if (chip == SN240 || chip == SN290) ok = protocol_blank_check(handle); // 240 and 290 + if (!ok) exit(1); sleep(1); - if (cs_level != CS0) protocol_reset_cs(handle); + if (cs_level != CS0) ok = protocol_reset_cs(handle); + if (!ok) exit(1); sleep(1); - if (chip == SN240 || chip == SN290) erase_flash(handle); + if (chip == SN240 || chip == SN290) ok = erase_flash(handle); + if (!ok) exit(1); sleep(1); while (file_size % REPORT_SIZE != 0) @@ -665,9 +693,11 @@ int main(int argc, char *argv[]) { protocol_reboot_user(handle); } else { fprintf(stderr, "ERROR: Could not flash the device. Try again.\n"); + exit(1); } } else { fprintf(stderr, "ERROR: Could not open the device (Is the device connected?).\n"); + exit(1); } fclose(fp); From cf2fc277c2385a2819f2b7dafe45540be7e54c11 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 19:17:00 +0300 Subject: [PATCH 11/46] print out supported vid pid for known chips --- sonixflasher.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index fd6b307..9d35f87 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -68,6 +68,19 @@ static uint16_t password = 0x0000; // Initial ISP password int chip; uint16_t cs_level; +static void print_vidpid_table() { + printf("Supported VID/PID pairs:\n"); + printf("+-----------------+------------+------------+\n"); + printf("| Device | VID | PID |\n"); + printf("+-----------------+------------+------------+\n"); + printf("| SONIX SN26x | 0x%04X | 0x%04X |\n", SONIX_VID, SN268_PID); + printf("| SONIX SN24xB | 0x%04X | 0x%04X |\n", SONIX_VID, SN248B_PID); + printf("| SONIX SN24xC | 0x%04X | 0x%04X |\n", SONIX_VID, SN248C_PID); + printf("| SONIX SN24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN248_PID); + printf("| SONIX SN29x | 0x%04X | 0x%04X |\n", SONIX_VID, SN299_PID); + printf("+-----------------+------------+------------+\n"); +} + static void print_usage(char *m_name) { fprintf(stderr, "Usage: \n" @@ -79,6 +92,7 @@ static void print_usage(char *m_name) { " --jumploader -j Define if we are flashing a jumploader \n" " --reboot -r Request bootloader reboot in OEM firmware (options: evision, hfd) \n" " --debug -d Enable debug mode \n" + " --list-vidpid -l Display supported VID/PID pairs\n" " --version -V Print version information \n" "\n" "Examples: \n" @@ -216,7 +230,7 @@ int sn32_decode_chip(unsigned char *data) { } } -bool sn32_get_isp_password(unsigned char *data) { +bool sn32_check_isp_password(unsigned char *data) { uint16_t received_password = (data[12] << 8) | data[13]; printf("Expected password: 0x%04X\n", password); printf("Received password: 0x%04X\n", received_password); @@ -342,7 +356,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; chip = sn32_decode_chip(buf); cs_level = sn32_get_cs_level(buf); - if (!sn32_get_isp_password(buf)) return false; + if (!sn32_check_isp_password(buf)) return false; bool reboot_fail = !read_response_32(buf, 0, 0, &resp); bool init_fail = !read_response_32(buf, 0, CMD_GET_FW_VERSION, &resp); @@ -525,13 +539,16 @@ int main(int argc, char *argv[]) { exit(1); } - struct option longoptions[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"vidpid", required_argument, NULL, 'v'}, {"offset", optional_argument, NULL, 'o'}, {"file", required_argument, NULL, 'f'}, {"jumploader", no_argument, NULL, 'j'}, {"reboot", required_argument, NULL, 'r'}, {"debug", no_argument, NULL, 'd'}, {"nooffset", no_argument, NULL, 'k'}, {NULL, 0, 0, 0}}; + struct option longoptions[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"vidpid", required_argument, NULL, 'v'}, {"offset", optional_argument, NULL, 'o'}, {"file", required_argument, NULL, 'f'}, {"jumploader", no_argument, NULL, 'j'}, {"reboot", required_argument, NULL, 'r'}, {"debug", no_argument, NULL, 'd'}, {"nooffset", no_argument, NULL, 'k'}, {"list-vidpid", no_argument, NULL, 'l'}, {NULL, 0, 0, 0}}; - while ((opt = getopt_long(argc, argv, "hVv:o:r:f:jdk", longoptions, &opt_index)) != -1) { + while ((opt = getopt_long(argc, argv, "hlVv:o:r:f:jdk", longoptions, &opt_index)) != -1) { switch (opt) { case 'h': // Show help print_usage(PROJECT_NAME); break; + case 'l': // list-vidpid + print_vidpid_table(); + break; case 'V': // version display_version(PROJECT_NAME); break; @@ -548,6 +565,7 @@ int main(int argc, char *argv[]) { // make sure we have the correct vidpid if (vid == 0 || pid == 0) { fprintf(stderr, "ERROR: invalid vidpid -'%s'.\n", optarg); + print_vidpid_table(); exit(1); } break; From 0eefacfa49329d00c83a88267be0f40c91fd7da9 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 26 Aug 2024 19:28:27 +0300 Subject: [PATCH 12/46] fail if chip version is not supported --- sonixflasher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index 9d35f87..aae1204 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -354,7 +354,8 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (attempt_no > MAX_ATTEMPTS) return false; if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; - chip = sn32_decode_chip(buf); + chip = sn32_decode_chip(buf); + if (chip == 0) return false; cs_level = sn32_get_cs_level(buf); if (!sn32_check_isp_password(buf)) return false; From 916e9c51ba5279c9988b12ff243418274e99c108 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Thu, 5 Sep 2024 14:27:58 +0300 Subject: [PATCH 13/46] fix bad --offset argument reqs --- sonixflasher.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index aae1204..277dd76 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -539,8 +539,19 @@ int main(int argc, char *argv[]) { print_usage(PROJECT_NAME); exit(1); } - - struct option longoptions[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"vidpid", required_argument, NULL, 'v'}, {"offset", optional_argument, NULL, 'o'}, {"file", required_argument, NULL, 'f'}, {"jumploader", no_argument, NULL, 'j'}, {"reboot", required_argument, NULL, 'r'}, {"debug", no_argument, NULL, 'd'}, {"nooffset", no_argument, NULL, 'k'}, {"list-vidpid", no_argument, NULL, 'l'}, {NULL, 0, 0, 0}}; + // clang-format off + struct option longoptions[] = {{"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"vidpid", required_argument, NULL, 'v'}, + {"offset", required_argument, NULL, 'o'}, + {"file", required_argument, NULL, 'f'}, + {"jumploader", no_argument, NULL, 'j'}, + {"reboot", required_argument, NULL, 'r'}, + {"debug", no_argument, NULL, 'd'}, + {"nooffset", no_argument, NULL, 'k'}, + {"list-vidpid", no_argument, NULL, 'l'}, + {NULL, 0, 0, 0}}; + // clang-format on while ((opt = getopt_long(argc, argv, "hlVv:o:r:f:jdk", longoptions, &opt_index)) != -1) { switch (opt) { From 8f79b9534bff5062e0db43e849c4f627a3950ca0 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Thu, 5 Sep 2024 14:46:14 +0300 Subject: [PATCH 14/46] 280: preliminary support --- sonixflasher.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sonixflasher.c b/sonixflasher.c index 277dd76..885f26b 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -15,6 +15,7 @@ #define USER_ROM_SIZE_SN32F240 64 // in KB #define USER_ROM_SIZE_SN32F240B 64 // in KB #define USER_ROM_SIZE_SN32F240C 128 // in KB +#define USER_ROM_SIZE_SN32F280 128 // in KB #define USER_ROM_SIZE_SN32F290 256 // in KB #define USER_ROM_SIZE_KB(x) ((x) * 1024) @@ -37,6 +38,7 @@ #define SN240 1 #define SN260 2 #define SN240B 3 +#define SN280 4 #define SN290 5 #define SN240C 6 @@ -203,6 +205,13 @@ int sn32_decode_chip(unsigned char *data) { CS0 = 0; sn32_variant = SN240B; break; + case SN280: + printf("280 Detected.\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F280; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN280; + break; case SN290: printf("290 Detected.\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; From 58a43dda4747c1be78f5e60c17e12c42e6798de0 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 00:44:35 +0300 Subject: [PATCH 15/46] erase: correct behavior we should parse pages, not kb size --- sonixflasher.c | 62 +++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 885f26b..1554d90 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -19,6 +19,13 @@ #define USER_ROM_SIZE_SN32F290 256 // in KB #define USER_ROM_SIZE_KB(x) ((x) * 1024) +#define USER_ROM_PAGES_SN32F260 480 +#define USER_ROM_PAGES_SN32F240 64 +#define USER_ROM_PAGES_SN32F240B 1024 +#define USER_ROM_PAGES_SN32F240C 128 +#define USER_ROM_PAGES_SN32F280 128 +#define USER_ROM_PAGES_SN32F290 256 + #define QMK_OFFSET_DEFAULT 0x200 #define CMD_BASE 0x55AA00 @@ -63,6 +70,7 @@ uint16_t CS0 = 0; uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; +uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); bool flash_jumploader = false; bool debug = false; @@ -186,45 +194,51 @@ int sn32_decode_chip(unsigned char *data) { switch (data[9]) { case SN240: printf("240 Detected.\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; - sn32_variant = SN240; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN240; break; case SN260: printf("260 Detected.\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0; - sn32_variant = SN260; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0; + sn32_variant = SN260; break; case SN240B: printf("240B Detected.\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F240B; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0; - sn32_variant = SN240B; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240B; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F240B; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0; + sn32_variant = SN240B; break; case SN280: printf("280 Detected.\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F280; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; - sn32_variant = SN280; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F280; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F280; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN280; break; case SN290: printf("290 Detected.\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; - sn32_variant = SN290; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F290; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN290; break; case SN240C: printf("240C Detected. \n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F240C; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; - sn32_variant = SN240C; + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240C; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F240C; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_variant = SN240C; break; default: fprintf(stderr, "ERROR: Unsupported bootloader version: %d, we don't support this chip.\n", data[9]); From f350501e1532e63546357c0af6c2334ad369c1cd Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 12:27:09 +0300 Subject: [PATCH 16/46] add 280 series PID --- sonixflasher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index 1554d90..399a07b 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -58,6 +58,7 @@ #define SN248B_PID 0x7040 #define SN248C_PID 0x7145 #define SN248_PID 0x7900 +#define SN289_PID 0x7120 #define SN299_PID 0x7140 #define EVISION_VID 0x320F @@ -87,6 +88,7 @@ static void print_vidpid_table() { printf("| SONIX SN24xB | 0x%04X | 0x%04X |\n", SONIX_VID, SN248B_PID); printf("| SONIX SN24xC | 0x%04X | 0x%04X |\n", SONIX_VID, SN248C_PID); printf("| SONIX SN24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN248_PID); + printf("| SONIX SN28x | 0x%04X | 0x%04X |\n", SONIX_VID, SN289_PID); printf("| SONIX SN29x | 0x%04X | 0x%04X |\n", SONIX_VID, SN299_PID); printf("+-----------------+------------+------------+\n"); } @@ -711,7 +713,7 @@ int main(int argc, char *argv[]) { printf("Device opened successfully...\n"); // Check VID/PID - if (vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN248C_PID && pid != SN268_PID && pid != SN299_PID)) { + if (vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN248C_PID && pid != SN268_PID && pid != SN289_PID && pid != SN299_PID)) { if (vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); if (vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); printf("Warning: Flashing a non-sonix bootloader device, you are now on your own.\n"); From 288e1a64ddd7cd794fce3591db1661a7aee73578 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 22:27:40 +0300 Subject: [PATCH 17/46] update buffer handling to send 64b always --- sonixflasher.c | 102 +++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 37 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 399a07b..5b93e97 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -28,16 +28,17 @@ #define QMK_OFFSET_DEFAULT 0x200 -#define CMD_BASE 0x55AA00 -#define CMD_GET_FW_VERSION (CMD_BASE + 0x1) -#define CMD_COMPARE_ISP_PASSWORD (CMD_BASE + 0x2) -#define CMD_SET_ENCRYPTION_ALGO (CMD_BASE + 0x3) -#define CMD_ENABLE_ERASE (CMD_BASE + 0x4) -#define CMD_ENABLE_PROGRAM (CMD_BASE + 0x5) -#define CMD_GET_CHECKSUM (CMD_BASE + 0x6) -#define CMD_RETURN_USER_MODE (CMD_BASE + 0x7) -#define CMD_SET_CS (CMD_BASE + 0x8) -#define CMD_GET_CS (CMD_BASE + 0x9) +#define CMD_BASE 0x55AA +#define CMD_GET_FW_VERSION 0x1 +#define CMD_COMPARE_ISP_PASSWORD 0x2 +#define CMD_SET_ENCRYPTION_ALGO 0x3 +#define CMD_ENABLE_ERASE 0x4 +#define CMD_ENABLE_PROGRAM 0x5 +#define CMD_GET_CHECKSUM 0x6 +#define CMD_RETURN_USER_MODE 0x7 +#define CMD_SET_CS 0x8 +#define CMD_GET_CS 0x9 +#define CMD_VERIFY(x) ((CMD_BASE << 8) | (x)) #define CMD_OK 0xFAFAFAFA #define VALID_FW 0xAAAA5555 @@ -148,6 +149,10 @@ void write_buffer_32(unsigned char *data, uint32_t cmd) { memcpy(data, &cmd, 4); } +void write_buffer_16(unsigned char *data, uint16_t cmd) { + memcpy(data, &cmd, 2); +} + void print_data(const unsigned char *data, int length) { for (int i = 0; i < length; i++) { if (i % 16 == 0) { @@ -172,17 +177,30 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { printf("Sending payload...\n"); print_data(data, length); } - - unsigned char buf[REPORT_LENGTH]; - - // Set the Report ID byte (first byte of data) - buf[0] = 0x0; - memcpy(buf + 1, data, length); - - if (hid_send_feature_report(dev, data, length + 1) < 0) { - unsigned char command = data[0]; - fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", command, hid_error(dev)); - return false; + // hidapi will hijack a 0x00 for Report ID and strip it from the buffer. + // Check if the first byte of data is 0x00 + if (data[0] == 0x00) { + // Allocate a temporary buffer with an extra byte + unsigned char temp_buf[REPORT_SIZE + 1]; + + // Set the Report ID byte (0x00) at the start of the buffer + temp_buf[0] = 0x00; + + // Copy the data into the buffer, starting from the second byte + // This allows the actual 0x00 to be sent + memcpy(temp_buf + 1, data, length); + + // Send the feature report using the temporary buffer + if (hid_send_feature_report(dev, temp_buf, length + 1) < 0) { + fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", data[0], hid_error(dev)); + return false; + } + } else { + // Send the report as is + if (hid_send_feature_report(dev, data, length) < 0) { + fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", data[0], hid_error(dev)); + return false; + } } return true; @@ -367,8 +385,9 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { printf("Fetching flash version...\n"); sleep(2); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_GET_FW_VERSION); - write_buffer_32(buf + 4, password); + buf[0] = CMD_GET_FW_VERSION; + write_buffer_16(buf + 1, CMD_BASE); + write_buffer_16(buf + 3, password); uint8_t attempt_no = 1; while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { @@ -385,7 +404,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (!sn32_check_isp_password(buf)) return false; bool reboot_fail = !read_response_32(buf, 0, 0, &resp); - bool init_fail = !read_response_32(buf, 0, CMD_GET_FW_VERSION, &resp); + bool init_fail = !read_response_32(buf, 0, CMD_VERIFY(CMD_GET_FW_VERSION), &resp); if (init_fail) { if (oem_reboot && reboot_fail) { fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, 0); @@ -400,9 +419,9 @@ bool protocol_blank_check(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 02) Prepare for ISP password check printf("Checking ISP password...\n"); // aka Blank Check - clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_COMPARE_ISP_PASSWORD); - write_buffer_32(buf + 4, password); + buf[0] = CMD_COMPARE_ISP_PASSWORD; + write_buffer_16(buf + 1, CMD_BASE); + write_buffer_16(buf + 3, password); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); return true; @@ -413,9 +432,10 @@ bool protocol_reset_cs(hid_device *dev) { // 03) Reset ISP password printf("Resetting ISP password...\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_SET_ENCRYPTION_ALGO); - write_buffer_32(buf + 4, password); - write_buffer_32(buf + 6, CS0); // WARNING THIS SETS CS + buf[0] = CMD_SET_ENCRYPTION_ALGO; + write_buffer_16(buf + 1, CMD_BASE); + write_buffer_16(buf + 3, password); + write_buffer_16(buf + 5, CS0); // WARNING THIS SETS CS if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); @@ -427,8 +447,9 @@ bool erase_flash(hid_device *dev) { // 04) Erase flash printf("Erasing flash...\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_ENABLE_ERASE); - write_buffer_32(buf + 8, USER_ROM_SIZE); + buf[0] = CMD_ENABLE_ERASE; + write_buffer_16(buf + 1, CMD_BASE); + write_buffer_16(buf + 8, USER_ROM_PAGES); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_ENABLE_ERASE)) return false; clear_buffer(buf, REPORT_SIZE); @@ -440,7 +461,8 @@ bool protocol_reboot_user(hid_device *dev) { // 08) Reboot to User Mode printf("Flashing done. Rebooting.\n"); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_RETURN_USER_MODE); + buf[0] = CMD_RETURN_USER_MODE; + write_buffer_16(buf + 1, CMD_BASE); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); return true; @@ -469,7 +491,8 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip printf("Enabling Program mode...\n"); sleep(2); clear_buffer(buf, REPORT_SIZE); - write_buffer_32(buf, CMD_ENABLE_PROGRAM); + buf[0] = CMD_ENABLE_PROGRAM; + write_buffer_16(buf + 1, CMD_BASE); write_buffer_32(buf + 4, (uint32_t)offset); write_buffer_32(buf + 8, (uint32_t)(fw_size / REPORT_SIZE)); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; @@ -483,8 +506,13 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip size_t bytes_read = 0; clear_buffer(buf, REPORT_SIZE); - while ((bytes_read = fread(buf + 1, 1, REPORT_SIZE, firmware)) > 0) { - if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; + while ((bytes_read = fread(buf, 1, REPORT_SIZE, firmware)) > 0) { + if (bytes_read < REPORT_SIZE) { + fprintf(stderr, "WARNING: Read %zu bytes, expected %d bytes.\n", bytes_read, REPORT_SIZE); + exit(1); + } + if (!hid_set_feature(dev, buf, bytes_read)) return false; + clear_buffer(buf, REPORT_SIZE); } clear_buffer(buf, REPORT_SIZE); @@ -740,7 +768,7 @@ int main(int argc, char *argv[]) { sleep(1); while (file_size % REPORT_SIZE != 0) - file_size++; // Add padded zereos (if any) to file_size, since we are using a fixed 64 + 1 buffer, we need to take in consideration when the file doesnt fill the buffer. + file_size++; // Add padded zereos (if any) to file_size, we need to take in consideration when the file doesnt fill the buffer. if (((flash_jumploader && sanity_check_jumploader_firmware(file_size)) || (!flash_jumploader && sanity_check_firmware(file_size, offset))) && (flash(handle, offset, fp, file_size, no_offset_check))) { printf("Device succesfully flashed!\n"); From 5608960279da8fba7b0aeff37fde7240b01549ed Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 22:41:56 +0300 Subject: [PATCH 18/46] rename isp password check we're actually doing code option table checks here --- sonixflasher.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 5b93e97..6341385 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -30,7 +30,7 @@ #define CMD_BASE 0x55AA #define CMD_GET_FW_VERSION 0x1 -#define CMD_COMPARE_ISP_PASSWORD 0x2 +#define CMD_COMPARE_CODE_OPTION 0x2 #define CMD_SET_ENCRYPTION_ALGO 0x3 #define CMD_ENABLE_ERASE 0x4 #define CMD_ENABLE_PROGRAM 0x5 @@ -76,7 +76,7 @@ uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); bool flash_jumploader = false; bool debug = false; -static uint16_t password = 0x0000; // Initial ISP password +static uint16_t code_option = 0x0000; // Initial Code Option Table int chip; uint16_t cs_level; @@ -273,13 +273,13 @@ int sn32_decode_chip(unsigned char *data) { } } -bool sn32_check_isp_password(unsigned char *data) { - uint16_t received_password = (data[12] << 8) | data[13]; - printf("Expected password: 0x%04X\n", password); - printf("Received password: 0x%04X\n", received_password); - if (received_password != password) { - printf("Updating password from 0x%04X to 0x%04X\n", password, received_password); - password = received_password; +bool sn32_check_isp_code_option(unsigned char *data) { + uint16_t received_code_option = (data[12] << 8) | data[13]; + printf("Expected Code Option Table: 0x%04X\n", code_option); + printf("Received Code Option Table: 0x%04X\n", received_code_option); + if (received_code_option != code_option) { + printf("Updating Code Option Table from 0x%04X to 0x%04X\n", code_option, received_code_option); + code_option = received_code_option; return false; } return true; @@ -387,7 +387,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_GET_FW_VERSION; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, password); + write_buffer_16(buf + 3, code_option); uint8_t attempt_no = 1; while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { @@ -401,7 +401,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { chip = sn32_decode_chip(buf); if (chip == 0) return false; cs_level = sn32_get_cs_level(buf); - if (!sn32_check_isp_password(buf)) return false; + if (!sn32_check_isp_code_option(buf)) return false; bool reboot_fail = !read_response_32(buf, 0, 0, &resp); bool init_fail = !read_response_32(buf, 0, CMD_VERIFY(CMD_GET_FW_VERSION), &resp); @@ -415,13 +415,13 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { return true; } -bool protocol_blank_check(hid_device *dev) { +bool protocol_code_option_check(hid_device *dev) { unsigned char buf[REPORT_SIZE]; - // 02) Prepare for ISP password check - printf("Checking ISP password...\n"); // aka Blank Check - buf[0] = CMD_COMPARE_ISP_PASSWORD; + // 02) Prepare for Code Option Table check + printf("Checking Code Option Table...\n"); + buf[0] = CMD_COMPARE_CODE_OPTION; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, password); + write_buffer_16(buf + 3, code_option); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); return true; @@ -429,13 +429,13 @@ bool protocol_blank_check(hid_device *dev) { bool protocol_reset_cs(hid_device *dev) { unsigned char buf[REPORT_SIZE]; - // 03) Reset ISP password - printf("Resetting ISP password...\n"); + // 03) Reset Code Option Table + printf("Resetting Code Option Table...\n"); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_SET_ENCRYPTION_ALGO; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, password); - write_buffer_16(buf + 5, CS0); // WARNING THIS SETS CS + write_buffer_16(buf + 3, code_option); + write_buffer_16(buf + 5, CS0); // WARNING THIS SETS CS0 if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); @@ -757,7 +757,7 @@ int main(int argc, char *argv[]) { } if (!ok) exit(1); sleep(3); - if (chip == SN240 || chip == SN290) ok = protocol_blank_check(handle); // 240 and 290 + if (chip == SN240 || chip == SN290) ok = protocol_code_option_check(handle); // 240 and 290 if (!ok) exit(1); sleep(1); if (cs_level != CS0) ok = protocol_reset_cs(handle); From a23b8bd2414d1321c61eede9d2f1a7036322ed32 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 23:08:38 +0300 Subject: [PATCH 19/46] slight cleanup --- sonixflasher.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 6341385..d588a61 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -419,6 +419,7 @@ bool protocol_code_option_check(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 02) Prepare for Code Option Table check printf("Checking Code Option Table...\n"); + clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_COMPARE_CODE_OPTION; write_buffer_16(buf + 1, CMD_BASE); write_buffer_16(buf + 3, code_option); @@ -499,7 +500,6 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip if (!hid_get_feature(dev, buf, CMD_ENABLE_PROGRAM)) return false; clear_buffer(buf, REPORT_SIZE); - // return true; // 06) Flash printf("Flashing device, please wait...\n"); @@ -509,7 +509,6 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip while ((bytes_read = fread(buf, 1, REPORT_SIZE, firmware)) > 0) { if (bytes_read < REPORT_SIZE) { fprintf(stderr, "WARNING: Read %zu bytes, expected %d bytes.\n", bytes_read, REPORT_SIZE); - exit(1); } if (!hid_set_feature(dev, buf, bytes_read)) return false; From f9670dd97645d2b89e795d741b9592f1dc779a54 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 6 Sep 2024 23:09:10 +0300 Subject: [PATCH 20/46] v2.0.2 bump --- sonixflasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index d588a61..39b3d67 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -68,7 +68,7 @@ #define MAX_ATTEMPTS 5 #define PROJECT_NAME "sonixflasher" -#define PROJECT_VER "2.0.1" +#define PROJECT_VER "2.0.2" uint16_t CS0 = 0; uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; From 6b011f611bd86ab93102e743f511b334742a8c43 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 11:48:46 +0300 Subject: [PATCH 21/46] fix command offsets --- sonixflasher.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 39b3d67..916d44d 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -387,7 +387,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_GET_FW_VERSION; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, code_option); + write_buffer_16(buf + 4, code_option); uint8_t attempt_no = 1; while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. { @@ -409,7 +409,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (oem_reboot && reboot_fail) { fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, 0); } else - fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_GET_FW_VERSION); + fprintf(stderr, "ERROR: Failed to initialize: response cmd is 0x%08x, expected 0x%08x.\n", resp, CMD_VERIFY(CMD_GET_FW_VERSION)); return false; } return true; @@ -422,7 +422,7 @@ bool protocol_code_option_check(hid_device *dev) { clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_COMPARE_CODE_OPTION; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, code_option); + write_buffer_16(buf + 4, code_option); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; clear_buffer(buf, REPORT_SIZE); return true; @@ -435,8 +435,8 @@ bool protocol_reset_cs(hid_device *dev) { clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_SET_ENCRYPTION_ALGO; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 3, code_option); - write_buffer_16(buf + 5, CS0); // WARNING THIS SETS CS0 + write_buffer_16(buf + 4, code_option); + write_buffer_16(buf + 6, CS0); // WARNING THIS SETS CS0 if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); From 7b7a96c41f3063308e08d6b32165df10ac9ddf1d Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 12:24:32 +0300 Subject: [PATCH 22/46] introduce a mechanism to retry if busy sometimes we poll too fast. Check if the device is busy and retry --- sonixflasher.c | 53 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 916d44d..5f5f968 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -66,6 +66,7 @@ #define APPLE_VID 0x05ac #define MAX_ATTEMPTS 5 +#define RETRY_DELAY_MS 100 #define PROJECT_NAME "sonixflasher" #define PROJECT_VER "2.0.2" @@ -314,28 +315,46 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { clear_buffer(data, sizeof(data)); int res = hid_get_feature_report(dev, data, REPORT_LENGTH); - if (res == REPORT_LENGTH) { - // Shift the data buffer to remove the first byte - memmove(data, data + 1, res - 1); + uint8_t attempt_no = 1; + while (attempt_no <= MAX_ATTEMPTS) { + clear_buffer(data, sizeof(data)); - if (debug) { - printf("Received payload...\n"); - print_data(data, res - 1); - } + // Attempt to get the feature report + res = hid_get_feature_report(dev, data, REPORT_LENGTH); + + if (res == REPORT_LENGTH) { + // Shift the data buffer to remove the first byte + memmove(data, data + 1, res - 1); + + if (debug) { + printf("Received payload...\n"); + print_data(data, res - 1); + } + + // Check the status directly in the data buffer + unsigned int status = *((unsigned int *)(data + 4)); + if (status != CMD_OK) { + fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02X.\n", status, CMD_OK, command & 0xFF); + return false; + } - // Check the status directly in the data buffer - unsigned int status = *((unsigned int *)(data + 4)); - if (status != CMD_OK) { - fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02X.\n", status, CMD_OK, command & 0xFF); + // Success + return true; + } else if (res < 0) { + // Error condition, such as abort pipe + fprintf(stderr, "ERROR: Device busy or failed to get feature report, retrying...\n"); + attempt_no++; + usleep(RETRY_DELAY_MS * 1000); // Delay before retrying + } else { + // Incorrect response length + fprintf(stderr, "ERROR: Invalid response length for command 0x%02X: got %d, expected %d.\n", command & 0xFF, res, REPORT_LENGTH); return false; } - // Success - return true; - - } else { - fprintf(stderr, "ERROR: Failed to get feature report for command 0x%02X: got response of length %d, expected %d.\n", command & 0xFF, res, REPORT_LENGTH); - return false; } + + // After retries failed + fprintf(stderr, "ERROR: Failed to get feature report for command 0x%02X after %d retries.\n", command & 0xFF, attempt_no); + return false; } bool send_magic_command(hid_device *dev, const uint32_t *command) { From af47949b8bd4bba93a38c01a96a9c6713b2e3a6e Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 14:58:53 +0300 Subject: [PATCH 23/46] file ops: do NOT keep it open until exit hopefully this fixes memory corruption --- sonixflasher.c | 138 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 40 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 5f5f968..b5261ef 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -488,7 +488,13 @@ bool protocol_reboot_user(hid_device *dev) { return true; } -bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip_offset_check) { +bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bool skip_offset_check) { + FILE *firmware = fopen(file_name, "rb"); + if (firmware == NULL) { + fprintf(stderr, "ERROR: Could not open firmware file (Does the file exist?).\n"); + return false; + } + unsigned char buf[REPORT_SIZE]; uint32_t resp = 0; @@ -534,6 +540,7 @@ bool flash(hid_device *dev, long offset, FILE *firmware, long fw_size, bool skip clear_buffer(buf, REPORT_SIZE); } clear_buffer(buf, REPORT_SIZE); + fclose(firmware); // 07) Verify flash complete printf("\n"); @@ -592,6 +599,90 @@ bool sanity_check_jumploader_firmware(long fw_size) { return true; } +long get_file_size(FILE *fp) { + if (fseek(fp, 0, SEEK_END) != 0) { + fprintf(stderr, "ERROR: Could not read EOF.\n"); + return -1; + } + + long file_size = ftell(fp); + if (file_size == -1L) { + fprintf(stderr, "ERROR: File size calculation failed.\n"); + return -1; + } + + // Reset file position to the beginning + if (fseek(fp, 0, SEEK_SET) != 0) { + fprintf(stderr, "ERROR: File size cleanup failed.\n"); + return -1; + } + + return file_size; +} + +long prepare_file_to_flash(const char *file_name, bool flash_jumploader) { + FILE *fp = fopen(file_name, "rb"); + if (fp == NULL) { + fprintf(stderr, "ERROR: Could not open file (Does the file exist?).\n"); + return -1; + } + + long file_size = get_file_size(fp); + if (file_size == -1L) { + fclose(fp); + return -1; + } + + if (file_size == 0) { + fprintf(stderr, "ERROR: File is empty.\n"); + fclose(fp); + return -1; + } + + printf("File size: %ld bytes\n", file_size); + + // If jumploader is not 0x200 in length, add padded zeroes to file + if (flash_jumploader && file_size < QMK_OFFSET_DEFAULT) { + printf("Warning: jumploader binary doesn't have a size of: 0x%04x bytes.\n", QMK_OFFSET_DEFAULT); + printf("Truncating jumploader binary to: 0x%04x.\n", QMK_OFFSET_DEFAULT); + + fclose(fp); + if (truncate(file_name, QMK_OFFSET_DEFAULT) != 0) { + fprintf(stderr, "ERROR: Could not truncate file.\n"); + return -1; + } + + // Reopen the file + fp = fopen(file_name, "rb"); + if (fp == NULL) { + fprintf(stderr, "ERROR: Could not open file after truncation.\n"); + return -1; + } + + // Recalculate file size + file_size = get_file_size(fp); + if (file_size == -1L) { + fclose(fp); + return -1; + } + } + + // Adjust file size to fit in the HID report + if (file_size % REPORT_SIZE != 0) { + printf("File size must be adjusted to fit in the HID report.\n"); + long padded_file_size = file_size; + printf("File size before padding: %ld bytes\n", padded_file_size); + while (padded_file_size % REPORT_SIZE != 0) { + padded_file_size++; + } + printf("File size after padding: %ld bytes\n", padded_file_size); + file_size = padded_file_size; + } + + fclose(fp); + return file_size; +} + int main(int argc, char *argv[]) { int opt, opt_index, res; hid_device *handle; @@ -704,40 +795,6 @@ int main(int argc, char *argv[]) { printf("Firmware to flash: %s with offset 0x%04lx, device: 0x%04x/0x%04x.\n", file_name, offset, vid, pid); - FILE *fp = fopen(file_name, "rb"); - - if (fp == NULL) { - fprintf(stderr, "ERROR: Could not open file (Does the file exist?).\n"); - fclose(fp); - exit(1); - } - - // Get file size - fseek(fp, 0, SEEK_END); - long file_size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - // if jumploader is not 0x200 in length, add padded zeroes to file - if (flash_jumploader && file_size < QMK_OFFSET_DEFAULT) { - printf("Warning: jumploader binary doesnt have a size of: 0x%04x bytes.\n", QMK_OFFSET_DEFAULT); - printf("Truncating jumploader binary to: 0x%04x.\n", QMK_OFFSET_DEFAULT); - - // Close device before truncating it - fclose(fp); - if (truncate(file_name, QMK_OFFSET_DEFAULT) != 0) { - fprintf(stderr, "ERROR: Could not truncate file.\n"); - exit(1); - } - - // Try open the file again. - fp = fopen(file_name, "rb"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Could not open file.\n"); - fclose(fp); - exit(1); - } - } - // Try to open the device res = hid_init(); printf("\n"); @@ -785,10 +842,12 @@ int main(int argc, char *argv[]) { if (!ok) exit(1); sleep(1); - while (file_size % REPORT_SIZE != 0) - file_size++; // Add padded zereos (if any) to file_size, we need to take in consideration when the file doesnt fill the buffer. - - if (((flash_jumploader && sanity_check_jumploader_firmware(file_size)) || (!flash_jumploader && sanity_check_firmware(file_size, offset))) && (flash(handle, offset, fp, file_size, no_offset_check))) { + long prepared_file_size = prepare_file_to_flash(file_name, flash_jumploader); + if (prepared_file_size < 0) { + fprintf(stderr, "ERROR: File preparation failed.\n"); + exit(1); + } + if (((flash_jumploader && sanity_check_jumploader_firmware(prepared_file_size)) || (!flash_jumploader && sanity_check_firmware(prepared_file_size, offset))) && (flash(handle, offset, file_name, prepared_file_size, no_offset_check))) { printf("Device succesfully flashed!\n"); sleep(3); protocol_reboot_user(handle); @@ -801,7 +860,6 @@ int main(int argc, char *argv[]) { exit(1); } - fclose(fp); hid_close(handle); res = hid_exit(); From 87e77f6e6c0c8433d8d58ee7ecf2ecfa2398936f Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 15:19:01 +0300 Subject: [PATCH 24/46] always cleanup on exit --- sonixflasher.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index b5261ef..bb405bb 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -683,8 +683,20 @@ long prepare_file_to_flash(const char *file_name, bool flash_jumploader) { return file_size; } +void cleanup(hid_device *handle) { + if (handle) hid_close(handle); + if (hid_exit() != 0) { + fprintf(stderr, "ERROR: Could not close the device.\n"); + } +} + +void error(hid_device *handle) { + cleanup(handle); + exit(1); +} + int main(int argc, char *argv[]) { - int opt, opt_index, res; + int opt, opt_index; hid_device *handle; uint16_t vid = 0; @@ -796,7 +808,10 @@ int main(int argc, char *argv[]) { printf("Firmware to flash: %s with offset 0x%04lx, device: 0x%04x/0x%04x.\n", file_name, offset, vid, pid); // Try to open the device - res = hid_init(); + if (hid_init() < 0) { + fprintf(stderr, "ERROR: Could not initialize HID.\n"); + exit(1); + } printf("\n"); printf("\n"); printf("Opening device...\n"); @@ -830,22 +845,22 @@ int main(int argc, char *argv[]) { ok = protocol_init(handle, reboot_requested, reboot_opt); attempt_no++; } - if (!ok) exit(1); + if (!ok) error(handle); sleep(3); if (chip == SN240 || chip == SN290) ok = protocol_code_option_check(handle); // 240 and 290 - if (!ok) exit(1); + if (!ok) error(handle); sleep(1); if (cs_level != CS0) ok = protocol_reset_cs(handle); - if (!ok) exit(1); + if (!ok) error(handle); sleep(1); if (chip == SN240 || chip == SN290) ok = erase_flash(handle); - if (!ok) exit(1); + if (!ok) error(handle); sleep(1); long prepared_file_size = prepare_file_to_flash(file_name, flash_jumploader); if (prepared_file_size < 0) { fprintf(stderr, "ERROR: File preparation failed.\n"); - exit(1); + error(handle); } if (((flash_jumploader && sanity_check_jumploader_firmware(prepared_file_size)) || (!flash_jumploader && sanity_check_firmware(prepared_file_size, offset))) && (flash(handle, offset, file_name, prepared_file_size, no_offset_check))) { printf("Device succesfully flashed!\n"); @@ -853,19 +868,13 @@ int main(int argc, char *argv[]) { protocol_reboot_user(handle); } else { fprintf(stderr, "ERROR: Could not flash the device. Try again.\n"); - exit(1); + error(handle); } } else { fprintf(stderr, "ERROR: Could not open the device (Is the device connected?).\n"); - exit(1); - } - - hid_close(handle); - res = hid_exit(); - - if (res < 0) { - fprintf(stderr, "ERROR: Could not close the device.\n"); + error(handle); } + cleanup(handle); exit(0); } From 80cb4d19e634214980f252b46c3b9c0ece9d143c Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 15:47:26 +0300 Subject: [PATCH 25/46] document --noofset --- sonixflasher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index bb405bb..3468aaf 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -106,7 +106,8 @@ static void print_usage(char *m_name) { " --jumploader -j Define if we are flashing a jumploader \n" " --reboot -r Request bootloader reboot in OEM firmware (options: evision, hfd) \n" " --debug -d Enable debug mode \n" - " --list-vidpid -l Display supported VID/PID pairs\n" + " --nooffset -k Disable offset checks \n" + " --list-vidpid -l Display supported VID/PID pairs \n" " --version -V Print version information \n" "\n" "Examples: \n" From c92049897c499feea094ce643165c2b71adf5c3c Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 16:19:43 +0300 Subject: [PATCH 26/46] update the docs --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- sonixflasher.c | 12 ++++++------ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d1e33ed..7c2b62c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Sonix Flasher C -A CLI-based Flasher for Sonix 24x/26x MCUs. +A CLI-based Flasher for Sonix SN32F2xx MCUs. ## Description @@ -39,6 +39,50 @@ make sonixflasher ./sonixflasher ``` +#### Command List: + +- `--vidpid -v` Set VID and PID for the device to flash. +- `--offset -o` Set flashing offset (default: 0). +- `--file -f` Binary of the firmware to flash (*.bin extension). +- `--jumploader -j` Define if flashing a jumploader. +- `--reboot -r` Request bootloader reboot in OEM firmware (options: evision, hfd). +- `--debug -d` Enable debug mode. +- `--list-vidpid -l` Display supported VID/PID pairs. +- `--nooffset -k` Disable offset checks. +- `--version -V` Print version information. +- `--help -h` Show this help message. + +#### ISP Bootloader Mode Defaults: + ++-----------------+--------+--------+ +| Device | VID | PID | ++-----------------+--------+--------+ +| SONIX SN32F26x | 0x0C45 | 0x7010 | +| SONIX SN32F24xB | 0x0C45 | 0x7040 | +| SONIX SN32F24xC | 0x0C45 | 0x7145 | +| SONIX SN32F24x | 0x0C45 | 0x7900 | +| SONIX SN32F28x | 0x0C45 | 0x7120 | +| SONIX SN32F29x | 0x0C45 | 0x7140 | ++-----------------+--------+--------+ + +Notice that some devices support flashing while booted. In that case, use +``` +--reboot +``` +to expose the ISP mode + +## Usage Examples + +- **Flash jumploader to device with VID/PID 0x0c45/0x7040:** + + ``` + sonixflasher --vidpid 0c45/7040 --file fw.bin -j + ``` +- **Flash firmware to device with VID/PID 0x0c45/0x7040 and offset 0x200:** + + ``` + sonixflasher --vidpid 0c45/7040 --file fw.bin -o 0x200 + ``` ## License diff --git a/sonixflasher.c b/sonixflasher.c index 3468aaf..c4b1083 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -86,12 +86,12 @@ static void print_vidpid_table() { printf("+-----------------+------------+------------+\n"); printf("| Device | VID | PID |\n"); printf("+-----------------+------------+------------+\n"); - printf("| SONIX SN26x | 0x%04X | 0x%04X |\n", SONIX_VID, SN268_PID); - printf("| SONIX SN24xB | 0x%04X | 0x%04X |\n", SONIX_VID, SN248B_PID); - printf("| SONIX SN24xC | 0x%04X | 0x%04X |\n", SONIX_VID, SN248C_PID); - printf("| SONIX SN24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN248_PID); - printf("| SONIX SN28x | 0x%04X | 0x%04X |\n", SONIX_VID, SN289_PID); - printf("| SONIX SN29x | 0x%04X | 0x%04X |\n", SONIX_VID, SN299_PID); + printf("| SONIX SN32F26x | 0x%04X | 0x%04X |\n", SONIX_VID, SN268_PID); + printf("| SONIX SN32F24xB | 0x%04X | 0x%04X |\n", SONIX_VID, SN248B_PID); + printf("| SONIX SN32F24xC | 0x%04X | 0x%04X |\n", SONIX_VID, SN248C_PID); + printf("| SONIX SN32F24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN248_PID); + printf("| SONIX SN32F28x | 0x%04X | 0x%04X |\n", SONIX_VID, SN289_PID); + printf("| SONIX SN32F29x | 0x%04X | 0x%04X |\n", SONIX_VID, SN299_PID); printf("+-----------------+------------+------------+\n"); } From 782c13ef6ee322ce03d45d73f9e38c40221d85b9 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 17:34:24 +0300 Subject: [PATCH 27/46] standardize logging setup --- sonixflasher.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index c4b1083..57f139a 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -166,7 +166,6 @@ void print_data(const unsigned char *data, int length) { printf("%02x ", data[i]); } printf("\n"); - printf("\n"); } bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { @@ -176,6 +175,7 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { } if (debug) { + printf("\n"); printf("Sending payload...\n"); print_data(data, length); } @@ -194,13 +194,13 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { // Send the feature report using the temporary buffer if (hid_send_feature_report(dev, temp_buf, length + 1) < 0) { - fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", data[0], hid_error(dev)); + fprintf(stderr, "ERROR: Error while writing command 0x%02x! Reason: %ls\n", data[0], hid_error(dev)); return false; } } else { // Send the report as is if (hid_send_feature_report(dev, data, length) < 0) { - fprintf(stderr, "ERROR: Error while writing command %0x2X! Reason: %ls\n", data[0], hid_error(dev)); + fprintf(stderr, "ERROR: Error while writing command 0x%02x! Reason: %ls\n", data[0], hid_error(dev)); return false; } } @@ -210,12 +210,13 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { int sn32_decode_chip(unsigned char *data) { if (data[8] == 32) { printf("Sonix SN32 Detected.\n"); - printf("Checking variant...\n"); + printf("\n"); + printf("Checking variant... "); sleep(2); int sn32_variant; switch (data[9]) { case SN240: - printf("240 Detected.\n"); + printf("240 Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -223,7 +224,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN240; break; case SN260: - printf("260 Detected.\n"); + printf("260 Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -231,7 +232,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN260; break; case SN240B: - printf("240B Detected.\n"); + printf("240B Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F240B; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240B; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -239,7 +240,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN240B; break; case SN280: - printf("280 Detected.\n"); + printf("280 Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F280; USER_ROM_PAGES = USER_ROM_PAGES_SN32F280; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -247,7 +248,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN280; break; case SN290: - printf("290 Detected.\n"); + printf("290 Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; USER_ROM_PAGES = USER_ROM_PAGES_SN32F290; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -255,7 +256,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN290; break; case SN240C: - printf("240C Detected. \n"); + printf("240C Detected!\n"); USER_ROM_SIZE = USER_ROM_SIZE_SN32F240C; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240C; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); @@ -263,6 +264,7 @@ int sn32_decode_chip(unsigned char *data) { sn32_variant = SN240C; break; default: + printf("\n"); fprintf(stderr, "ERROR: Unsupported bootloader version: %d, we don't support this chip.\n", data[9]); sn32_variant = 0; break; @@ -305,7 +307,7 @@ uint16_t sn32_get_cs_level(unsigned char *data) { printf("Current Security level: CS3. \n"); break; default: - fprintf(stderr, "ERROR: Unsupported Security level: %04x, we don't support this chip.\n", combined_cs); + fprintf(stderr, "ERROR: Unsupported Security level: 0x%04X, we don't support this chip.\n", combined_cs); break; } } @@ -328,6 +330,7 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { memmove(data, data + 1, res - 1); if (debug) { + printf("\n"); printf("Received payload...\n"); print_data(data, res - 1); } @@ -335,7 +338,7 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { // Check the status directly in the data buffer unsigned int status = *((unsigned int *)(data + 4)); if (status != CMD_OK) { - fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02X.\n", status, CMD_OK, command & 0xFF); + fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02x.\n", status, CMD_OK, command & 0xFF); return false; } @@ -348,13 +351,13 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { usleep(RETRY_DELAY_MS * 1000); // Delay before retrying } else { // Incorrect response length - fprintf(stderr, "ERROR: Invalid response length for command 0x%02X: got %d, expected %d.\n", command & 0xFF, res, REPORT_LENGTH); + fprintf(stderr, "ERROR: Invalid response length for command 0x%02x: got %d, expected %d.\n", command & 0xFF, res, REPORT_LENGTH); return false; } } // After retries failed - fprintf(stderr, "ERROR: Failed to get feature report for command 0x%02X after %d retries.\n", command & 0xFF, attempt_no); + fprintf(stderr, "ERROR: Failed to get feature report for command 0x%02x after %d retries.\n", command & 0xFF, attempt_no); return false; } @@ -402,6 +405,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { } // 01) Initialize + printf("\n"); printf("Fetching flash version...\n"); sleep(2); clear_buffer(buf, REPORT_SIZE); @@ -438,6 +442,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { bool protocol_code_option_check(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 02) Prepare for Code Option Table check + printf("\n"); printf("Checking Code Option Table...\n"); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_COMPARE_CODE_OPTION; @@ -451,7 +456,9 @@ bool protocol_code_option_check(hid_device *dev) { bool protocol_reset_cs(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 03) Reset Code Option Table + printf("\n"); printf("Resetting Code Option Table...\n"); + printf("Setting Code Option Table 0x%04x with CS 0x%04X.\n", code_option, CS0); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_SET_ENCRYPTION_ALGO; write_buffer_16(buf + 1, CMD_BASE); @@ -466,6 +473,7 @@ bool protocol_reset_cs(hid_device *dev) { bool erase_flash(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 04) Erase flash + printf("\n"); printf("Erasing flash...\n"); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_ENABLE_ERASE; @@ -480,6 +488,7 @@ bool erase_flash(hid_device *dev) { bool protocol_reboot_user(hid_device *dev) { unsigned char buf[REPORT_SIZE]; // 08) Reboot to User Mode + printf("\n"); printf("Flashing done. Rebooting.\n"); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_RETURN_USER_MODE; @@ -639,7 +648,7 @@ long prepare_file_to_flash(const char *file_name, bool flash_jumploader) { fclose(fp); return -1; } - + printf("\n"); printf("File size: %ld bytes\n", file_size); // If jumploader is not 0x200 in length, add padded zeroes to file From 1ad3487101f8a42d02d005c63fff52d61df83e9d Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 7 Sep 2024 17:34:49 +0300 Subject: [PATCH 28/46] v2.0.3 --- sonixflasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index 57f139a..8724fd7 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -69,7 +69,7 @@ #define RETRY_DELAY_MS 100 #define PROJECT_NAME "sonixflasher" -#define PROJECT_VER "2.0.2" +#define PROJECT_VER "2.0.3" uint16_t CS0 = 0; uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; From bbd493d78e2bb36f775dbb3b5a1f3f64807a32dd Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 11:34:17 +0300 Subject: [PATCH 29/46] support sn32f220 and sn32f230 --- sonixflasher.c | 60 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 8724fd7..9fe305e 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -12,6 +12,8 @@ #define REPORT_SIZE 64 #define REPORT_LENGTH (REPORT_SIZE + 1) #define USER_ROM_SIZE_SN32F260 30 // in KB +#define USER_ROM_SIZE_SN32F220 16 // in KB +#define USER_ROM_SIZE_SN32F230 32 // in KB #define USER_ROM_SIZE_SN32F240 64 // in KB #define USER_ROM_SIZE_SN32F240B 64 // in KB #define USER_ROM_SIZE_SN32F240C 128 // in KB @@ -20,6 +22,8 @@ #define USER_ROM_SIZE_KB(x) ((x) * 1024) #define USER_ROM_PAGES_SN32F260 480 +#define USER_ROM_PAGES_SN32F220 16 +#define USER_ROM_PAGES_SN32F230 32 #define USER_ROM_PAGES_SN32F240 64 #define USER_ROM_PAGES_SN32F240B 1024 #define USER_ROM_PAGES_SN32F240C 128 @@ -208,20 +212,46 @@ bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { return true; } int sn32_decode_chip(unsigned char *data) { + // data[8-11] holds the bootloader version if (data[8] == 32) { printf("Sonix SN32 Detected.\n"); printf("\n"); printf("Checking variant... "); sleep(2); - int sn32_variant; + int sn32_family; switch (data[9]) { case SN240: - printf("240 Detected!\n"); - USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; - USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; - MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; - sn32_variant = SN240; + switch (data[11]) { + case 1: + printf("220 Detected!\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F220; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F220; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_family = SN240; + break; + case 2: + printf("230 Detected!\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F230; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F230; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_family = SN240; + break; + case 3: + printf("240 Detected!\n"); + USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; + USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; + MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); + CS0 = 0xFFFF; + sn32_family = SN240; + break; + default: + printf("\n"); + fprintf(stderr, "ERROR: Unsupported 2xx variant: %d.%d.%d, we don't support this chip.\n", data[9], data[10], data[11]); + sn32_family = 0; + break; + } break; case SN260: printf("260 Detected!\n"); @@ -229,7 +259,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = 0; - sn32_variant = SN260; + sn32_family = SN260; break; case SN240B: printf("240B Detected!\n"); @@ -237,7 +267,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F240B; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = 0; - sn32_variant = SN240B; + sn32_family = SN240B; break; case SN280: printf("280 Detected!\n"); @@ -245,7 +275,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F280; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = 0xFFFF; - sn32_variant = SN280; + sn32_family = SN280; break; case SN290: printf("290 Detected!\n"); @@ -253,7 +283,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F290; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = 0xFFFF; - sn32_variant = SN290; + sn32_family = SN290; break; case SN240C: printf("240C Detected!\n"); @@ -261,16 +291,16 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F240C; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = 0xFFFF; - sn32_variant = SN240C; + sn32_family = SN240C; break; default: printf("\n"); - fprintf(stderr, "ERROR: Unsupported bootloader version: %d, we don't support this chip.\n", data[9]); - sn32_variant = 0; + fprintf(stderr, "ERROR: Unsupported bootloader version: %d.%d.%d, we don't support this chip.\n", data[9], data[10], data[11]); + sn32_family = 0; break; } - return sn32_variant; + return sn32_family; } else { fprintf(stderr, "ERROR: Unsupported family version: %d, we don't support this chip.\n", data[8]); return 0; From 1df4c8afdf6fdf97d577216e9ca7ee6400333927 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 12:14:23 +0300 Subject: [PATCH 30/46] cleanup security level checks --- sonixflasher.c | 76 +++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 9fe305e..33a9ffd 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -54,6 +54,9 @@ #define SN290 5 #define SN240C 6 +#define CS0_0 0x0000 +#define CS0_1 0xFFFF + #define CS1 0x5A5A #define CS2 0xA5A5 #define CS3 0x55AA @@ -75,7 +78,7 @@ #define PROJECT_NAME "sonixflasher" #define PROJECT_VER "2.0.3" -uint16_t CS0 = 0; +uint16_t CS0 = CS0_0; uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); @@ -83,7 +86,7 @@ bool flash_jumploader = false; bool debug = false; static uint16_t code_option = 0x0000; // Initial Code Option Table int chip; -uint16_t cs_level; +int cs_level; static void print_vidpid_table() { printf("Supported VID/PID pairs:\n"); @@ -227,7 +230,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F220; USER_ROM_PAGES = USER_ROM_PAGES_SN32F220; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN240; break; case 2: @@ -235,7 +238,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F230; USER_ROM_PAGES = USER_ROM_PAGES_SN32F230; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN240; break; case 3: @@ -243,7 +246,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F240; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN240; break; default: @@ -258,7 +261,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0; + CS0 = CS0_0; sn32_family = SN260; break; case SN240B: @@ -266,7 +269,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F240B; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240B; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0; + CS0 = CS0_0; sn32_family = SN240B; break; case SN280: @@ -274,7 +277,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F280; USER_ROM_PAGES = USER_ROM_PAGES_SN32F280; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN280; break; case SN290: @@ -282,7 +285,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F290; USER_ROM_PAGES = USER_ROM_PAGES_SN32F290; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN290; break; case SN240C: @@ -290,7 +293,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_SIZE = USER_ROM_SIZE_SN32F240C; USER_ROM_PAGES = USER_ROM_PAGES_SN32F240C; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); - CS0 = 0xFFFF; + CS0 = CS0_1; sn32_family = SN240C; break; default: @@ -319,29 +322,31 @@ bool sn32_check_isp_code_option(unsigned char *data) { return true; } -uint16_t sn32_get_cs_level(unsigned char *data) { - cs_level = 0; - uint16_t combined_cs = (data[14] << 8) | data[15]; - - if (combined_cs == CS0) { - printf("Current Security level: CS0. \n"); - } else { - switch (combined_cs) { - case CS1: - printf("Current Security level: CS1. \n"); - break; - case CS2: - printf("Current Security level: CS2. \n"); - break; - case CS3: - printf("Current Security level: CS3. \n"); - break; - default: - fprintf(stderr, "ERROR: Unsupported Security level: 0x%04X, we don't support this chip.\n", combined_cs); - break; - } - } - return combined_cs; +int sn32_get_code_security(unsigned char *data) { + cs_level = -1; + uint16_t cs_value = (data[14] << 8) | data[15]; + + switch (cs_value) { + case CS0_0: + case CS0_1: + cs_level = 0; + break; + case CS1: + cs_level = 1; + break; + case CS2: + cs_level = 2; + break; + case CS3: + cs_level = 3; + break; + default: + fprintf(stderr, "ERROR: Unsupported Code Security value: 0x%04X, we don't support this chip.\n", cs_value); + return cs_level; + } + + printf("Current Security level: CS%d. Code Security value: 0x%04X.\n", cs_level, cs_value); + return cs_level; } bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { @@ -454,7 +459,8 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; chip = sn32_decode_chip(buf); if (chip == 0) return false; - cs_level = sn32_get_cs_level(buf); + cs_level = sn32_get_code_security(buf); + if (cs_level < 0) return false; if (!sn32_check_isp_code_option(buf)) return false; bool reboot_fail = !read_response_32(buf, 0, 0, &resp); @@ -890,7 +896,7 @@ int main(int argc, char *argv[]) { if (chip == SN240 || chip == SN290) ok = protocol_code_option_check(handle); // 240 and 290 if (!ok) error(handle); sleep(1); - if (cs_level != CS0) ok = protocol_reset_cs(handle); + if (cs_level != 0) ok = protocol_reset_cs(handle); if (!ok) error(handle); sleep(1); if (chip == SN240 || chip == SN290) ok = erase_flash(handle); From 4cac294c525760faf5c7e43e4f76c9b972582b2b Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 13:17:24 +0300 Subject: [PATCH 31/46] fixup protocol checks for 240b and 260 --- sonixflasher.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 33a9ffd..240cb23 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -893,13 +893,13 @@ int main(int argc, char *argv[]) { } if (!ok) error(handle); sleep(3); - if (chip == SN240 || chip == SN290) ok = protocol_code_option_check(handle); // 240 and 290 + if (chip != SN240B && chip != SN260) ok = protocol_code_option_check(handle); if (!ok) error(handle); sleep(1); if (cs_level != 0) ok = protocol_reset_cs(handle); if (!ok) error(handle); sleep(1); - if (chip == SN240 || chip == SN290) ok = erase_flash(handle); + if (chip != SN240B && chip != SN260) ok = erase_flash(handle); if (!ok) error(handle); sleep(1); From 729c66278a9250d028e3ff9e4922b1abc6c386e2 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 13:26:19 +0300 Subject: [PATCH 32/46] abstract page erase --- sonixflasher.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 240cb23..0e3734e 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -506,15 +506,16 @@ bool protocol_reset_cs(hid_device *dev) { return true; } -bool erase_flash(hid_device *dev) { +bool erase_flash(hid_device *dev, uint16_t page_start, uint16_t page_end) { unsigned char buf[REPORT_SIZE]; // 04) Erase flash printf("\n"); - printf("Erasing flash...\n"); + printf("Erasing flash from page %u to page %u...\n", page_start, page_end); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_ENABLE_ERASE; write_buffer_16(buf + 1, CMD_BASE); - write_buffer_16(buf + 8, USER_ROM_PAGES); + write_buffer_16(buf + 4, page_start); + write_buffer_16(buf + 8, page_end); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_ENABLE_ERASE)) return false; clear_buffer(buf, REPORT_SIZE); @@ -899,7 +900,7 @@ int main(int argc, char *argv[]) { if (cs_level != 0) ok = protocol_reset_cs(handle); if (!ok) error(handle); sleep(1); - if (chip != SN240B && chip != SN260) ok = erase_flash(handle); + if (chip != SN240B && chip != SN260) ok = erase_flash(handle, 0, USER_ROM_PAGES); if (!ok) error(handle); sleep(1); From 9d00b376489e2284cf20b88c609bb66433e42f4e Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 13:42:57 +0300 Subject: [PATCH 33/46] refactor cs reset --- sonixflasher.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 0e3734e..e31ca02 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -489,17 +489,16 @@ bool protocol_code_option_check(hid_device *dev) { return true; } -bool protocol_reset_cs(hid_device *dev) { +bool protocol_code_option_set(hid_device *dev, uint16_t code_option, uint16_t cs_value) { unsigned char buf[REPORT_SIZE]; - // 03) Reset Code Option Table + // 03) Set Code Option Table printf("\n"); - printf("Resetting Code Option Table...\n"); - printf("Setting Code Option Table 0x%04x with CS 0x%04X.\n", code_option, CS0); + printf("Setting Code Option Table 0x%04x with Code Security value 0x%04X...\n", code_option, cs_value); clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_SET_ENCRYPTION_ALGO; write_buffer_16(buf + 1, CMD_BASE); write_buffer_16(buf + 4, code_option); - write_buffer_16(buf + 6, CS0); // WARNING THIS SETS CS0 + write_buffer_16(buf + 6, cs_value); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); @@ -897,7 +896,10 @@ int main(int argc, char *argv[]) { if (chip != SN240B && chip != SN260) ok = protocol_code_option_check(handle); if (!ok) error(handle); sleep(1); - if (cs_level != 0) ok = protocol_reset_cs(handle); + if (cs_level != 0) { + printf("Resetting Code Security from CS%d to CS%d...\n", cs_level, 0); + ok = protocol_code_option_set(handle, code_option, CS0); + } if (!ok) error(handle); sleep(1); if (chip != SN240B && chip != SN260) ok = erase_flash(handle, 0, USER_ROM_PAGES); From 42406c7831f80973e1fa60bd7b0b8b821a6345fd Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 13:57:12 +0300 Subject: [PATCH 34/46] fixup buffer size handling in hid_get_feature --- sonixflasher.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index e31ca02..4979053 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -349,13 +349,13 @@ int sn32_get_code_security(unsigned char *data) { return cs_level; } -bool hid_get_feature(hid_device *dev, unsigned char *data, uint32_t command) { - clear_buffer(data, sizeof(data)); +bool hid_get_feature(hid_device *dev, unsigned char *data, size_t data_size, uint32_t command) { + clear_buffer(data, data_size); int res = hid_get_feature_report(dev, data, REPORT_LENGTH); uint8_t attempt_no = 1; while (attempt_no <= MAX_ATTEMPTS) { - clear_buffer(data, sizeof(data)); + clear_buffer(data, data_size); // Attempt to get the feature report res = hid_get_feature_report(dev, data, REPORT_LENGTH); @@ -456,7 +456,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { } if (attempt_no > MAX_ATTEMPTS) return false; - if (!hid_get_feature(dev, buf, CMD_GET_FW_VERSION)) return false; + if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_GET_FW_VERSION)) return false; chip = sn32_decode_chip(buf); if (chip == 0) return false; cs_level = sn32_get_code_security(buf); @@ -500,7 +500,7 @@ bool protocol_code_option_set(hid_device *dev, uint16_t code_option, uint16_t cs write_buffer_16(buf + 4, code_option); write_buffer_16(buf + 6, cs_value); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf, CMD_SET_ENCRYPTION_ALGO)) return false; + if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_SET_ENCRYPTION_ALGO)) return false; clear_buffer(buf, REPORT_SIZE); return true; } @@ -516,7 +516,7 @@ bool erase_flash(hid_device *dev, uint16_t page_start, uint16_t page_end) { write_buffer_16(buf + 4, page_start); write_buffer_16(buf + 8, page_end); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf, CMD_ENABLE_ERASE)) return false; + if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_ENABLE_ERASE)) return false; clear_buffer(buf, REPORT_SIZE); return true; } @@ -569,7 +569,7 @@ bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bo write_buffer_32(buf + 8, (uint32_t)(fw_size / REPORT_SIZE)); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; - if (!hid_get_feature(dev, buf, CMD_ENABLE_PROGRAM)) return false; + if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_ENABLE_PROGRAM)) return false; clear_buffer(buf, REPORT_SIZE); // 06) Flash @@ -591,7 +591,7 @@ bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bo // 07) Verify flash complete printf("\n"); printf("Verifying flash completion...\n"); - if (!hid_get_feature(dev, buf, CMD_ENABLE_PROGRAM)) return false; + if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_ENABLE_PROGRAM)) return false; if (read_response_32(buf, (sizeof(buf) - sizeof(VALID_FW)), VALID_FW, &resp)) { printf("Flash completion verified. \n"); return true; From e45924ec24c657bdefe22e3496470fbe268dd8c9 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 14:48:47 +0300 Subject: [PATCH 35/46] ensure we're checking the correct reply --- sonixflasher.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 4979053..840b47d 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -44,7 +44,7 @@ #define CMD_GET_CS 0x9 #define CMD_VERIFY(x) ((CMD_BASE << 8) | (x)) -#define CMD_OK 0xFAFAFAFA +#define CMD_ACK 0xFAFAFAFA #define VALID_FW 0xAAAA5555 #define SN240 1 @@ -371,14 +371,20 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, size_t data_size, uin } // Check the status directly in the data buffer - unsigned int status = *((unsigned int *)(data + 4)); - if (status != CMD_OK) { - fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02x.\n", status, CMD_OK, command & 0xFF); + unsigned int cmdreply = *((unsigned int *)(data)); + unsigned int status = *((unsigned int *)(data + 4)); + if (cmdreply == CMD_VERIFY(command)) { + if (status != CMD_ACK) { + fprintf(stderr, "ERROR: Invalid response status: 0x%08x, expected 0x%08x for command 0x%02x.\n", status, CMD_ACK, command & 0xFF); + return false; + } + + // Success + return true; + } else { + fprintf(stderr, "ERROR: Invalid response command: 0x%08x, expected command 0x%02x.\n", cmdreply, command & 0xFF); return false; } - - // Success - return true; } else if (res < 0) { // Error condition, such as abort pipe fprintf(stderr, "ERROR: Device busy or failed to get feature report, retrying...\n"); From a16c308929c4e74a49e90a3a5a64873723a36118 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 15:08:59 +0300 Subject: [PATCH 36/46] add 220 and 230 pids, refactor pid check --- sonixflasher.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 840b47d..3b84e5f 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -62,10 +62,12 @@ #define CS3 0x55AA #define SONIX_VID 0x0c45 -#define SN268_PID 0x7010 +#define SN229_PID 0x7900 +#define SN239_PID SN229_PID +#define SN249_PID SN229_PID #define SN248B_PID 0x7040 #define SN248C_PID 0x7145 -#define SN248_PID 0x7900 +#define SN268_PID 0x7010 #define SN289_PID 0x7120 #define SN299_PID 0x7140 @@ -78,25 +80,28 @@ #define PROJECT_NAME "sonixflasher" #define PROJECT_VER "2.0.3" -uint16_t CS0 = CS0_0; -uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; -uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; -long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); -bool flash_jumploader = false; -bool debug = false; -static uint16_t code_option = 0x0000; // Initial Code Option Table -int chip; -int cs_level; - -static void print_vidpid_table() { +uint16_t CS0 = CS0_0; +uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; +uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; +long MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE_SN32F260); +bool flash_jumploader = false; +bool debug = false; +static uint16_t code_option = 0x0000; // Initial Code Option Table +int chip; +int cs_level; +const unsigned int known_isp_pids[] = {SN229_PID, SN239_PID, SN248B_PID, SN248C_PID, SN268_PID, SN289_PID, SN299_PID}; + +static void print_vidpid_table() { printf("Supported VID/PID pairs:\n"); printf("+-----------------+------------+------------+\n"); printf("| Device | VID | PID |\n"); printf("+-----------------+------------+------------+\n"); - printf("| SONIX SN32F26x | 0x%04X | 0x%04X |\n", SONIX_VID, SN268_PID); + printf("| SONIX SN32F22x | 0x%04X | 0x%04X |\n", SONIX_VID, SN229_PID); + printf("| SONIX SN32F23x | 0x%04X | 0x%04X |\n", SONIX_VID, SN239_PID); + printf("| SONIX SN32F24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN249_PID); printf("| SONIX SN32F24xB | 0x%04X | 0x%04X |\n", SONIX_VID, SN248B_PID); printf("| SONIX SN32F24xC | 0x%04X | 0x%04X |\n", SONIX_VID, SN248C_PID); - printf("| SONIX SN32F24x | 0x%04X | 0x%04X |\n", SONIX_VID, SN248_PID); + printf("| SONIX SN32F26x | 0x%04X | 0x%04X |\n", SONIX_VID, SN268_PID); printf("| SONIX SN32F28x | 0x%04X | 0x%04X |\n", SONIX_VID, SN289_PID); printf("| SONIX SN32F29x | 0x%04X | 0x%04X |\n", SONIX_VID, SN299_PID); printf("+-----------------+------------+------------+\n"); @@ -175,6 +180,16 @@ void print_data(const unsigned char *data, int length) { printf("\n"); } +bool is_known_isp_pid(unsigned int pid) { + size_t num_known_pids = sizeof(known_isp_pids) / sizeof(known_isp_pids[0]); + for (size_t i = 0; i < num_known_pids; ++i) { + if (pid == known_isp_pids[i]) { + return true; + } + } + return false; +} + bool hid_set_feature(hid_device *dev, unsigned char *data, size_t length) { if (length > REPORT_SIZE) { fprintf(stderr, "ERROR: Report can't be more than %d bytes!! (Attempted: %zu bytes)\n", REPORT_SIZE, length); @@ -883,7 +898,7 @@ int main(int argc, char *argv[]) { printf("Device opened successfully...\n"); // Check VID/PID - if (vid != SONIX_VID || (pid != SN248_PID && pid != SN248B_PID && pid != SN248C_PID && pid != SN268_PID && pid != SN289_PID && pid != SN299_PID)) { + if (vid != SONIX_VID || !is_known_isp_pid(pid)) { if (vid == EVISION_VID && !reboot_requested) printf("Warning: eVision VID detected! You probably need to use the reboot option.\n"); if (vid == APPLE_VID && !reboot_requested) printf("Warning: Apple VID detected! You probably need to use the reboot option.\n"); printf("Warning: Flashing a non-sonix bootloader device, you are now on your own.\n"); From 0380ae049cb3b2c1cab0ab83a128eb9a297f0321 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 19:20:49 +0300 Subject: [PATCH 37/46] add flash erase verification --- sonixflasher.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 3b84e5f..bcb3a3e 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -80,6 +80,7 @@ #define PROJECT_NAME "sonixflasher" #define PROJECT_VER "2.0.3" +uint16_t BLANK_CHECKSUM = 0x0000; uint16_t CS0 = CS0_0; uint16_t USER_ROM_SIZE = USER_ROM_SIZE_SN32F260; uint16_t USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; @@ -91,7 +92,7 @@ int chip; int cs_level; const unsigned int known_isp_pids[] = {SN229_PID, SN239_PID, SN248B_PID, SN248C_PID, SN268_PID, SN289_PID, SN299_PID}; -static void print_vidpid_table() { +static void print_vidpid_table() { printf("Supported VID/PID pairs:\n"); printf("+-----------------+------------+------------+\n"); printf("| Device | VID | PID |\n"); @@ -150,6 +151,15 @@ void print_buffer(unsigned char *data, size_t length) { printf("\n"); } +bool read_response_16(unsigned char *data, uint32_t offset, uint16_t expected_result, uint16_t *resp) { + uint16_t r = *resp; + + memcpy(&r, data + offset, sizeof(uint16_t)); + + *resp = r; + return r == expected_result; +} + bool read_response_32(unsigned char *data, uint32_t offset, uint32_t expected_result, uint32_t *resp) { uint32_t r = *resp; @@ -246,6 +256,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F220; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0xe000; sn32_family = SN240; break; case 2: @@ -254,6 +265,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F230; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0xc000; sn32_family = SN240; break; case 3: @@ -262,6 +274,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F240; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0x8000; sn32_family = SN240; break; default: @@ -277,6 +290,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F260; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_0; + BLANK_CHECKSUM = 0x8000; sn32_family = SN260; break; case SN240B: @@ -285,6 +299,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F240B; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_0; + BLANK_CHECKSUM = 0x8000; sn32_family = SN240B; break; case SN280: @@ -293,6 +308,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F280; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0x0000; sn32_family = SN280; break; case SN290: @@ -301,6 +317,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F290; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0x0000; sn32_family = SN290; break; case SN240C: @@ -309,6 +326,7 @@ int sn32_decode_chip(unsigned char *data) { USER_ROM_PAGES = USER_ROM_PAGES_SN32F240C; MAX_FIRMWARE = USER_ROM_SIZE_KB(USER_ROM_SIZE); CS0 = CS0_1; + BLANK_CHECKSUM = 0x0000; sn32_family = SN240C; break; default: @@ -526,8 +544,9 @@ bool protocol_code_option_set(hid_device *dev, uint16_t code_option, uint16_t cs return true; } -bool erase_flash(hid_device *dev, uint16_t page_start, uint16_t page_end) { +bool erase_flash(hid_device *dev, uint16_t page_start, uint16_t page_end, uint16_t blank_checksum) { unsigned char buf[REPORT_SIZE]; + uint16_t resp = 0; // 04) Erase flash printf("\n"); printf("Erasing flash from page %u to page %u...\n", page_start, page_end); @@ -538,8 +557,15 @@ bool erase_flash(hid_device *dev, uint16_t page_start, uint16_t page_end) { write_buffer_16(buf + 8, page_end); if (!hid_set_feature(dev, buf, REPORT_SIZE)) return false; if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_ENABLE_ERASE)) return false; + if (read_response_16(buf, 8, blank_checksum, &resp)) { + printf("Flash erase verified. \n"); + return true; + } else { + fprintf(stderr, "ERROR: Failed to verify flash erase: response is 0x%04x, expected 0x%04x.\n", resp, blank_checksum); + return false; + } clear_buffer(buf, REPORT_SIZE); - return true; + return false; } bool protocol_reboot_user(hid_device *dev) { @@ -923,7 +949,7 @@ int main(int argc, char *argv[]) { } if (!ok) error(handle); sleep(1); - if (chip != SN240B && chip != SN260) ok = erase_flash(handle, 0, USER_ROM_PAGES); + if (chip != SN240B && chip != SN260) ok = erase_flash(handle, 0, USER_ROM_PAGES, BLANK_CHECKSUM); if (!ok) error(handle); sleep(1); From 4971ec4686d4effadd8a8345b41cf88d575efbcc Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 20:49:48 +0300 Subject: [PATCH 38/46] add flash program checksum to verification --- sonixflasher.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index bcb3a3e..00afbb6 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -177,6 +177,22 @@ void write_buffer_16(unsigned char *data, uint16_t cmd) { memcpy(data, &cmd, 2); } +uint16_t checksum16(const unsigned char *data, size_t size) { + uint16_t sum = 0; + size_t i; + + for (i = 0; i + 1 < size; i += 2) { + uint16_t value = data[i] | (data[i + 1] << 8); + sum += value; + } + + if (i < size) { + sum += data[i]; + } + + return sum; +} + void print_data(const unsigned char *data, int length) { for (int i = 0; i < length; i++) { if (i % 16 == 0) { @@ -622,16 +638,19 @@ bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bo // 06) Flash printf("Flashing device, please wait...\n"); - size_t bytes_read = 0; + size_t bytes_read = 0; + uint16_t checksum = 0; clear_buffer(buf, REPORT_SIZE); while ((bytes_read = fread(buf, 1, REPORT_SIZE, firmware)) > 0) { if (bytes_read < REPORT_SIZE) { fprintf(stderr, "WARNING: Read %zu bytes, expected %d bytes.\n", bytes_read, REPORT_SIZE); } + checksum += checksum16(buf, bytes_read); if (!hid_set_feature(dev, buf, bytes_read)) return false; clear_buffer(buf, REPORT_SIZE); } + printf("Flashed File Checksum: 0x%04x\n", checksum); clear_buffer(buf, REPORT_SIZE); fclose(firmware); @@ -641,7 +660,15 @@ bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bo if (!hid_get_feature(dev, buf, REPORT_SIZE, CMD_ENABLE_PROGRAM)) return false; if (read_response_32(buf, (sizeof(buf) - sizeof(VALID_FW)), VALID_FW, &resp)) { printf("Flash completion verified. \n"); - return true; + uint16_t resp_16 = (uint16_t)resp; + if (read_response_16(buf, 8, checksum, &resp_16)) { + printf("Flash Verification Checksum: OK!\n"); + return true; + } else { + fprintf(stderr, "ERROR:Flash Verification Checksum: FAILED! response is 0x%04x, expected 0x%04x.\n", resp_16, checksum); + return false; + } + return false; } else { fprintf(stderr, "ERROR: Failed to verify flash completion: response is 0x%08x, expected 0x%08x.\n", resp, VALID_FW); return false; From 9a23d7de9f5f11d1832b0cb6fc375fc319d2ef19 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Tue, 10 Sep 2024 21:42:43 +0300 Subject: [PATCH 39/46] v2.0.4 --- sonixflasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index 00afbb6..fbb66fb 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -78,7 +78,7 @@ #define RETRY_DELAY_MS 100 #define PROJECT_NAME "sonixflasher" -#define PROJECT_VER "2.0.3" +#define PROJECT_VER "2.0.4" uint16_t BLANK_CHECKSUM = 0x0000; uint16_t CS0 = CS0_0; From 37f44e56dfd0d58868c167c6748eacbae9bc5a83 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 13 Sep 2024 17:31:19 +0300 Subject: [PATCH 40/46] cleanup code option print --- sonixflasher.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index fbb66fb..cd0351f 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -361,8 +361,7 @@ int sn32_decode_chip(unsigned char *data) { bool sn32_check_isp_code_option(unsigned char *data) { uint16_t received_code_option = (data[12] << 8) | data[13]; - printf("Expected Code Option Table: 0x%04X\n", code_option); - printf("Received Code Option Table: 0x%04X\n", received_code_option); + printf("Checking Code Option Table... Expected: 0x%04X Received: 0x%04X.\n", code_option, received_code_option); if (received_code_option != code_option) { printf("Updating Code Option Table from 0x%04X to 0x%04X\n", code_option, received_code_option); code_option = received_code_option; From f2ec3ed242be02b68fb9c671734349c41fd77400 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 13 Sep 2024 17:34:04 +0300 Subject: [PATCH 41/46] speed up procedures --- sonixflasher.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index cd0351f..3995c54 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -261,7 +261,7 @@ int sn32_decode_chip(unsigned char *data) { printf("Sonix SN32 Detected.\n"); printf("\n"); printf("Checking variant... "); - sleep(2); + int sn32_family; switch (data[9]) { case SN240: @@ -496,7 +496,7 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { // 01) Initialize printf("\n"); printf("Fetching flash version...\n"); - sleep(2); + clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_GET_FW_VERSION; write_buffer_16(buf + 1, CMD_BASE); @@ -623,7 +623,7 @@ bool flash(hid_device *dev, long offset, const char *file_name, long fw_size, bo // 05) Enable program printf("\n"); printf("Enabling Program mode...\n"); - sleep(2); + clear_buffer(buf, REPORT_SIZE); buf[0] = CMD_ENABLE_PROGRAM; write_buffer_16(buf + 1, CMD_BASE); @@ -965,7 +965,7 @@ int main(int argc, char *argv[]) { attempt_no++; } if (!ok) error(handle); - sleep(3); + sleep(1); if (chip != SN240B && chip != SN260) ok = protocol_code_option_check(handle); if (!ok) error(handle); sleep(1); @@ -986,7 +986,7 @@ int main(int argc, char *argv[]) { } if (((flash_jumploader && sanity_check_jumploader_firmware(prepared_file_size)) || (!flash_jumploader && sanity_check_firmware(prepared_file_size, offset))) && (flash(handle, offset, file_name, prepared_file_size, no_offset_check))) { printf("Device succesfully flashed!\n"); - sleep(3); + sleep(2); protocol_reboot_user(handle); } else { fprintf(stderr, "ERROR: Could not flash the device. Try again.\n"); From 4a9c0520c9ae369b1425ccdef6751a1dca341c23 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 13 Sep 2024 17:37:15 +0300 Subject: [PATCH 42/46] update docs and pid tables --- README.md | 6 ++++-- sonixflasher.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7c2b62c..273aec9 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,12 @@ make sonixflasher +-----------------+--------+--------+ | Device | VID | PID | +-----------------+--------+--------+ -| SONIX SN32F26x | 0x0C45 | 0x7010 | +| SONIX SN32F22x | 0x0C45 | 0x7900 | +| SONIX SN32F23x | 0x0C45 | 0x7900 | +| SONIX SN32F24x | 0x0C45 | 0x7900 | | SONIX SN32F24xB | 0x0C45 | 0x7040 | | SONIX SN32F24xC | 0x0C45 | 0x7145 | -| SONIX SN32F24x | 0x0C45 | 0x7900 | +| SONIX SN32F26x | 0x0C45 | 0x7010 | | SONIX SN32F28x | 0x0C45 | 0x7120 | | SONIX SN32F29x | 0x0C45 | 0x7140 | +-----------------+--------+--------+ diff --git a/sonixflasher.c b/sonixflasher.c index 3995c54..b17f9f2 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -90,7 +90,7 @@ bool debug = false; static uint16_t code_option = 0x0000; // Initial Code Option Table int chip; int cs_level; -const unsigned int known_isp_pids[] = {SN229_PID, SN239_PID, SN248B_PID, SN248C_PID, SN268_PID, SN289_PID, SN299_PID}; +const unsigned int known_isp_pids[] = {SN229_PID, SN239_PID, SN249_PID, SN248B_PID, SN248C_PID, SN268_PID, SN289_PID, SN299_PID}; static void print_vidpid_table() { printf("Supported VID/PID pairs:\n"); From 1f9341c07aa58ddf63d39b53f87aec97b85f9437 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Fri, 13 Sep 2024 18:50:40 +0300 Subject: [PATCH 43/46] persist while attempting to reboot to bootloader --- sonixflasher.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index b17f9f2..ff157c5 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -456,7 +456,14 @@ bool send_magic_command(hid_device *dev, const uint32_t *command) { clear_buffer(buf, sizeof(buf)); write_buffer_32(buf, command[0]); write_buffer_32(buf + sizeof(uint32_t), command[1]); - if (!hid_set_feature(dev, buf, sizeof(buf))) return false; + uint8_t attempt_no = 1; + while (!hid_set_feature(dev, buf, REPORT_SIZE) && attempt_no <= MAX_ATTEMPTS) // Try {MAX ATTEMPTS} to init flash. + { + printf("Failed to greet device, re-trying in 1 second. Attempt %d of %d...\n", attempt_no, MAX_ATTEMPTS); + sleep(1); + attempt_no++; + } + if (attempt_no > MAX_ATTEMPTS) return false; clear_buffer(buf, sizeof(buf)); return true; } From f83799ca67f7174acb92abde5b8b97a75d640f15 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 14 Sep 2024 12:06:49 +0300 Subject: [PATCH 44/46] add sonix reboot option --- README.md | 2 +- sonixflasher.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 273aec9..e4dcc5e 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ make sonixflasher - `--offset -o` Set flashing offset (default: 0). - `--file -f` Binary of the firmware to flash (*.bin extension). - `--jumploader -j` Define if flashing a jumploader. -- `--reboot -r` Request bootloader reboot in OEM firmware (options: evision, hfd). +- `--reboot -r` Request bootloader reboot in OEM firmware (options: sonix, evision, hfd). - `--debug -d` Enable debug mode. - `--list-vidpid -l` Display supported VID/PID pairs. - `--nooffset -k` Disable offset checks. diff --git a/sonixflasher.c b/sonixflasher.c index ff157c5..595e69d 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -117,7 +117,7 @@ static void print_usage(char *m_name) { " --offset -o Set flashing offset (default: 0)\n" " --file -f Binary of the firmware to flash (*.bin extension) \n" " --jumploader -j Define if we are flashing a jumploader \n" - " --reboot -r Request bootloader reboot in OEM firmware (options: evision, hfd) \n" + " --reboot -r Request bootloader reboot in OEM firmware (options: sonix, evision, hfd) \n" " --debug -d Enable debug mode \n" " --nooffset -k Disable offset checks \n" " --list-vidpid -l Display supported VID/PID pairs \n" @@ -469,15 +469,15 @@ bool send_magic_command(hid_device *dev, const uint32_t *command) { } bool reboot_to_bootloader(hid_device *dev, char *oem_option) { - uint32_t evision_reboot[2] = {0x5AA555AA, 0xCC3300FF}; - uint32_t hfd_reboot[2] = {0x5A8942AA, 0xCC6271FF}; + uint32_t sonix_reboot[2] = {0x5AA555AA, 0xCC3300FF}; + uint32_t hfd_reboot[2] = {0x5A8942AA, 0xCC6271FF}; if (oem_option == NULL) { printf("ERROR: reboot option cannot be null.\n"); return false; } - if (strcmp(oem_option, "evision") == 0) { - return send_magic_command(dev, evision_reboot); + if (strcmp(oem_option, "sonix") == 0 || strcmp(oem_option, "evision") == 0) { + return send_magic_command(dev, sonix_reboot); } else if (strcmp(oem_option, "hfd") == 0) { return send_magic_command(dev, hfd_reboot); } @@ -493,9 +493,9 @@ bool protocol_init(hid_device *dev, bool oem_reboot, char *oem_option) { if (oem_reboot) { printf("Requesting bootloader reboot...\n"); if (reboot_to_bootloader(dev, oem_option)) - printf("Bootloader reboot succesfull.\n"); + printf("Bootloader reboot request success.\n"); else { - printf("ERROR: Bootloader reboot failed.\n"); + printf("ERROR: Bootloader reboot request failed.\n"); return false; } } From d6c0516b59b728eccf8d34f4ac845e9f87843029 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 14 Sep 2024 12:37:16 +0300 Subject: [PATCH 45/46] exit if a program operation is already pending If flashing gets interrupted while the device is receiving the firmware, it will stay in program mode. Inform the user about it --- sonixflasher.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sonixflasher.c b/sonixflasher.c index 595e69d..ceaaec2 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -139,6 +139,18 @@ static void display_version(char *m_name) { fprintf(stderr, "%s " PROJECT_VER "\n", m_name); } +void cleanup(hid_device *handle) { + if (handle) hid_close(handle); + if (hid_exit() != 0) { + fprintf(stderr, "ERROR: Could not close the device.\n"); + } +} + +void error(hid_device *handle) { + cleanup(handle); + exit(1); +} + void clear_buffer(unsigned char *data, size_t length) { for (int i = 0; i < length; i++) data[i] = 0; @@ -431,6 +443,10 @@ bool hid_get_feature(hid_device *dev, unsigned char *data, size_t data_size, uin return true; } else { fprintf(stderr, "ERROR: Invalid response command: 0x%08x, expected command 0x%02x.\n", cmdreply, command & 0xFF); + if ((cmdreply == CMD_VERIFY(CMD_ENABLE_PROGRAM)) && (status == CMD_ACK)) { + printf("Device progam pending. Please power cycle the device.\n"); + error(dev); + } return false; } } else if (res < 0) { @@ -809,18 +825,6 @@ long prepare_file_to_flash(const char *file_name, bool flash_jumploader) { return file_size; } -void cleanup(hid_device *handle) { - if (handle) hid_close(handle); - if (hid_exit() != 0) { - fprintf(stderr, "ERROR: Could not close the device.\n"); - } -} - -void error(hid_device *handle) { - cleanup(handle); - exit(1); -} - int main(int argc, char *argv[]) { int opt, opt_index; hid_device *handle; From 8f6d09a1a14434a09a4ad5f2364eb5b2753cb15c Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Sat, 14 Sep 2024 13:05:16 +0300 Subject: [PATCH 46/46] v2.0.5 --- sonixflasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonixflasher.c b/sonixflasher.c index ceaaec2..11d9f17 100644 --- a/sonixflasher.c +++ b/sonixflasher.c @@ -78,7 +78,7 @@ #define RETRY_DELAY_MS 100 #define PROJECT_NAME "sonixflasher" -#define PROJECT_VER "2.0.4" +#define PROJECT_VER "2.0.5" uint16_t BLANK_CHECKSUM = 0x0000; uint16_t CS0 = CS0_0;