amnemonic / Quansheng_UV-K5_Firmware

Quansheng UV-K5 Firmware
619 stars 124 forks source link

Wrong dump: nvram_(0x10000-0x107FF).bin #110

Open Lar-Sen opened 7 months ago

Lar-Sen commented 7 months ago

Maybe you should delete this file. In fact, true NVRAM region is hidden everytime. It is no way located at the mentioned address, thus the dump being garbage.

To dump NVRAM region correctly, you must first issue write_memory 0x4006F000 32 0x3 in OpenOCD to select it.

Then you can dump 0x800 bytes from 0x0000 address: dump_image my_nvram.bin 0x0 0x800

Its contents are interesting, as they host a fingerprint for Quansheng's "anti-counterfeiting" routines to recognize the device as genuine, plus CpuID (sector 0 = OTP only) and some factory data at the very end of the dump.

This fake dump was misleading me in finding the reason why my transceiver went nuts after playing with UART 0x516 command :) So, 0x516 is definitely used as an updater for NVRAM's sectors 1 to 3. Maybe we could make use of that.

amnemonic commented 7 months ago

That is very interesting info, for sure it would be great to investigate further.

Lar-Sen commented 7 months ago

Just to correct myself: 0x516 only allows updating the 104 first bytes (ECDSA signature?) of sector 1. Anyway it's easy enough to mod bootloader's code. As I lost my original NVRAM bytes on this device, I cannot investigate further about the signature algorithm they implemented. I'm about to receive a fresh new UV-K5, I'll dump all the regions asap.

Another interesting fact: The wrong NVRAM dump we talk about seems to be a forgotten piece of code from the CPU maker MCU's internal boot code. Analysing it, I found that they can program NVRAM sector 0 by issuing an undocumented value for 0x4006F000 register: 0x16. Bits 4-6 serve to select Main or NVRAM region, as previously mentioned, but 0b101xx is said to be 'reserved'. 0b1011x allows write access to the full NVRAM area. MSb here means "god mode" .

The code apparently allows to read update TRIM parameters for flash memory (offset 0x100), maybe CPUid data too. As it occupies another 2kb , I'll try to wipe this factory code just to see if it still works :)

EDIT: Dit it. So surprise, this is a read-only region. Even with "god bit" on. Everything beyond 0x0FFFF loops back to bootloader's address, as expected. EDIT2: Striked some misguiding information, following DualTachyon's comment

DualTachyon commented 6 months ago

"The forgotten piece of code" is just the normal boot ROM of the MCU. At power on, the ROM is mapped from 0 all the way to 0x1FFFFFFF. After doing the trim work, it switches in the FLASH into address 0..0xFFFF, which is why you see this "forgotten code" at 0x10000+.

0x16 is nothing more than "NV_SEL = 1 && CMD = READ_APB". The flash can be read in 2 ways: via AHB (= direct memory map) and via APB (= via register programming).

You can see the details of the CFG register here: https://github.com/DualTachyon/uv-k5-firmware/blob/main/hardware/dp32g030/flash.def#L19

Lar-Sen commented 6 months ago

As a beginner, I made an assumption about these unknown bytes which needed some necessary knowledge I wasn't aware of :) Thank you for your explanation about boot code. I thought that what we call 'bootloader' was enough to properly initialize full MCU and its interfaces... I haven't managed to reverse engineer (and understand!) all of its code, and for sure I lack some basics about ARM microcontroller architecture. Anyway I'm unable to find any information about flash access via the buses you mentioned. I thought that, as soon as we have 'programming' bit set, this should be a write operation. In my mind, the (apparently) undocumented bit 4 may be a bypass, even if it seems pretty naive :) I still learn a lot every day.

Did you find FLASH_CFG valid states in official DP32G030 chinese technical document?