fix flashing firmware larger than 0xe600 bytes

pull/10/head
sq5bpf 2023-09-27 18:26:55 +02:00
rodzic 15e1dde73e
commit d68ec83d92
2 zmienionych plików z 183 dodań i 45 usunięć

162
README
Wyświetl plik

@ -1,4 +1,4 @@
k5prog - Quansheng UV-K5 EEPROM programmer v0.1
k5prog - Quansheng UV-K5 EEPROM and flash programmer v0.5
(c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
This program can read and write the eeprom of Quansheng UV-K5.
@ -6,12 +6,30 @@ It can read/write arbitrary data, and might be useful for making backups of
the configuration, mass programming of radios or reverse engineering of
the radio configuration. Please note that it is probably possible to break
your radio by writing a bad configuration to it, so please use at your own
risk.
risk.
Note that this program does not edit the contents of the eeprom. Use an
external hex editor.
The program can also flash the firmware on the Quansheng UV-K5. This will
flash the raw binary, and not the Quansheng-encrypted firmware files.
A Quansheng-encrypted firmware can be decrypted using the fw.py script from
here:
https://github.com/fagci/qs-uvk5-firmware-modder
An example decrypted file is provided in k5_flash_test.raw, this is the vendor
2.01.23 firmware without any modifications.
Please use extreme caution, as reprogramming the radioflash can potentially i
brick your radio. If unsure, please use the vendor flashing software.
The flashing support in k5prog was used in at least 2 cases to recover radios
which were bricked by flashing firmware using the vendor flasher. I don't know
why this worked, but it did.
To compile, please see the compiling section at the end.
The program is written to (hopefully) run on POSIX systems. Testing was done
on GNU/Linux, but MacOS X and windows under cygwin should work too.
@ -20,13 +38,38 @@ For licensing see the file LICENSE.
---- Usage ----
for help run the programwithout arguments, or with the -h option.
The configuration options are:
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
cmdline opts:
-f <file> filename that contains the eeprom dump (default: k5_eeprom.raw)
-b <file> filename that contains the raw flash image (default k5_flash.raw)
-Y increase "I know what i'm doing" value, to enable functionality likely to break the radio
-D wait for the message from the radio flasher, print it's version
-F flash firmware, WARNING: this will likely brick your radio!
-O offset of block to flash in hex (default: 0)
-L length of file to flash in hex (default: all)
-r read eeprom
-w write eeprom like the original software does
-W write most of the eeprom (but without what i think is calibration data)
-B write ALL of the eeprom (the "brick my radio" mode)
-p <port> device name (default: /dev/ttyUSB0)
-s <speed> serial speed (default: 38400, the UV-K5 doesn't accept any other speed)
-h print this help
-v be verbose, use multiple times for more verbosity
---- Reading/writing the configuration eeprom ----
For a basic usage use -r to read eeprom, -w to write eeprom. The -v option
gives more verbosity.
Read configuration:
sq5bpf@chronos:~/k5prog$ ./k5prog -r -v
Quansheng UV-K5 EEPROM programmer v0.2 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
k5_prepare: try 0
****** Connected to firmware version: [k5_2.01.23]
@ -40,7 +83,7 @@ changed with the -f option.
Write configuration from file k5_eeprom.raw:
sq5bpf@chronos:~/chirp/k5prog$ ./k5prog -w -v
Quansheng UV-K5 EEPROM programmer v0.2 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
k5_prepare: try 0
****** Connected to firmware version: [k5_2.01.23]
@ -63,22 +106,109 @@ allowing overwriting of calibration data (if there is any) or other data which
may be critical to the proper functioning of your radio. I have used this on
my radio, and it still works but please be extra-careful.
I have written the radio eeprom with the -W option tens of times, and others
have too. So far it hasn't produced any bad results. But of course beware.
Other configuration options are:
---- Flashing support ----
The flashing support is for the really brave people who know what they are
doing (hence the -Y flag is needed).
It is possible to read the bootloder version using the -D option. This option
is safe, but needs the -Y value. Put the radio into flash mode and:
./k5prog -Y -D
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
"I know what i'm doing" value set to 1
******** k5 command hexdump [obf_len:44 clear_len:36 crc_ok:1 **********
## obfuscated ##
0x00002c |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: ab cd 24 00 0e 69 34 e6 2f 93 0f 46 3d 66 85 0a ..$..i4./..F=f..
0x000010: 24 44 16 8f 9a 6c 47 e6 1c bf 3d 70 0f 05 e3 40 $D...lG...=p...@
0x000020: 27 09 e9 80 16 6c 14 c6 d1 6e dc ba '....l...n..
## cleartext ##
0x000024 |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: 18 05 20 00 01 02 02 06 1c 53 50 4a 37 47 ff 0f .. ......SPJ7G..
0x000010: 8c 00 53 00 32 2e 30 30 2e 30 36 00 34 0a 00 00 ..S.2.00.06.4...
0x000020: 00 00 00 20 ...
*****************
Flasher version is: [2.00.06]
The radio can also be flashed with the raw unencrypted binary.
An example binary is provided in the k5_flash.raw file (this is the 2.01.23
firmware). The binary file can be specified with the -b option.
Flashing the radio requires the "i know what i'm doing value" of at least 5.
./k5prog -b k5_flash.raw -YYYYYY -F
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
"I know what i'm doing" value set to 6
******** k5 command hexdump [obf_len:44 clear_len:36 crc_ok:1 **********
## obfuscated ##
0x00002c |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: ab cd 24 00 0e 69 34 e6 2f 93 0f 46 3d 66 85 0a ..$..i4./..F=f..
0x000010: 24 44 16 8f 9a 6c 47 e6 1c bf 3d 70 0f 05 e3 40 $D...lG...=p...@
0x000020: 27 09 e9 80 16 6c 14 c6 d1 6e dc ba '....l...n..
## cleartext ##
0x000024 |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: 18 05 20 00 01 02 02 06 1c 53 50 4a 37 47 ff 0f .. ......SPJ7G..
0x000010: 8c 00 53 00 32 2e 30 30 2e 30 36 00 34 0a 00 00 ..S.2.00.06.4...
0x000020: 00 00 00 20 ...
*****************
Flasher version is: [2.00.06]
*** FLASH at 0x0000 length 0x0100 result=1
*** FLASH at 0x0100 length 0x0100 result=1
*** FLASH at 0x0200 length 0x0100 result=1
*** FLASH at 0x0300 length 0x0100 result=1
etc... until all flash is writtem
It is possible to overwrite only one flash block. Each block has 0x100 bytes
size. The offset can be specified by the -O option, and the length by the -L
option. The length is rounded up to the nearest block size.
For example program 0x300 bytes starting at offset 0xe000:
./k5prog -b k5_flash.raw -YYYYYY -F -L 0x300 -O 0xe000
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
"I know what i'm doing" value set to 6
******** k5 command hexdump [obf_len:44 clear_len:36 crc_ok:1 **********
## obfuscated ##
0x00002c |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: ab cd 24 00 0e 69 34 e6 2f 93 0f 46 3d 66 85 0a ..$..i4./..F=f..
0x000010: 24 44 16 8f 9a 6c 47 e6 1c bf 3d 70 0f 05 e3 40 $D...lG...=p...@
0x000020: 27 09 e9 80 16 6c 14 c6 d1 6e dc ba '....l...n..
## cleartext ##
0x000024 |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |a |b |c |d |e |f |
---------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+------------
0x000000: 18 05 20 00 01 02 02 06 1c 53 50 4a 37 47 ff 0f .. ......SPJ7G..
0x000010: 8c 00 53 00 32 2e 30 30 2e 30 36 00 34 0a 00 00 ..S.2.00.06.4...
0x000020: 00 00 00 20 ...
*****************
Flasher version is: [2.00.06]
Writing blocks from address 0xe000 until 0xe300
*** FLASH at 0xe000 length 0x0100 result=1
*** FLASH at 0xe100 length 0x0100 result=1
*** FLASH at 0xe200 length 0x0100 result=1
Quansheng UV-K5 EEPROM programmer v0.2 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
cmdline opts:
-f <file> filename that contains the eeprom dump (default: k5_eeprom.raw)
-r read eeprom
-w write eeprom like the original software does
-W write most of the eeprom (but without what i think is calibration data)
-B write ALL of the eeprom (the "brick my radio" mode)
-p <port> device name (default: /dev/ttyUSB0)
-s <speed> serial speed (default: 38400, the UV-K5 doesn't accept any other speed)
-h print this help
-v be verbose, use multiple times for more verbosity

Wyświetl plik

@ -50,7 +50,7 @@
#include <stdint.h>
#include "uvk5.h"
#define VERSION "Quansheng UV-K5 EEPROM programmer v0.4 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>"
#define VERSION "Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>"
#define MODE_NONE 0
#define MODE_READ 1
@ -651,7 +651,7 @@ int k5_send_flash_version_message(int fd) {
return(1);
}
int k5_writeflash(int fd, unsigned char *buf, int len, int offset)
int k5_writeflash(int fd, unsigned char *buf, int len, int offset,int max_flash_addr)
{
int l;
unsigned char writeflash[512];
@ -679,8 +679,10 @@ int k5_writeflash(int fd, unsigned char *buf, int len, int offset)
writeflash[8]=(offset>>8)&0xff;
writeflash[9]=offset&0xff;
writeflash[10]=0xe6;
//writeflash[10]=0xe6;
writeflash[10]=(max_flash_addr>>8)&0xff;
writeflash[11]=0x00;
//writeflash[11]=max_flash_addr&0xff;
writeflash[12]=len&0xff;
writeflash[13]=(len>>8)&0xff;
writeflash[14]=0x00;
@ -741,8 +743,10 @@ void helpme()
"-f <file>\tfilename that contains the eeprom dump (default: " DEFAULT_FILE_NAME ")\n"
"-b <file>\tfilename that contains the raw flash image (default " DEFAULT_FLASH_NAME ")\n"
"-Y \tincrease \"I know what i'm doing\" value, to enable functionality likely to break the radio\n"
"-D\twait for the message from the radio flasher, print it's version\n"
"-F\tflash firmware, WARNING: this will likely brick your radio!\n"
"-D \twait for the message from the radio flasher, print it's version\n"
"-F \tflash firmware, WARNING: this will likely brick your radio!\n"
"-O \toffset of block to flash in hex (default: 0)\n"
"-L \tlength of file to flash in hex (default: all)\n"
"-r \tread eeprom\n"
"-w \twrite eeprom like the original software does\n"
"-W \twrite most of the eeprom (but without what i think is calibration data)\n"
@ -805,7 +809,7 @@ void parse_cmdline(int argc, char **argv)
int opt;
int tmpval;
int res;
int res;
/* cmdline opts:
* -f <file>
* -b <flash file>
@ -947,7 +951,8 @@ int main(int argc,char **argv)
unsigned char eeprom[UVK5_EEPROM_SIZE];
unsigned char flash[UVK5_MAX_FLASH_SIZE];
int flash_length;
int flash_length2;
int flash_max_addr;
int flash_max_block_addr;
int i,r,j,len;
printf (VERSION "\n\n");
@ -999,41 +1004,44 @@ int main(int argc,char **argv)
exit(1);
}
flash_length=read(ffd,(unsigned char *)&flash,UVK5_MAX_FLASH_SIZE);
close(ffd);
/* arbitrary limit do that someone doesn't flash some random short file */
if (flash_length<50000) {
fprintf(stderr,"Failed to read whole eeprom from file %s (read %i), file too short or some other error\n",file,flash_length);
exit(1);
}
if ((write_length>0)&&((write_length+write_offset)>=UVK5_MAX_FLASH_SIZE)) {
fprintf(stderr,"write_length (%d) + write_offset (%d) is bigger than the flash size (%d)\n", write_length, write_offset, UVK5_MAX_FLASH_SIZE);
if (verbose>0) { printf ("Read file %s success\n",flash_file); }
flash_max_addr=flash_length;
if (write_length>0) flash_max_addr=write_offset+write_length;
if (flash_max_addr>flash_length) flash_max_addr=flash_length;
if (flash_max_addr&0xff) {
flash_max_block_addr=(flash_max_addr&0xff00)+UVK5_FLASH_BLOCKSIZE;
} else {
flash_max_block_addr=(flash_max_addr&0xff00);
}
printf("Writing blocks from address 0x%x until 0x%x, firmware size is 0x%x\n",write_offset,flash_max_block_addr,flash_length);
if (flash_max_block_addr>UVK5_MAX_FLASH_SIZE) {
fprintf(stderr,"flash length 0x%x is greater than max flash size 0x%s\n",flash_max_block_addr,UVK5_MAX_FLASH_SIZE);
exit(1);
}
close(ffd);
if (verbose>0) { printf ("Read file %s success\n",flash_file); }
r=wait_flash_message(fd,10000);
if (!r) exit(0);
k5_send_flash_version_message(fd);
r=wait_flash_message(fd,10000);
if (!r) exit(0);
k5_send_flash_version_message(fd);
/* for(i=0; i<flash_length; i+=UVK5_FLASH_BLOCKSIZE) */
flash_length2=flash_length;
if (write_length>0) {
flash_length2=write_offset+write_length;
if (flash_length2%UVK5_FLASH_BLOCKSIZE>0) {
flash_length2=flash_length2-flash_length2%UVK5_FLASH_BLOCKSIZE+UVK5_FLASH_BLOCKSIZE;
}
if (flash_length2>flash_length) flash_length2=flash_length;
printf("Writing blocks from address 0x%x until 0x%x\n",write_offset,flash_length2);
}
for(i=write_offset; i<flash_length2; i+=UVK5_FLASH_BLOCKSIZE)
for(i=write_offset; i<flash_max_addr; i+=UVK5_FLASH_BLOCKSIZE)
{
len=flash_length-i;
len=flash_max_addr-i;
if (len>UVK5_FLASH_BLOCKSIZE) len=UVK5_FLASH_BLOCKSIZE;
r=k5_writeflash(fd, (unsigned char *)&flash+i,len,i);
r=k5_writeflash(fd, (unsigned char *)&flash+i,len,i,flash_max_block_addr);
printf("*** FLASH at 0x%4.4x length 0x%4.4x result=%i\n",i,len,r);
if (!r) {