-
Notifications
You must be signed in to change notification settings - Fork 0
License
james-portman/subaru-ecu-flashing
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
subaru-ecu-flashing This is my progress so far into an open source method for flashing - reading and writing - subaru ECUs Ideally without having to use expensive cables or software DISCLAIMER: BE CAREFUL DOING ANYTHING RELATED TO THIS, IF YOU PARTIALLY OR IMPROPERLY FLASH AN ECU IT WILL PROBABLY BE USELESS IF YOU ERASE A FLASH BLOCK WITHOUT IMMEDIATELY REPROGRAMMING IT THEN THE ECU WILL PROBABLY BE USELESS There is a way to recover these ECUs (user boot mode) but requires soldering directly on to test pads etc and is not guaranteed There is some python code in the repo related to all of this, partially tested, never guaranteed to work You should not use it on a real car or ECU, if you do then it is at your own risk Specifically this is for a 32-bit ECU from drive by wire equipped 2006 EDM Impreza STI It has a Renesas SH-7058 CPU The code for it is SH-2e If there is interest then it can be expanded to more ECUs It is possible to decompile the ECU ROM file in Ghidra or Ida pro The ROM data in the ECU memory map starts at 0x0 so it is easy to load in The CPU manuals tell you where I/O etc are such as the serial ports It uses what I have seen called SSM 2 (version 2 of the Subaru SSM protocol) See ssm2-protocol file for general info on the protocol for the diagnostic side It is basically close to KWP-2000/UDS - it uses the same service IDs, failures return 0x7f... in the same way Here are the general steps to gain full control over the ECUs; Connect the test-mode connector in the car - not 100% sure this is needed or even present on all cars Some cars have the test connector also wired to the diagnostic port, you can make a special cable with the test pin permanently pulled to ground, or on a switch Connect using a diagnostic cable Any normal k-line cable will work, sometimes they get called vag-KKL, cables with FTDI chip in definitely work e.g. FT232R Use 4800 baud, 8 data bits, no parity, 1 stop bit (1 start bit inferred) Packets from the tester to the ECU in this mode are in the following format 0x80 0xf0 0x10 [data length 1 byte] [data bytes...] [sum checksum of everything before this checksum byte, 1 byte so & 0xFF] Packets from the ECU replying to the tester will start with 0x80 0x10 0xf0 (source and destination swapped) Send 0xbf to the ECU e.g. 0x80 0xf0 0x10 0x01 0xbf 0x40 This is an init type command which is needed to start things off The ECU replies with a fair amount of data If you want then you can check for the test mode connector being set/connected in the data Send 0x81 in a packet Send 0x83, 0x00 in a packet Now we need to authenticate Send 0x27 0x01 in a packet The ECU will reply 0x67, 0x02, [4 byte seed] You need to run the seed through an algorithm to generate a key and send that back to the ECU Send the key back: 0x27 0x02 [4 byte key] If successful the ECU will reply with 0x67 Now send 0x10 0x85 0x02 The ECU should reply 0x50 At this point, immediately change baud rate to 15625 Wait for some amount of time to allow the ECU to also change baud rate before you send any more packets, in my code I put a sleep of 300ms which is probably overkill but works In this mode it is possible to send arbitrary code to the ECU and have it execute it I have been testing with the OpenECU kernel from EcuFlash 1.28 but it is not clear what license is on this, so not sure if I can distribute or reuse it or not. I have asked for confirmation The EcuFlash kernel for this ECU has code to carry on communication, run CRC32 checks on areas of data in the ECU and to read and write to the ECU If it is not allowed to re-use the OpenECU kernel then a new one could be made from scratch. There are a lot of sample source code files on the Renesas website for this ECU - some related to erasing and writing flash, talking over serial etc I will carry on explaining while assuming that the OpenECU kernel can be used Use service 0x34 to request a data download (download means FROM us TO the ECU) In the ECU code there are restriction on where you can write this to - specific area of RAM, and size limitation Assuming you are writing to RAM from address 0xffff3000 onwards, and your code/kernel is 3112 bytes long (0xc28) For whatever reason you don't need to send the first 0xff for the address, the ECU assumes it I am not totally sure on the format of this but it works, the ECU does specifically check for the 0x04 in the middle Send the following in a packet: 0x34 [(address >> 16) & 0xFF] [(address >> 8) & 0xFF] [address & 0xFF] 0x04 [(size >> 16) & 0xFF] [(size >> 8) & 0xFF] [size & 0xFF] e.g. 0x34 0xff 0x30 0x00 0x04 0x00 0x0c 0x28 The ECU should reply 0x74 for OK Now you can transfer the code/kernel using service 0x36 Send a 3 byte target address, as above missing the first 0xff Send max 128 bytes of code/kernel at a time until you have sent the whole thing In this case the code that you send must be encrypted, the ECU decrypts it and stores it in RAM at the target addresses The encryption is very close to the seed/key method but slightly different values fed in e.g. 0x36 [0xff 0x30 0x00] [128 bytes of code] then send the data for address target 128 bytes on 0x36 [0xff 0xb0 0x00] [next 128 bytes of code] Each time the ECU should reply 0x76 for OK Not sure if the next step is needed but it is very strange I think it is basically for checking that the data was sent OK, even though there are checksums on every packet The data is too large to send in a normal packet with a single byte for data length, so maybe that's why it is different to normal Basically send the whole code/kernel in one go, and only this one time, DON'T use the proper packet format Send the raw bytes: 0x53 0xff 0x30 0x00 (start address of download) 0x0c 0x28 (code/download size) [all data bytes of the code in one go] [sum checksum of everything previous] I don't think the ECU replies to this Now to make the ECU run the code you sent, send a final packet: 0x31 0x01 0x01 If OK it will reply 0x71 and immediately run your code From now onwards you need to communicate however the new code/kernel requires The following concerns the OpenECU kernel for this ECU (OpenECU Subaru SH7058 OCP Kernel V0.21) Immediately swap to baud rate 62500 The kernel packets are formatted as the following, no matter which direction 0xbe 0xef [high byte of data size] [low byte of data size] [data bytes] [sum checksum of everything previous] In brief, below are the commands you can run, the code replies with the command byte+0x80 It also sends 0xF~ for errors 0x01 - get kernel version 0x02 - run CRC 32 on an area of ECU memory 0x03 - read a block of data from ECU memory 0x04 - check car battery voltage 0x20 - enable flash 0x21 - disable flash 0x22 - write to flash buffer (prepare to write but not yet) 0x23 - validate flash buffer 0x24 - commit flash buffer (actually write it) 0x25 - erase a flash block, needed before writing Error values: 0xF0 - bad data length 0xF1 - bad data value 0xF2 - programming failure 0xF3 - voltage too low 0xF4 - voltage too high 0xF5 - CRC incorrect 0xFF - bad command Flash can only be erased and then written in blocks, that's just how it works Here are the list of blocks for this CPU: address 0x00000 length 0x1000 address 0x01000 length 0x01000 address 0x02000 length 0x01000 address 0x03000 length 0x01000 address 0x04000 length 0x01000 address 0x05000 length 0x01000 address 0x06000 length 0x01000 address 0x07000 length 0x01000 address 0x08000 length 0x18000 address 0x20000 length 0x20000 address 0x40000 length 0x20000 address 0x60000 length 0x20000 address 0x80000 length 0x20000 address 0xa0000 length 0x20000 address 0xc0000 length 0x20000 address 0xe0000 length 0x20000 If you need to change data inside one of the blocks then you need to wipe the whole block and reprogram it fully Rather than programming the entire ECU every time you can just check the CRC32 for a block, and compare it to your local ROM file To ask for CRC for a block, send the following in a packet; 0x02 [4 byte address, highest byte first] [4 byte length, highest byte first] e.g. for the last block from above: 0x02 [0x00 0x0e 0x00 0x00] [0x00 0x02 0x00 0x00] The ECU should reply 0x82 [4 byte CRC, highest byte first] This is as far as I have tested so far and can confirm the above works To read an area of the CPU, use the 0x03 command and also send a 4 byte address, plus two bytes for the length To erase a flash page use the 0x25 command with a 4 byte address which should point to the start of a flash block To write to the flash buffer use command 0x22 with a 4 byte address with 512 bytes of raw data To commit the flash buffer use command 0x24 followed by the 4 byte address and 4 byte CRC, I assume the address should be the start of a flash block
About
No description, website, or topics provided.
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published