gashtaan / sinowealth-8051-dumper

Flash memory dumper for 8051-based SinoWealth MCUs
GNU General Public License v3.0
18 stars 1 forks source link

Request: write function/info #5

Open niztor opened 1 year ago

niztor commented 1 year ago

Hi! Thanks for your this amazing proyect. I was wondering if you plan to release any updates with write / mass erase flash functions. Currently i have a bunch of SH79F084A to play with, trying to figure out a way to clear and rewrite it. I was able to read it using current dumper implementation, but i have no luck guessing the correct ICP commands or sequence for write it. I have no access to any programmers like JET51 or similar. Is there any way I can help with the implementation of such functions ?

swiftgeek commented 1 year ago

@niztor could you post dump of code options and part number it displays for SH79F084A? I think it might come handy for reference

gashtaan commented 1 year ago

@niztor as its name suggest, write/erase function are out of scope of this tool. I think @swiftgeek is already working on it.

swiftgeek commented 1 year ago

@gashtaan I was waiting for you to mention other opcodes, especially erase ones, and I'm only aware of one write opcode (0x42) that likely writes just to code options area. I don't have access to JET51A either. And I don't have blank chips to test that one write opcode.

So pretty please, even list of other opcodes spotted would help, even without exact description (or even none at all).

gashtaan commented 1 year ago

@swiftgeek neither do I have access to JET51A or any other programmer, it's enough to look into the firmware which is freely downloadable in Keil C51 package.

niztor commented 1 year ago

@swiftgeek here is the part number and options extracted with the dumper tool

JTAG ID: 083A

Dumping part number: 79F084A000

Dumping code options: 00000000220FE0A10090000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000

hope this can help.

swiftgeek commented 1 year ago

@gashtaan I definitely don't have smarts required to reverse the way you did it, but if it's too much work for you then that's fine. I would have never figured out that enabling pattern on the start, despite having prior knowledge of few opcodes from chroma 3360 test head for years.

niztor commented 1 year ago

@gashtaan sorry for misunderstand the goals of this project. I was just eager to try write/erase functions and could not find any other projects like this. I have no so much experience reversing fw. I think it will so lot of fun trying to do this. have you any idea what kind of mcu is based the jet51a programmer ? can you give some point where to start ? i though about using IDA tools to dissamble the fw.

gashtaan commented 1 year ago

@swiftgeek I don't understand how knowing some "opcodes" for years is relevant to this proprietary protocol... it's just some bits and timings. There is no standard that every manufacturer follow.

swiftgeek commented 1 year ago

It's the same protocol and target devices, just different "programmer"

carlossless commented 1 year ago

@swiftgeek I sniffed the JTAG pins while reading and writing firmware to the SH68F90A with my sinolink programmer. I only checked the signal integrity and the initialization sequence that @gashtaan has already recreated with this tool (although they don't seem to be exactly the same), but I haven't checked the rest (including the opcodes you're searching for). I hope these dumps will help your efforts.

sinolink-sh68f90a-read-cycle.sr.zip sinolink-sh68f90a-write-verify-cycle.sr.zip the (dummy) firmware getting read and written

DSC00692

swiftgeek commented 1 year ago

@carlossless is mass-erase exposed in software as well? If so I would love see capture of that too. Though I don't see any security capabilities in SH68F88 die, so I probably won't be able to test that.

Also would it be possible for you to check what MCU your sinolink programmer has? (and perhaps take some photos / CCD scanner scans of the board). Don't want to impose too much if shell is hard to open, as there is always a decent chance of markings being scratched off / having different markings to common ones.

In any case thank you very much for those captures, especially erase one - it definitely beats guessing opcodes blind, got some anxiety there that blind trying would brick my MCUs and only mass-erase would work ^^ Finding replacement MCUs is hard.

Also I really need to hasten BYK916 pinout extraction (from ~reference schematics) since you have all the tools ^^

carlossless commented 1 year ago

@swiftgeek

is mass-erase exposed in software as well?

Let me check, I'll get back to you regarding that.

Also would it be possible for you to check what MCU your sinolink programmer has? (and perhaps take some photos / CCD scanner scans of the board). Don't want to impose too much if shell is hard to open, as there is always a decent chance of markings being scratched off / having different markings to common ones.

I had actually already made a picture of it :). Conveniently, not much is scratched off (just M from ARM?) and it seems (somewhat surprisingly) powered by an stm32f205.

sinolink-top-pcb sinolink-bottom-pcb

carlossless commented 1 year ago

@swiftgeek

So I tried playing around with the software, but no matter what I would do it looks like it would only erase sectors one by one.

image

swiftgeek commented 1 year ago

Snippet from one of the datasheets, I was basing this on:

The mass erase operation will erase all the contents of program code, code option, code protect bit and customer code ID, regardless the status of code-protect control mode. (The Flash Programmer supplies customer code ID setting function for customer to distinguish their product.)

niztor commented 1 year ago

@carlossless Thank you so much for the dumps!

niztor commented 1 year ago

@carlossless Could you please capture only the erase/blank sector process ? I made some progress with the write function, but it only overwrite content (its an logic OR). So i think a erase sniff/dump would help to do a blank first before write new content. Thanks in advance!

swiftgeek commented 1 year ago

There appears to be consistent sinolink glitch on TDI line, 2 samples long, after capture of 8bit+1bit sync/wait (TDO/MISO is delayed by one cycle sometimes). Noticeable especially with 0xFF when previous or next state is "1". DUT can't capture it as it is not clocked in, but it definitely helps me to double check that i'm still in sync when parsing this with sigrok's spi decoder (1bit long though + annotating manually as clock has strange twitches too).

Screenshot of the glitch ![glitch after byte and sync](https://user-images.githubusercontent.com/270845/231906397-dd75223c-5e47-4ec4-bff0-2c8801dd7bc4.png)

0x4B look like a new opcode, but the stranger one to me is this entire transaction:

Screenshot ![long-ff](https://user-images.githubusercontent.com/270845/231896075-c6457c21-c5ae-4e33-af16-5407c1b9770a.png)

0x4B is distinguishable in other transaction, maybe here it's just merely data.

Start of transaction on screenshot is followed by a lot of 0xFFFF with heavy spacing between them (5ms), and final 0xFF after which MCU indicates something by switching TDO state to high. Timing wise it sorta looks like erase of of main flash maybe since erase takes a lot of time - should be the longest operation.

15 0A 09 06 FF at end matches test head for... format? So did I confuse/conflate erase with write? 0x42 seems to take address as argument, but taking two bytes would be inconsistent


Next one is even stranger, replaces 0x4B with 0xA5, and 0x00 instead of 0xFF after 0x06 and gains very different behavior, though address is different too. Ends with sending distinctive 0xAA followed by two 0x00

Next transaction screen ![A5 write maybe](https://user-images.githubusercontent.com/270845/231908910-12df966f-2934-44c2-91d2-5494d4b84c76.png)

This one starts looking like write, outputting contents for verification after significant delay. This time we have 0x6E instead of 0xA5 or 0x4B, and 0xF0 after 0x06

DUT output seems to be shifted backwards (LSB/MSB ~swapped), after something that looks like "write ack pulse" on TDO. So after each byte to be written, there is one 0x00 (with ack), and next byte to be written during which DUT shifts out data written back previously. (or maybe even greater delay, since repeating 0xDE is hard to track for exact offset). At least shifting out backwards matches test head expectations

Write transaction (maybe) Start of transaction: ![write-start](https://user-images.githubusercontent.com/270845/231920159-6638bd0b-6194-4043-98c9-ed23caed169f.png) End of transaction: ![end-of-write](https://user-images.githubusercontent.com/270845/231919425-6abf5811-7069-4f8a-9a42-a03d62f0247c.png)
swiftgeek commented 1 year ago

Looks like we are writing at least to some IB_* SFR registers

IB_CON1:

0xE6: Erase the selected block 0x6E: Write to the selected block

Would 0x4B be mass erase? And then there is also 0xA5

IB_CON3 (being written 0x0A)

0x0A: enter S2 Other: enter S1

IB_CON4 (being written 0x09)

0x09: enter S3 Other: enter S2

IB_CON5 (being written 0x06)

0x06: enter S4 Other: enter S3

Maybe ICP has simply more states and operations than SSP, but general state machine is the same

niztor commented 1 year ago

@swiftgeek Hey, very interesting analysis you did. Thank for that! I did not realize the 0x42 command it just setting IB registers. that was an amazing discovery. So, I've already have some succefull results erasing and writing sector. It's just a matter of first erasing then writing following the IB sequence through the 0x42 command, as you've mention 0xE6 for ereasing and 0x6E for writing. it apperase erasing is mandatory , otherwise the write made only OR bitwise operation. Also by doing some bruteforce testing against IB_CON1 I discover some interesting results about mass erase and options writing. After sending IB_CON1 = 0x5E all the content is clear, except for portions in option's memory that is set to 0xFF. After sendind IB_CON1 = 0xA5 its allow to write to the option / custom options sector....

After sending 0x5E , it needed to clear or set options (I sent just 0x00) for enable writing sector. I dont think if it applies to the general writing process, but at least it works for SH79F084A.

vuhuycan commented 11 months ago

@swiftgeek Hey, very interesting analysis you did. Thank for that! I did not realize the 0x42 command it just setting IB registers. that was an amazing discovery. So, I've already have some succefull results erasing and writing sector. It's just a matter of first erasing then writing following the IB sequence through the 0x42 command, as you've mention 0xE6 for ereasing and 0x6E for writing. it apperase erasing is mandatory , otherwise the write made only OR bitwise operation. Also by doing some bruteforce testing against IB_CON1 I discover some interesting results about mass erase and options writing. After sending IB_CON1 = 0x5E all the content is clear, except for portions in option's memory that is set to 0xFF. After sendind IB_CON1 = 0xA5 its allow to write to the option / custom options sector....

After sending 0x5E , it needed to clear or set options (I sent just 0x00) for enable writing sector. I dont think if it applies to the general writing process, but at least it works for SH79F084A.

Hi, I was figuring out how to write custom firmware for my keyboard (it uses BYK916), and stumble on this amazing work you guys have done. Are you still working on erase/write through JTAG? I'd love to help in making such tool.

Also, @carlossless already implemented https://github.com/carlossless/sinowealth-kb-tool . But I fear that using SSP for custom firmware can messes up the bootloader and bricking the chip. I'm not sure if that's a valid concern though?

swiftgeek commented 10 months ago

Since official programmer is now known to use STM32F2, I was thinking about recreating it in some way, though if logic analyzer captures could be made for JTAG debug session of sinowealth 8051 target, then that would be a great alternative.

For programming JTAG is not used (or doesn't have to be used) and instead a special ICP protocol is used (different function over JTAG pins). My intention was to extend flashrom's serprog protocol to support generic programmer-advertised (bespoke) targets, but extending protocol in robust way for generic targets is giving me a lil bit too much headache so I should probably make something much simpler first (like inlining bootloader (4KiB) dumped with sinowealth-kb-tool, together with minimal main fw portion that always jumps to bootloader - then programming the rest with sinowealth-kb-tool over USB).

The issue with bootloader on BYKxxx is that it's not using MCU features for selecting bootloader, and then even if MCU features were used it wouldn't resolve issues with interrupt vector locations. On my particular BYK816 it doesn't even boot through bootloader and instead just starts with main firmware directly making bricks extremely easy.

gashtaan commented 10 months ago

@vuhuycan What is the SSP you mentioned? If you use read/write/erase features of stock bootloader, it wont allow you to overwrite itself or overwrite the jump at reset vector.

The bootloader has to take over USB communication to receive your commands, so for update, you either have to:

Either way, you will always have a way to update the firmware, IMO it's hard to brick it - just look at the code.

swiftgeek commented 10 months ago

Is that sequence described somewhere? If it behaves just like ISP pin straps, then in eg. BYK816 bootloader it points into completely random place.

I only found reference to USB JIG ( "USB ISP Boot Circuit" that has a single transistor) which seems to be implemented inside bootloader (for configuration where reset vector points into bootloader, but use of update tool changes that to main fw (even if only read operation is performed) on BYK816 at least)