DIGIC 8+ MPU investigation

Started by coon, December 14, 2020, 07:17:02 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

leegong

structure of MPU Msg in RP is exactly same as that in EOS.
MainTimeLapse_SW1OFF : mpu_send(0x5 0x3 0x21 0x00 0x00);
MainTimeLapse_SW1ON : mpu_send(0x5 0x3 0x21 0x01 0x00);
MainTimeLapse_SW2OFF : mpu_send(0x5 0x3 0x22 0x00 0x00);
MainTimeLapse_SW2ON : mpu_send(0x5 0x3 0x22 0x01 0x00);

leegong

Quote from: coon on December 14, 2020, 10:58:34 PM

MEMR 0 FFFFF


Does a hex dump from a region of the MPUs memory. First argument is start address, second argument is number of bytes to read.
Maximum value allowed for second argument is FFFFF.

When executing the command above, the complete firmware of MPU is dumped, since firmware is mapped to 0.
From address ~0x60000 to 0xFFFFF data bytes are all 0xFF on EOS RP and do not need to be dumped.

The firmware of MPU on EOS RP can be dumped by executing the following command:


MEMR 0 60000


Be careful not to type MEMW by accident, which will overwrite data in RAM and may lead to undefined behaviour of the MPU! This meight destroy hardware components in worst case.

Based on analyzing of RP MPU firmware, Both of First argument and second argument are address ,
so Usage : MEMR StartingADDR EndingADDR
StartingADDR and EndingADDR could add prefix "0x"

leegong

LockSw                        // MPU_send_Msg0300(0x5,0x3, 0x0,LockSw,0x0);               
CardCover                    // MPU_send_Msg0301(0x5,0x3, 0x1,CardCover,0x0);           
BatCover                      // MPU_send_Msg0302(0x5,0x3, 0x2,BatCover,0x0);           
CF2DetectSw               // MPU_send_Msg0304(0x5,0x3, 0x4,CF2DetectSw,0x0);
ELButton                     // MPU_send_Msg0312(0x5,0x3, 0x12,ELButton,0x0);
SubDialLockSw            // MPU_send_Msg031B(0x5,0x3, 0x1B,SubDialLockSw,0x0);
Sw1                           // MPU_send_Msg0305(0x5,0x3, 0x5,Sw1,0x0);
Sw2                           // MPU_send_Msg0306(0x5,0x3, 0x6,Sw2,0x0);
AELockButton             // MPU_send_Msg0307(0x5,0x3, 0x7,AELockButton,0x0);
AFStartButton             // MPU_send_Msg0308(0x5,0x3, 0x8,AFStartButton,0x0);
AFFrameSelectButton       // MPU_send_Msg030B(0x5,0x3, 0x8,AFFrameSelectButton,0x0);
MIFSw                         : Off
ShotModeButton         // MPU_send_Msg030A(0x5,0x3, 0xA,ShotModeButton,0x0);
M                             // MPU_send_Msg030C(0x5,0x3, 0xC,M,0x0);
SetButton                     // MPU_send_Msg030D(0x5,0x3, 0xD,SetButton,0x0);
MenuButton                   // MPU_send_Msg030E(0x5,0x3, 0xE,MenuButton ,0x0);
PlayButton                    // MPU_send_Msg030F(0x5,0x3, 0xF,PlayButton ,0x0);
InfoButton                    // MPU_send_Msg0310(0x5,0x3, 0x10,InfoButton ,0x0);
EraseButton                  // MPU_send_Msg0311(0x5,0x3, 0x11,EraseButton ,0x0);
LvMovieStartButton       // MPU_send_Msg0314(0x5,0x3, 0x14,LvMovieStartButton ,0x0);
CrossUp                       // MPU_send_Msg0315(0x5,0x3, 0x15,CrossUp,0x0);
CrossDown                   // MPU_send_Msg0316(0x5,0x3, 0x16,CrossDown,0x0);
CrossRight                   // MPU_send_Msg0317(0x5,0x3, 0x17,CrossRight,0x0);
CrossLeft                     // MPU_send_Msg0318(0x5,0x3, 0x18,CrossLeft,0x0);

kitor

A few details based on Digic X / EOS R5 MPU firmwares (both internal MPU and grip MPU).

Details on BG-R10 battery grip MPU UART: https://www.magiclantern.fm/forum/index.php?topic=7531.msg242570#msg242570

Firmware

For Ghidra I got a better disassembly using ARM Cortex instead of ARMv7.

1st stage bootloader starts at 0x0. It is very small compared to ICU counterpart. Some small chunks of bootloader are copied to RAM before execution.
Then there's a usual cstart() (including copy of some data into RAM) which follows up to a "regular" DryOS.
Early init_task is similar, but differences start quickly.

Init task literally kickstarts everything by filling in interrupt handlers, msg queues, flags, semaphores, registering assert handler and then spawning a single MainTask.

MainTask is where all the other hardware init happens (including spawning all other tasks at once). When its done, it goes into a loop that handles messages from queue.

There's no functions like task_create, firmware calls "internal" kernel functions directly. So it is definitely a lightweit version of DryOS.
R5 firmwares runs DryOS 060+p8, like ICU.

New thing, visible on R5/R5 grip is DbgMgr. Firmware is much more verbose on UART. R/RP/R grip used uart_printf directly.
It seems a simplified form of DbgMgr from EOS firmwares. `DryosDebugMsg` call format is the same.

As said, is it very verbose now (this is UART output on R5):

MON>>>      94.063 : MATRIX ksout:2
      94.071 : MATRIX ksin :2
      94.650 :  [LENS] kick-> 2
      94.669 :  [LENS] not kick-> 0
      94.733 :  [LENS] Event -> 2
      94.742 :  [!!LENS] CtrlEvent -> 5
      94.761 : VBAT2Off VDD2Off
      95.905 :  [LENS] Event -> 0
      95.924 :  [LENS] waitTimer start
     100.321 : AllTask InitComp
     114.086 : powerSupply stop
     114.105 :  [STM] STM_STATE_T:   -> SupplyOff
     116.426 : ----9V req
     117.336 : BATT INFO1 -> 4
     117.344 : BATT INFO2 -> 0
     117.478 : powerSupply stop
     117.497 :  [STM] STM_STATE_T:   -> SupplyOff
     151.749 : para2:1
     197.445 :  [!!LENS] timer comp-> 0
     197.473 :  [LENS] event Que Empty...
     696.636 : Rcv ICU Cmd :COM_INIT
     696.647 : Rcv ICU ID  :0x00
     696.655 : Rcv ICU DATA:0x00
     696.758 : init PDIC_USB_DET = High
     699.681 : ------------Startup Time Report------------
     699.726 :   NOT First run
     699.815 :   Lens  OFF
     699.860 :   ICU RESET RELEASE              [   68 ms]
     699.906 :   Response COM_INIT_DATA_REQUEST [    3 ms]
     699.939 : -------------------------------------------
     702.067 : Sw Rcv ICU Cmd :0x03
     702.116 : Sw Rcv ICU ID  :0x32
     702.165 : Sw Rcv ICU DATA:0x00
     702.266 : Sw Rcv ICU Cmd :0x03
     702.273 : Sw Rcv ICU ID  :0x32
     702.281 : Sw Rcv ICU DATA:0x00
     702.878 : Rcv ICU Cmd :COM_TIMER
     702.984 : Rcv ICU ID  :0x04
     703.032 : Rcv ICU DATA:0x00
     703.152 : Sw Rcv ICU Cmd :0x02
     703.159 : Sw Rcv ICU ID  :0x14
     703.167 : Sw Rcv ICU DATA:0x00
     704.864 : Sw Rcv ICU Cmd :0x02
     704.872 : Sw Rcv ICU ID  :0x14
     704.880 : Sw Rcv ICU DATA:0x00
     706.378 : Sw Rcv ICU Cmd :0x02
     706.386 : Sw Rcv ICU ID  :0x2E
     706.394 : Sw Rcv ICU DATA:0x02
     706.932 : Rcv ICU Cmd :COM_INFO
     706.981 : Rcv ICU ID  :0x12
     707.134 : Sw Rcv ICU Cmd :0x02
     707.183 : Sw Rcv ICU ID  :0x14
     707.292 : Sw Rcv ICU DATA:0x00
     707.456 : Sw Rcv ICU Cmd :0x02
     707.464 : Sw Rcv ICU ID  :0x2E
     707.471 : Sw Rcv ICU DATA:0x02
     707.489 : Rcv ICU DATA:0x00
     707.514 : Rcv ICU Cmd :COM_INFO
     707.521 : Rcv ICU ID  :0x31
     707.529 : Rcv ICU DATA:0x00
     707.539 : NOT exist WFT(default target 1)
     812.484 : Rcv ICU Cmd :COM_INFO
     812.492 : Rcv ICU ID  :0x10
     812.500 : Rcv ICU DATA:0xB4
     816.857 : MPU_ERROR_HISTORY[4]:0x00
     816.880 : MPU_ERROR_HISTORY[5]:0x00
     816.888 : MPU_ERROR_HISTORY[6]:0x00
     816.895 : MPU_ERROR_HISTORY[7]:0x00
     816.903 : MPU_ERROR_HISTORY[8]:0x00
     881.214 : Rcv ICU Cmd :COM_INFO
     881.221 : Rcv ICU ID  :0x12
     881.239 : Rcv ICU DATA:0x00
    1501.250 : Rcv ICU Cmd :COM_INFO
    1501.262 : Rcv ICU ID  :0x04
    1501.270 : Rcv ICU DATA:0x1F


Not all messages are forwarded to UART, like on usual ICU DebugMgr.


Hardware

It is still the same Toshiba chip. It is a custom part made for Canon, based on TMPM440F10XBG.

The "official" chip has only Japanese datasheet, I asked Toshiba for English one and got a reply that there's no EN datasheet as chip is just for Japan market.
With some translator magic it is possible to get a pretty good translation of that datasheet.

Some important details:
Internal flash is at 0x0. Size 0x100000. A lot of it is unused.
RAM at 0x20000000, size probably 0xE000 - this seems to match the datasheet.
Extra RAM (!) at 0x22000000, size 0x200000 - this is Canon specific.

Devices sit at 0x40000000. Addresses so far doesn't match those in datasheet.
The ones found so far are in "hard fault" regions from datasheet. For ROM to boot into DryOS I had to map 0x4009xxxx, 0x400Bxxxx, 0x400Fxxxx.
0x400Bxxxx contains I2C bus(es?). On R5 one is used to talk to a charger - ISL9241.


0x400bxxxx read: a4dc(4) == 0
0x400bxxxx read: a4dc(4) == 0
0x4009xxxx read: a200 4
0x4009xxxx read: a100 4
0x4009xxxx write: a200 4 60
(9030000:03)  <--enq cmd.dev=3,
(9030002:03) func=0,
(9030002:03) sync=1

(9030000:03)  -->deq cmd.dev=3,
(9030002:03) func=0,
(9030002:03) sync=1

(1010000:01) drv_i2ccomm.c:496 eventWait Error ch =0

(1010000:01) drv_i2ccomm.c:497 eventWait Error ret=-2

0x400bxxxx read: a4dc(4) == 0
0x400bxxxx read: a4dc(4) == 0
0x400bxxxx read: a4dc(4) == 0
0x400bxxxx read: a4dc(4) == 0


QEMU  :D

In QEMU for ICU emulation we just replay MPU messages from a list. For some time now I wanted to try emulating MPU ROM in QEMU - if possible it should be easy to spawn two instances (one for MPU and one for ICU) and... let them just talk.
It took just two evenings to see some results.

https://github.com/kitor/qemu-eos/tree/eosmpu/hw/arm/eosmpu.c

This code (with a little help of gdb to skip ISL9241 i2c init) is able to boot firmware into DryOS and MainTask. It then stays waiting for other tasks to spawn, but since timers and interrupts are not yet implemented (as well as UART), it just waits forever.

In the log above prints with data in brackets are taken using GDB from DryosDebugMsg() calls.


(5030000:03) wakeup[0] 00000000
(5030000:03) wakeup[1] 00000000
(5030000:03) wakeup[2] 00000000
(5030000:03) wakeup[3] 00000000
(5030000:03) wakeup[4] 00000000
(5030000:03) wakeup[5] 00000000
(3030000:03) lens VBAT2 VDD2 Keep (0)
(30000:03) INITIAL
(20000:02) Grip exist judge OK
(9030000:03)  <--enq cmd.dev=2,
(9030002:03) func=0,
(9030002:03) sync=1
(9030000:03)  -->deq cmd.dev=2,
(9030002:03) func=0,
(9030002:03) sync=1
(9030000:03)  <--enq cmd.dev=3,
(9030002:03) func=0,
(9030002:03) sync=1
(9030000:03)  -->deq cmd.dev=3,
(9030002:03) func=0,
(9030002:03) sync=1

Too many Canon cameras.
If you have a dead R, RP, 250D mainboard (e.g. after camera repair) and want to donate for experiments, I'll cover shipping costs.

kitor

More on UART:

looks that R5 firmware can use SIO in UART mode or PL011-compatible UART. First one is used, which is a bummer as PL011 driver exists in QEMU.

From the code:
SIO sits at 0x400bb000 +0x100, +0x200, +0x300
PL011 at 0x44000000, maybe + 0x1000 too.
Too many Canon cameras.
If you have a dead R, RP, 250D mainboard (e.g. after camera repair) and want to donate for experiments, I'll cover shipping costs.