Nice find - who expected this to be called SROM?

Just like with the boot flag routine, we need to skip the interactive part (since we don't have access to the serial console on a real camera -
or maybe we do? hint for @space928 - "some electronics" sounds useful) and call the read routine directly. This appears to do all the interesting stuff, but has an unusual syntax: 0x40104DA8 sf_read_sio. Fortunately, it's called from many other places, so we can look at those to understand how to call it.
First argument is a pointer to a data structure. It's not obvious to me what that structure should contain (I'm not that skilled in reading ARM disassembly), so I'm going to trace the calls in the emulator. Notice how it's used in the routine: in the loop at 40104DE4 it reads each int32 until encountering -1, so it's probably a variable-sized list.
Second argument looks like an output buffer (written at 40104F0C), and third argument looks like its size.
Fourth argument looks like some boolean flag.
With this initial info, we can write the following GDB script for tracing the calls to this function (I usually place these in debugmsg.gdb):
b *0x40104DA8
command
silent
print_current_location
printf "sf_read_sio(%x { ", $r0
set $addr = $r0
while *(int*)$addr != -1
printf "%x ", *(int*)$addr
set $addr = $addr + 4
end
printf "-1 }, %x, %x, %x)\n", $r1, $r2, $r3
c
end
Running on t3r4n's example (type 1234 at the address prompt):
make -C ../magic-lantern/platform/portable.000/ install_qemu ML_MODULES_DYNAMIC= CONFIG_BOOT_DUMPER=y
./run_canon_fw.sh 750D,firmware="boot=1" -d io,sflash -s -S & arm-none-eabi-gdb -x 750D/debugmsg.gdb
Read Address[0x000000-0x7FFF00]:0x1234
[ :401057dc ] sf_read_sio(80000f00 { 3 0 12 34 -1 }, 80000b00, 100, 1)
[DIGIC6] at 0x40104DC0:401057E0 [0xD20B0D8C] <- 0xC0003 : SPI
(some activity on SIO2)
[DIGIC6] at 0x40104F24:401057E0 [0xD20B0D8C] <- 0xD0002 : SPI
4 5 6 7 8 9 A B C D E F 0 1 2 3
00001234 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
What does that mean?
- it seems to work
- print_current_location only prints the call address, but no task info (we are in bootloader, no tasks were started, so it's OK)
- that data structure appears to encode the serial flash address (still unsure what's up with that 3)
- [0xD20B0D8C] is the
chip select GPIO for our serial flash (same as 80D, nothing much to do - maybe some refactoring)
- SIO channel is 2 (serial_flash_sio_ch in model_list.c is declared correctly)
- however, this SIO activity is not forwarded to serial_flash.c, because serial flash is not enabled on 750D in QEMU (to do so, copy the serial_flash_size line from 80D in model_list.c)
This changes the output to:
Read Address[0x000000-0x7FFF00]:0x1234
[ :401057dc ] sf_read_sio(80000f00 { 3 0 12 34 -1 }, 80000b00, 100, 1)
[EEPROM] CS = 0
[DIGIC6] at 0x40104DC0:401057E0 [0xD20B0D8C] <- 0xC0003 : Serial flash CS
[EEPROM] Verbose: Got READ (03h)
[EEPROM] Verbose: address is now: 0x001234
[EEPROM] Verbose: Sent 256 bytes
[EEPROM] CS = 1
[DIGIC6] at 0x40104F24:401057E0 [0xD20B0D8C] <- 0xD0002 : Serial flash CS
4 5 6 7 8 9 A B C D E F 0 1 2 3
00001234 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
...
It worked!
Still, let's not forget our initial goal - we need to figure out how to call sf_read_sio. Let's trace other calls - to get the FROMUTILITY menu, we can simply delete AUTOEXEC.BIN from the card image, but leave it bootable (yes, that happens when your camera locks up):
. ./mtools_setup.sh
mdel -i $MSD ::/AUTOEXEC.BIN
./run_canon_fw.sh 750D,firmware="boot=1" -d io,sflash -s -S & arm-none-eabi-gdb -x 750D/debugmsg.gdb
...
**** SROM(SIO2) Menu ****
0.Exit from SROM Menu
1.Erase Chip 0x00800000
2.Erase Block 0x00010000
3.Erase Sector 0x00001000
4.Write Data
5.Write from Card
6.SROM Dump(SIO Read)
7.SROM Dump(QUAD Read)
8.Get Info
>>6
Read Address[0x000000-0x7FFF00]:0x10000
[EEPROM] CS = 0
[DIGIC6] at 0x00104DA8:001057E0 [0xD20B0D8C] <- 0xC0003 : Serial flash CS
[EEPROM] Verbose: Got READ (03h)
[EEPROM] Verbose: address is now: 0x010000
[EEPROM] Verbose: Sent 256 bytes
[EEPROM] CS = 1
[DIGIC6] at 0x00104EC8:001057E0 [0xD20B0D8C] <- 0xD0002 : Serial flash CS
0 1 2 3 4 5 6 7 8 9 A B C D E F
00010000 0F FF F0 00 00 00 01 20 00 00 00 00 10 01 41 90
...
We've got valid data!
However, our logging hook is no longer called. Why? Notice Canon code calls this routine from 0x0010smth, rather than 0x4010smth (0x40000000 is the uncacheable flag). However, it's their code that copied the bootloader routines at 0x40100000 (they copy to uncacheable memory, but execute from a cacheable address):
./run_canon_fw.sh 750D,firmware=boot=1 -d romcpy
B[ROMCPY] 0xFC020000 -> 0x0 size 0x40 at 0xFE0200C8
ootL[ROMCPY] 0xFE026450 -> 0x40100000 size 0xE500 at 0xFE0218EC
oadSLOT_A LOAD OK.
...
Anyway, let's adjust the address in the GDB script (b *0x104DA8) and run again.
>>6
Read Address[0x000000-0x7FFF00]:0x10000
[ :001057dc ] sf_read_sio(80000f20 { 3 1 0 0 -1 }, 80000b20, 100, 1)
[EEPROM] CS = 0
[DIGIC6] at 0x00104DC0:001057E0 [0xD20B0D8C] <- 0xC0003 : Serial flash CS
[EEPROM] Verbose: Got READ (03h)
[EEPROM] Verbose: address is now: 0x010000
[EEPROM] Verbose: Sent 256 bytes
[EEPROM] CS = 1
[DIGIC6] at 0x00104F24:001057E0 [0xD20B0D8C] <- 0xD0002 : Serial flash CS
0 1 2 3 4 5 6 7 8 9 A B C D E F
00010000 0F FF F0 00 00 00 01 20 00 00 00 00 10 01 41 90
...
The logging hook is alive!
Another try:
8.Get Info
>>8
[ :00105ef8 ] sf_read_sio(80000f4c { 3 0 0 0 -1 }, 80000f1c, c, 1)
[EEPROM] CS = 0
[DIGIC6] at 0x00104DC0:00105EFC [0xD20B0D8C] <- 0xC0003 : Serial flash CS
[EEPROM] Verbose: Got READ (03h)
[EEPROM] Verbose: address is now: 0x000000
[EEPROM] Verbose: Sent 12 bytes
[EEPROM] CS = 1
[DIGIC6] at 0x00104F24:00105EFC [0xD20B0D8C] <- 0xD0002 : Serial flash CS
0x80000331
In this case, it reads 12 bytes from address 0. You may look up 0x80000331
here.
Some more calls:
Read Address[0x000000-0x7FFF00]:0x123456
[ :001057dc ] sf_read_sio(80000f20 { 3 12 34 56 -1 }, 80000b20, 100, 1)
7.SROM Dump(QUAD Read)
>>7
Read Addr[0x000000-0x7FFF00]:0x1234
Read Size[0x4-0x800000]:0x100
[ :001059d0 ] sf_read_sio(80000ef8 { 9f -1 }, 80000eec, 3, 1)
[EEPROM] Verbose: Got RDID
[ :00104f78 ] sf_read_sio(80000ecc { 6 -1 }, 0, 0, 1)
[EEPROM] Verbose: Set Write Enable Latch
[ :00104fa4 ] sf_read_sio(80000ecc { 5 -1 }, 80000ec4, 1, 1)
[EEPROM] Verbose: [SR] >> 0x2
[ :00105b68 ] sf_read_sio(80000f14 { 6b 0 12 34 -1 }, 0, 0, 0)
[EEPROM] Verbose: Got QOFR (6Bh)
[EEPROM] Verbose: address is now: 0x001234
A-ha! The first parameter in arg0 is the raw serial flash command (see serial_flash_spi_write) and the remaining ones are its arguments (if any are required). The parameter we are interested in is 3 = READ, and its arguments are 3 bytes representing the read address. Our routine accepts an array of uint32_t's though.
The last parameter (R3) is used to enable the CS signal (now that we know the register, it's obvious what it does):
40104DB4 LDR R9, =0xD20B0000
40104DB8 CMP R3, #0
40104DBC BEQ loc_40104DC8
40104DC0 LDR R12, =0xC0003
40104DC4 STR R12, [R9,#0xD8C]
Now we can write the function declaration (and maybe rename it to sf_command_sio, as it doesn't do just reads)
void sf_command_sio(uint32_t command[], uint32_t * out_buffer, int out_buffer_size, int toggle_cs);
Sample call (edit: output buffer is an array of uint32_t, not char):
uint32_t buffer[0x100];
int addr = 0x1234;
sf_command_sio((uint32_t[]) {3, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, -1}, buffer, COUNT(buffer), 1);
"Beware of bugs in the above code; I have only proved it correct, not tried it." (
source)