ChristianIvarsson / eculoader

1 stars 1 forks source link

Bootloader E39A compatibility #1

Open lgrunenberg opened 7 months ago

lgrunenberg commented 7 months ago

Hi, first of all thanks for all the work. This is really stunning!

I am facing some issues running the bootloader for MCP5566 on my ACDelco E39A ECU. After uploading it to 0x40004000 and executing the code from the same location the ECU simply resets into the ROM software.

Unfortunately i'm not very good at hacking ECUs and coming up with loader solutions but i have somewhat verified that the code really executes by replacing the first instruction from the binary data by an infinite loop. In that case the ECU freezes and does not reboot, which leads me to believe that it's then really stuck in said loop.

I moved the infinite loop around a bit but i could not really find the exact issue the ECU has with the code. I have suspected that switching to supverisor mode in MSR but it seems that this is not the issue. I can also reach C code but at latest when nulling the PSR registers, the ECU crashes ad resets.

Am i missing something or is the E39A really that different to the E39/E78 making the loader solution not applicable?

BTW i had to change to diagnostic mode 2 instead of diagnostic mode 4 because mode 4 would result in a 7f1012 response

ChristianIvarsson commented 7 months ago

Hi! I don't have any hands-on with 39A but it seems fairly similar in terms of HW layout and main MPU.

I recall having a lot of problems with the paged mmu on SAAB's firmware which took some messing around so could be another case where it must be done in a particular order to prevent crashing.

In preloader/preloader.c: If you place a loop just before "if (!mainExtract(mainloader,(uint8_t *)mainbase))" - does it stay alive?

Another place to check is mainloader/mainloader.c main_Init() just before configureTBL() ( This code can be found in mainloader/mainhelper.S )

If you're able to make it stay alive by commenting out / putting a loop just before it it's for sure the culprit.. again 😄

You don't happen to have a full dump of the thing? Would help a lot if I could figure out how they configure their mmu

Edit: I recall having to add a modeword to the thing to be able to function on e39 and e78 so you could also have to write a 1 (32-bit, big endian so it'll be 00 00 00 01 if seen as a byte array) to offset 4 to make it aware of which type of ecu it's running on

lgrunenberg commented 7 months ago

Hi! I don't have any hands-on with 39A but it seems fairly similar in terms of HW layout and main MPU.

That's what i thought as well, to my uneducated view it seems that it's just a revised version of the E39. But maybe not.

I recall having a lot of problems with the paged mmu on SAAB's firmware which took some messing around so could be another case where it must be done in a particular order to prevent crashing.

In preloader/preloader.c: If you place a loop just before "if (!mainExtract(mainloader,(uint8_t *)mainbase))" - does it stay alive?

Another place to check is mainloader/mainloader.c main_Init() just before configureTBL() ( This code can be found in mainloader/mainhelper.S )

If you're able to make it stay alive by commenting out / putting a loop just before it it's for sure the culprit.. again 😄

The furthest i can put the loop making the ECU freeze instead of reset is in preloader.c:212. Even then i have to patch the startup.S:45-46 to only modify the supervisor bit:

lis %r3, 0
ori %r3, %r3, 0x4000

Otherwise the ECU will reset even at this point.

You don't happen to have a full dump of the thing? Would help a lot if I could figure out how they configure their mmu

I have a dump of everythig in flash that i can get without a loader, range 0x4000 - 0x300000. Seems to include the bootloader and the OS. Unfortunately (while i do understand more or less what your loader does) i can't get my head around what they are doing in the original firmware with all those checksums and other obfuscation. I'd love to share the dump if it helps, though.

Edit: I recall having to add a modeword to the thing to be able to function on e39 and e78 so you could also have to write a 1 (32-bit, big endian so it'll be 00 00 00 01 if seen as a byte array) to offset 4 to make it aware of which type of ecu it's running on

Seems i can't even get to the point where the modeword is evaluated :(

ChristianIvarsson commented 7 months ago

I have a dump of everythig in flash that i can get without a loader, range 0x4000 - 0x300000. Please do share :) Regular e39 is using the first 128k~ as recovery so it's likely that is more than enough to figure out why it's crashing. (maybe even create some Frankenstein's monster binary that is able to limp along on a regular e39)

The furthest i can put the loop making the ECU freeze instead of reset is in preloader.c:212. That's another place where e78 (another mpc5566 hw) would act up if one of the internal devices were disabled. Not entirely certain how much can be kept running without having errant interrupts but I guess one could try commenting out everything except "(volatile uint32_t)0xFFF48008 = 0;"

btw: Which compiler version/os are you using? Been switching between gnutoolchains' windows toolchain and whatever Debian had back when I wrote the code. Noticed the one on Windows had some problems with optimizations (Sole reason there's #pragma GCC push_options sprinkled here and there) :)

lgrunenberg commented 7 months ago

Please do share :)

I guess GitHub would not be happy with me sharing this binary here, would you mind me sending it to you by mail?

Not entirely certain how much can be kept running without having errant interrupts but I guess one could try commenting out everything except "_(volatile uint32t)0xFFF48008 = 0;"

Tried that, the next command that makes the ECU reset is rebaseInterrupt(tablebase);. Seems the ECU does not like messing with the interrupt config, really. When i comment out said command, the ECU finally stays alive even without introducing an infinite loop anywhere but it is not usable (no broadcast messages, no response to any commands). On the other hand this is somewhat expected as CAN interrupts and others are not configured.

btw: Which compiler version/os are you using?

I'm currently compiling with powerpc-linux-gnu-gcc v11.4 on Ubuntu 22.04. I had to do some minor modifications to make it compile which i pushed here: https://github.com/lgrunenberg/eculoader Not 100% sure if the compiler is really suited but it produces pretty simmilar machine code.

ChristianIvarsson commented 7 months ago

Hi again Edit: ( Mail received so commented out )

I'm currently compiling with powerpc-linux-gnu-gcc v11.4 on Ubuntu 22.04 Rarely if ever had any issues with later compilers on Linux platforms so I bet it's fine. Think I'm running 22.04 on the laptop so can do a quick check just to verify. I bet it's just the firmware that has configured the ECU in some weird way but it's always nice to use the same stuff on both ends :)

ChristianIvarsson commented 7 months ago

Figured it out!

I'm really sorry for this japping, should've noticed that you removed -mspe much earlier.

the're using a weird version of PowerPC so some instructions are missing.

It seems they don't have all the required packages for a installation on their mirror (tried universe, multiverse and several older repos) so a very ugly chroot situation had to be cooked up.

Wrote down the steps in https://github.com/ChristianIvarsson/eculoader/blob/main/mpc5566/HOWTO.md

Edit - Apparently still issues? Maybe one should look into buying one on ebay etc? :)