Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TODO] Work out i2c/UART bootloader for flashing/recovery. #7

Open
fifteenhex opened this issue Apr 18, 2020 · 33 comments
Open

[TODO] Work out i2c/UART bootloader for flashing/recovery. #7

fifteenhex opened this issue Apr 18, 2020 · 33 comments
Assignees

Comments

@fifteenhex
Copy link
Member

  • Work out how the UART bootloader works so black or bricked boards can be flashed.

  • Add the needed jumper/jumpers to the board so that it can be triggered.

@kadamski
Copy link
Contributor

Is the bootrom dump available somewhere to look at it?

@fifteenhex
Copy link
Member Author

It's here.

https://github.com/fifteenhex/mc200c2camerahacks/blob/master/msc313ebootrom.bin

Since playing with the i2c thingy I'm wondering if the "UART" bootstrap pin setting I have might mean just stopping it booting to interfering with the i2c. Hopefully it isn't. Loading over UART normally is much better than spi over i2c with a weird hacky interface.

@fifteenhex
Copy link
Member Author

Note to self: UART reading is in the M5 bootrom but not the I3 one. I3 probably doesn't have UART boot.

@kadamski
Copy link
Contributor

kadamski commented Apr 20, 2020

I3 probably doesn't have UART boot.

So for the msc313e, the only recovery option (in case of broken flash content) would be via i2c, right?

@fifteenhex
Copy link
Member Author

So for the msc313e, the only recovery option (in case of broken flash content) would be via i2c, right?

The SD card should be bootable. I just haven't looked hard enough yet for the pin to make it try to boot it. The strings in the I3 rom for that match up with the M5 rom and I'm already using it on the M5.

@fifteenhex fifteenhex changed the title [TODO] Work out UART bootloader for flashing/recovery. [TODO] Work out i2c/UART bootloader for flashing/recovery. Apr 20, 2020
@fifteenhex fifteenhex self-assigned this Apr 20, 2020
@kadamski
Copy link
Contributor

About the bootrom deassembly, have you worked out something already? Where is the code stored in the address space, what is starting point, where is vector table stored? Anything that could help me get up to speed?

The SRAM is at 0xa0000000, peripherals are somewhere above 0x1f000000, RAM is at 0x20000000, but the beginning of the binary uses some 0xeaXXXXXX values so this doesn't seem to be a vector table.. or is this binary mapped in 0xea000000?

@fifteenhex
Copy link
Member Author

The binary is mapped to 0x0. The vector table is at the beginning. The table is made up of ARM instructions instead of jump locations. The first 4 bytes should be the reset vector and that should be a branch to some ARM code that is right after the vector table.

What are you using for disassembly? I'm using hopper v4. I can give you my scrappy hopper database if that helps?

@kadamski
Copy link
Contributor

Oh, interesting, I though on ARM the vectors contains addresses, not instructions, thats useful, I have to change my reasoning, then.

I'm trying to use ghidra as it is opensource and free. I have some limited radare2 experience but the only real reverse engineering of binaries I did in last 10 years was for the esp8266 at the very beginning of its hype when none of the tools understood xtensa CPUs so all I had was objdump.. So I have a lot to catch up. The hopper has some demo version but since I'm not using such tools too often I wouldn't want to pay for it. But then its not the price of IDA so it would't broke me if its is worth it. Do you find it better for such tasks than Ghidra for example?

@fifteenhex
Copy link
Member Author

fifteenhex commented Apr 21, 2020

I tried radare2 via the cutter interface and it was a bit painful. Hopper probably isn't as good as IDA at working out all of the control flow etc but I think it was worth the $100.

@kadamski
Copy link
Contributor

Did you manage to find out what is at 0x1f200800 ?

@fifteenhex
Copy link
Member Author

fifteenhex commented Apr 22, 2020

According to my notes in the DTS (https://github.com/fifteenhex/linux/blob/4bf698c9b74b02df400bf635b851f85ccf9752ed/arch/arm/boot/dts/chenxing-v7.dtsi#L309) that's where the mailbox is. I think it's a mailbox between the ARM cpu and a house keeping 8051 that is there to handle deep sleep. The video processing parts also mention a 8051 and in some places openrisc.... so I'm not really sure which of them are in the chip.

@kadamski
Copy link
Contributor

So basically all the operations on this peripheral are unknown? Od you did manage to find some code that explains what is done there?

@fifteenhex
Copy link
Member Author

The vendor code writes the kernel log buffer address into some registers there on start up:
https://github.com/fifteenhex/linux-ssc325/blob/89341c7012404c72e192f198b2ea6405ec80d15d/arch/arm/mach-sstar/infinity3/soc.c#L404

I'm guessing that's so whatever is behind there is able to write messages in to the kernel log. Other than that I haven't found much other info about it. There are some interrupt numbers that seem to be interrupts from an 8051 to the ARM which might be related.

It's hard to tell though as so much of the code contains vestigial pieces from code for older chips they hacked up. It's possible the registers still exist but nothing is actually connected there.

@fifteenhex
Copy link
Member Author

I think I see what you where talking about now. I just noticed the bootrom writes to the mailbox box right after disabling the WDT. I guess it's the ARM core telling the PM core that it's alive.

@kadamski
Copy link
Contributor

Yes, there are a bunch of such writes in the bootrom, I think I've seen this in more than one place. But I hadn't have too much time in last day to look at this deeper. Know it may do something related to PM might be good enough for now.

@fifteenhex
Copy link
Member Author

I thought I might have seen some writes to it in the code that runs in SRAM to do the suspend (https://github.com/fifteenhex/linux-ssc325/blob/89341c7012404c72e192f198b2ea6405ec80d15d/arch/arm/mach-sstar/infinity3/sram.S#L145) but it looks like I was miss remembering.

I think it is PM related though. The PM code writes the same 0xbabe magic number and then seems to try to turn the ARM core power off via a gpio. My gut feeling is that when it comes back up it writes 0xbabe into the mailbox register to tell whatever is doing the PM not to try waking it up again.

@kadamski
Copy link
Contributor

In the function that seems to be like a main() (it is called at the end of the reset vector just before endless loop), I can see many writes to this address but this seems like some kind of "checkpoints mechanism" as each write there happens after some operation and the value written is incremented. So first write is 0xb01, then 0xb02 and 0xbff is written at the end of this function and such a call seems to be done before (and sometimes after) important actions and each of them has unique value for the argument. Maybe its just for debugging purposes?

@fifteenhex
Copy link
Member Author

It's coming back to me now. Yeah, they seem to write a value into a scratch register at different points in the boot rom. I think so they can work out where it died when debugging like you wrote.
Disregard what I wrote about PM. I think I was misremembering.

@kadamski
Copy link
Contributor

kadamski commented Apr 24, 2020

Another unknown peripheral I stumbled opon in bootrom code is at 0x1f28041c and 0x1f28042c. Those registers seems to be writen in the function just before configuring pinmux for NAND/SDIO.
Have you stumbled opon those somewhere maybe?

There is also this 0x1f280400-0x1f28048f which seems to be somehow related to loading something from SD card (it is used on the function at 0x2bf8 in bootrom) but the FCIE/MMC controler seems to be at 0x1f282000 according to devicetree. The code suggest, however, that it is using similar register layout as the one described in mstar-fcie.c so maybe this is another instance of this peripheral?

@fifteenhex
Copy link
Member Author

Looks like that's the "eMMC" copy of the sd host IP block that isn't broken out on the QFN80

https://github.com/fifteenhex/linux/blob/ff5b8260c9748cded793faecb7c3d2590cde928e/arch/arm/boot/dts/infinity.dtsi#L122

The chip seems to always output E:CD on boot which seems to be about checking the eMMC interface to boot from it but the card detect signal not being low.

@kadamski
Copy link
Contributor

Looking at the code of the function at 0x1a4, I can see the place where E:CD is printed but there should also be "Load IPL to IMI from eMMC failed! [HALT]\r\n" printed after it. But my understanding of the code might be wrong as I basically cannot see how this string could ever not be printed - it seems like this print was unconditional which is strange. I guess you don't see this message, right?

One thing I'm having problem to understand is that the main function seems to be reading the SPI0_DI pin value to decide what to do next. Then, the unknown to me register 0x1f0070c0 is read and if it is not 0x20 and not 0x4, the value read from DI is overwritten with 1.

Depending on this value, different part of pinctrl is configured. If it is 1, 0xC8 (which you mark as SD/SDIO pull up/strength which would make sense) and 0xA0 (which you did not document), if it is 0, 0xC0 and 0xC4 offsets are used which you documented as NAND drive/pull up (BTW, this means it is for eMMC?). Also least significant bit of 0x4c and 17 least significant bits of the 0x140 offset (which are undocumented) are cleared.

BTW, the offset 0x20 seems to be also little more complicated than you described in pinctrl-mstar.c - in case the value read from DI is 0, bits 0 and 3 are cleared, while bit 2 is set. in case the value from DI is 1, bits 0, 2 and 8 are cleared while bit 3 is set. This chip still has quite some unknowns :)

Anyways this value read from DI seems to be choosing if we are going to boot from SD card or not and some bits on 0x1f0070c0 seems to be forcing this option?

@fifteenhex
Copy link
Member Author

I guess you don't see this message, right?

On the infinity3 it comes out on every boot as if it always tries it before spi. On the mercury5 it comes out if you configure the boot straps for SD and don't have a card in.
I think I actually used that message coming out to validate boards before putting flash on them. ;)

One thing I'm having problem to understand is that the main function seems
to be reading the SPI0_DI pin value to decide what to do next.

Interesting. If you pull the pm spi clk line high it complains about not being able to init nand.
I wonder if DI is used to select which SD host to try?

Then, the unknown to me register 0x1f0070c0

I think 0x1f0070c0 is within the "DID" region that starts at 0x1f007000. The first few bytes there are a unique chip ID.

This is what it looks like from uboot

=> md.b 0x1f007000 100
1f007000: cf 15 00 00 53 47 00 00 ee 51 00 00 00 00 00 00    ....SG...Q......
1f007010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0070f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

NAND drive/pull up (BTW, this means it is for eMMC?).

I think the eMMC controller can also drive raw NAND and they call it NAND. From what I remember the offsets for the NAND drive strength came from the vendor eMMC driver.

BTW, the offset 0x20 seems to be also little more complicated than
you described in pinctrl-mstar.c

To work most of that out I was finding what GPIO the pin mapped to, setting it high and then changing registers in the pinctrl region until something was connected and disconnected the gpio making it go low again.

This chip still has quite some unknowns :)

Just a screenshot of the registers from the mystery areas would help so much. But I guess it would be less fun that way.

Anyways this value read from DI seems to be choosing
if we are going to boot from SD card or not and some bits on
0x1f0070c0 seems to be forcing this option?

I think the DID is lasered onto the chip at the factory. Maybe what it's checking at 0xc0 is a packaging register so the boot rom can know which packaging it's in.
One of the versions of the IPL bootloader part after the boot rom can tell if the chip has DDR2 or DDR3 and what the size is so that information has to be somewhere but I haven't worked that out yet.

By the way do you want a board to work on?

@kadamski
Copy link
Contributor

I wonder if DI is used to select which SD host to try?

I'm slowly working out the code around that to fully understand the boot logic.

I think 0x1f0070c0 is within the "DID" region that starts at 0x1f007000. The first few bytes there are a unique chip ID.

That would make sense. I did, however, a typo and the offset is 0x1c0, not 0xc0, sorry for that. It actually does something like this:

  gpio_spi0_di = read_volatile_2(0x1f2079c8);
  force_di = __DAT_1f0071c0 & 0x3c;
  gpio_spi0_di_value = gpio_spi0_di & 1;
  if (force_di != 0x20 && force_di != 4) {
    gpio_spi0_di_value = 1;
  }

However your explanation for DID does explain this code in the same function:

some_chip_id = (char)_DAT_1f00700c;
  if (some_chip_id == '\0') {
    ___REG_SCRATCH? = 0xb0c;
  }
  else if (DAT_a000000a != some_chip_id) {
      uart_print("CID check failed! [HALT]\r\n");
      do {
      } while( true );
  }
  (*(code *)&SUB_a0000000)();  // call the IPL loaded to SRAM

So basically if the value at offset 0xc (seems to be ChipID?) is not 0, the address 0xa in the IPL will be checked to match this CID before running IPL. However the offset 0xa, according to your https://linux-chenxing.org/blobs/ipl.html, would contain the part of size of the image. Maybe it is overwritten by something else later, however.

It is interesting, however, that it just reads the 0x1f2079c8 without setting it in any way so it must be INPUT by default, is that right? But if there's no internal pullup and this pin would be floating? Anyways, if SPI NOR is connected, what will be the default state of DI? Is it idling at 0 or 1?

To work most of that out I was finding what GPIO the pin mapped to, setting it high and then changing registers in the pinctrl region until something was connected and disconnected the gpio making it go low again.

I'm nothing than impressed on how much of that thing you was able to reverse engineer. Respect.

Just a screenshot of the registers from the mystery areas would help so much

You mena the screenshot of some datasheet/programming manual?

By the way do you want a board to work on?

That would be cool to have. I have started ordering parts but to be honest I have never soldered QFN packages or anything smaller than 0805 or maybe 0603. I would be happy to buy a prototype from you and actually have sent an e-mail asking for that like a week or so ago. But I guess you do get a lot of those so it was easy to get lost. Please check if you can find it and if not, let me know I'll drop you a message again so that we could discuss this. Thank you.

@fifteenhex
Copy link
Member Author

I'm slowly working out the code around that to fully understand the boot logic.

I can solder a wire onto my board and see what happens?

That would make sense. I did, however, a typo and the offset is 0x1c0, not 0xc0, sorry for that. It

Looks like there are some non-zero bytes there. I think each chip select in the register controller thing is 0x200 long so if I'm right that'd put that offset still inside the DID region.

1f007100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f007190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0071a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0071b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0071c0: 20 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ...............
1f0071d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0071e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
1f0071f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

However the offset 0xa, according to your https://linux-chenxing.org/blobs/ipl.html,
would contain the part of size of the image. Maybe it is overwritten by something
else later, however.

That's possible. It's also possible what is there is different to what I thought it is. I don't think so as I was able to load the uboot SPL as the IPL in the past. I just couldn't work out how to init the DRAM so it couldn't do anything.

It is interesting, however, that it just reads the 0x1f2079c8

One thing I just noticed is that that offset is in the normal gpio controller so that isn't the flash spi pin but on normal spi0 controller. I'll have a go at poking it. :)

Anyways, if SPI NOR is connected, what will be the default state of DI? Is it idling at 0 or 1?

I'll check.

I'm nothing than impressed on how much of that thing you was able to reverse engineer. Respect.

Thanks :)

Just a screenshot of the registers from the mystery areas would help so much
You mena the screenshot of some datasheet/programming manual?

Yeah. I have datasheets for other mstar chips that have the same ip blocks like the SD controller.
But for the lower level chip specific stuff I have nothing except vendor code. If we could just get a screenshot of the "pm sleep" registers I think it'd unlock everything.

actually have sent an e-mail asking for that like a week or so ago.

Ah crap. Sorry about that. I got about 50+ mails asking for boards. I had to stick everything in a folder that I'm slowly working through replying to people. Could you send me another one? I'm not getting much mail now so I'll see it right away.

@kadamski
Copy link
Contributor

1f0071c0: 20
Now it all makes sense. The bootloader is taking bits from 2 to 5 from this register:

force_di = __DAT_1f0071c0 & 0x3c;

Then, there is a series of if statements for different values there. If none of the bits is set, we get this message printed - "Check DID_KEY h70 bits[5:2] for storage... undefined! [HALT]". We have 4 possibilities as the bits seems to be exclusive (only one can be set at a time):

  • 0x4 - if something goes wrong, we can get "SPINAND init failed! [HALT]\r\n" printed
  • 0x8 - if something goes wrong, we can get "Load IPL to IMI from eMMC failed! [HALT]\r"
  • 0x10 - if something goes wrong, we can get "NAND init failed! [HALT]\r\n"
  • 0x20 - in this case, the address 0x14000004 is comared to 0x5f4c5049 (which is "IPL_"). And this area, according to my understanding, is the memory mapped NOR and "IPL_" is there at offset 0x4 which is about right!

Also, in case of 0x8 and 0x10, the value read from SPI0_DI is ignored anAlso, id is assumed 1.

The dump you've shown gives us 0x20 which, again, makes sense. But this value is checked after a function that, among others, reads SD_CDZ pin is called and only if it returns != 0. So this DID_KEY (btw, I'm wondering what "h70" means.. would that be 0x70? Maybe an offset in the DID_KEY field which would mean it starts at 1f007150?) seems to be something like default boot source. I now have to fully understand this function that is called before DID_KEY is resolved.

That's possible.

So far I did not find any evidence for that. But I'll keep an eye for that.

I got about 50+ mails asking for boards.
This is exactly what I though. No problem for me. I'll drop you an additional e-mail in few minutes.

@kadamski
Copy link
Contributor

I have one additional unknown - the function I mentioned in my previous comment (I'm calling it boot_sd_or_nand() for now) is trying to read one of two PM_GPIO addresses, if the SPI0_DI was 1 (or was forced to 1), it will use 0x1f001f1c, if it was 0 - it reads 0x1f001e1c. So the offset in the PM_GPIO is either 0x11C (SD_CDZ) or 0x1C - this one I don't know, as you don't mention it in gpio-msc313-pm.c. If you have any idea. In both cases, the code will read the bit 4 of the register so it checks the IN value and returns it. If this function returns 1 (so no card present), the "E:CD" is printed.

So if SPI0_DI was 1, this gives us the information if SD card is present and I guess something similar must be there for the other case.. what would that be? eMMC?

@fifteenhex
Copy link
Member Author

0x1c is PM_GPIO_7 (https://github.com/fifteenhex/linux/blob/6dc9f3186a721550c59820a0a9073034bda8601c/drivers/gpio/gpio-msc313-pm.c#L51) which isn't physically present on the MSC313E.

I think there might be 3 similar blocks in the chip, "sdio", "emmc" and "nand". I think what you're looking at is probably the code to work out which one to try.

@kadamski
Copy link
Contributor

6dc9f3186a721550c59820a0a9073034bda8601c/drivers/gpio/gpio-msc313-pm.c#L51

This is cool. I was looking at the file in the msc313e branch which has a lot less information about this PM_GPIO offsets. I'll switch to msc313e_dev_v_5_6_rebase instead. I guess this is the branch you are currently working on?

BTW.. Since we don't have datasheet, the only source of the information about the register map is to read the drivers and devicetree. This is spread in many places and is hard to work with. I could spend some time preparing some kind of markdown documentation for the peripherals so that we could have all this in one place. Do you think that would be useful? Would linux-chenxing.org be a good place for that? Would you be willing to review such informations?

@fifteenhex
Copy link
Member Author

Do you think that would be useful? Would linux-chenxing.org

I've started doing that now. I'm going to move the register maps out of the drivers in to a page under ip blocks. I've done that for the SAR registers so far.

@kadamski
Copy link
Contributor

I've started doing that now

Oh, I didn't notice that. That is something I can help with for sure as I believe you have a lot of other important topics to take care of. I think it might also a good opportunity to spread the knowledge an maybe clarify some things.

@fifteenhex
Copy link
Member Author

I'll switch to msc313e_dev_v_5_6_rebase instead.
I guess this is the branch you are currently working on?

Sorry I should have commented on this last time.. that is my current working branch. That's where all the latest info is so far. I'm rebasing it pretty often at the moment so it's likely to change.

I can add you as a committer to linux-chenxing so you can add anything you find directly if you want?

@kadamski
Copy link
Contributor

I can add you as a committer to linux-chenxing so you can add anything you find directly if you want?

I would still prefer you to take a look at what I'm adding there as I'm not yet that confident about some parts. Unless you find it to disturbing to review that, in this case I can commit directly.

@fifteenhex
Copy link
Member Author

I would still prefer you to take a look at what I'm adding
there as I'm not yet that confident about some parts.

That makes two of us. ;)

Unless you find it to disturbing to review that, in this case I can commit directly.

I don't remind reviewing stuff but the wiki is just a though dump at the moment anyway so I don't think there is any harm just committing direct as you find things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants