kopia lustrzana https://github.com/sq5bpf/k5prog
fix flashing firmware larger than 0xe600 bytes
rodzic
15e1dde73e
commit
d68ec83d92
160
README
160
README
|
@ -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>
|
(c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||||
|
|
||||||
This program can read and write the eeprom of Quansheng UV-K5.
|
This program can read and write the eeprom of Quansheng UV-K5.
|
||||||
|
@ -12,6 +12,24 @@ Note that this program does not edit the contents of the eeprom. Use an
|
||||||
external hex editor.
|
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
|
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.
|
on GNU/Linux, but MacOS X and windows under cygwin should work too.
|
||||||
|
|
||||||
|
@ -20,13 +38,38 @@ For licensing see the file LICENSE.
|
||||||
|
|
||||||
---- Usage ----
|
---- 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
|
For a basic usage use -r to read eeprom, -w to write eeprom. The -v option
|
||||||
gives more verbosity.
|
gives more verbosity.
|
||||||
|
|
||||||
Read configuration:
|
Read configuration:
|
||||||
|
|
||||||
sq5bpf@chronos:~/k5prog$ ./k5prog -r -v
|
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
|
k5_prepare: try 0
|
||||||
****** Connected to firmware version: [k5_2.01.23]
|
****** Connected to firmware version: [k5_2.01.23]
|
||||||
|
@ -40,7 +83,7 @@ changed with the -f option.
|
||||||
Write configuration from file k5_eeprom.raw:
|
Write configuration from file k5_eeprom.raw:
|
||||||
|
|
||||||
sq5bpf@chronos:~/chirp/k5prog$ ./k5prog -w -v
|
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
|
k5_prepare: try 0
|
||||||
****** Connected to firmware version: [k5_2.01.23]
|
****** 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
|
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.
|
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
54
k5prog.c
54
k5prog.c
|
@ -50,7 +50,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "uvk5.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_NONE 0
|
||||||
#define MODE_READ 1
|
#define MODE_READ 1
|
||||||
|
@ -651,7 +651,7 @@ int k5_send_flash_version_message(int fd) {
|
||||||
return(1);
|
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;
|
int l;
|
||||||
unsigned char writeflash[512];
|
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[8]=(offset>>8)&0xff;
|
||||||
writeflash[9]=offset&0xff;
|
writeflash[9]=offset&0xff;
|
||||||
writeflash[10]=0xe6;
|
//writeflash[10]=0xe6;
|
||||||
|
writeflash[10]=(max_flash_addr>>8)&0xff;
|
||||||
writeflash[11]=0x00;
|
writeflash[11]=0x00;
|
||||||
|
//writeflash[11]=max_flash_addr&0xff;
|
||||||
writeflash[12]=len&0xff;
|
writeflash[12]=len&0xff;
|
||||||
writeflash[13]=(len>>8)&0xff;
|
writeflash[13]=(len>>8)&0xff;
|
||||||
writeflash[14]=0x00;
|
writeflash[14]=0x00;
|
||||||
|
@ -743,6 +745,8 @@ void helpme()
|
||||||
"-Y \tincrease \"I know what i'm doing\" value, to enable functionality likely to break the radio\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"
|
"-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"
|
"-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"
|
"-r \tread eeprom\n"
|
||||||
"-w \twrite eeprom like the original software does\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"
|
"-W \twrite most of the eeprom (but without what i think is calibration data)\n"
|
||||||
|
@ -947,7 +951,8 @@ int main(int argc,char **argv)
|
||||||
unsigned char eeprom[UVK5_EEPROM_SIZE];
|
unsigned char eeprom[UVK5_EEPROM_SIZE];
|
||||||
unsigned char flash[UVK5_MAX_FLASH_SIZE];
|
unsigned char flash[UVK5_MAX_FLASH_SIZE];
|
||||||
int flash_length;
|
int flash_length;
|
||||||
int flash_length2;
|
int flash_max_addr;
|
||||||
|
int flash_max_block_addr;
|
||||||
int i,r,j,len;
|
int i,r,j,len;
|
||||||
|
|
||||||
printf (VERSION "\n\n");
|
printf (VERSION "\n\n");
|
||||||
|
@ -999,41 +1004,44 @@ int main(int argc,char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
flash_length=read(ffd,(unsigned char *)&flash,UVK5_MAX_FLASH_SIZE);
|
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 */
|
/* arbitrary limit do that someone doesn't flash some random short file */
|
||||||
if (flash_length<50000) {
|
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);
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
if ((write_length>0)&&((write_length+write_offset)>=UVK5_MAX_FLASH_SIZE)) {
|
if (verbose>0) { printf ("Read file %s success\n",flash_file); }
|
||||||
fprintf(stderr,"write_length (%d) + write_offset (%d) is bigger than the flash size (%d)\n", write_length, write_offset, UVK5_MAX_FLASH_SIZE);
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
close(ffd);
|
|
||||||
|
|
||||||
if (verbose>0) { printf ("Read file %s success\n",flash_file); }
|
|
||||||
|
|
||||||
|
|
||||||
r=wait_flash_message(fd,10000);
|
r=wait_flash_message(fd,10000);
|
||||||
if (!r) exit(0);
|
if (!r) exit(0);
|
||||||
|
|
||||||
k5_send_flash_version_message(fd);
|
k5_send_flash_version_message(fd);
|
||||||
|
|
||||||
/* for(i=0; i<flash_length; i+=UVK5_FLASH_BLOCKSIZE) */
|
for(i=write_offset; i<flash_max_addr; 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)
|
|
||||||
{
|
{
|
||||||
len=flash_length-i;
|
len=flash_max_addr-i;
|
||||||
if (len>UVK5_FLASH_BLOCKSIZE) len=UVK5_FLASH_BLOCKSIZE;
|
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);
|
printf("*** FLASH at 0x%4.4x length 0x%4.4x result=%i\n",i,len,r);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
|
Ładowanie…
Reference in New Issue