The nice part is that all other models can follow (more or less) the same procedure. Credits go to dfort
for getting the tutorials ball rolling - that's the reason I've picked this model for a walkthrough.
In other words, owners of other models will no longer have excuses for not knowing how to port ML to their camera

Anyway, let's continue figuring out the emulation.
.serial_flash_size = 0x1000000,
Unfortunately, this step doesn't change anything in the emulation.
Oops, I was wrong here. To quote Ange Albertini -
https://twitter.com/angealbertini/status/773650987839926272Reverse engineering tip: it's perfectly fine to
- have no idea what to do next
- have made wrong assumptions
- take 'too long'
Here's the detail I've missed the first time:
SerialFlash Initialize
[EEPROM-DMA]! [0x2D0000] -> [0x416D5B00] (0x1DC400 bytes)
Also, error messages like this will disappear after declaring .serial_flash_size:
6: 16.640 [PROPAD] ERROR Not Exist Valid ComboPackages!! 0x2D0000
That's good - it probably means we have nothing else to fix regarding serial flash. Running with -d sflash shows plenty of serial flash activity (but I swear I did ran this command back then and noticed none of it...)
Let's move on to the next item - MPU messages. You can find the registers used for these in InitializeIntercom (surrounded in the disassembly by "InitializeIntercom" ... "InitializeIntercom End(%#x)"). The function call between these two strings is:
ROM:FF0C3A9C LDR R2, =0xC020302C
ROM:FF0C3AA0 LDR R0, =0xC022006C
ROM:FF0C3AA4 MOV R1, #0x50 ; 'P'
ROM:FF0C3AA8 BL sub_3AD0
Looking up these registers, you'll find the former on the section with DIGIC 5 defaults (so nothing to change about it), and the latter on the EOSM, 100D and some other models. Let's copy it:
.mpu_request_register = 0xC022006C,
.mpu_status_register = 0xC022006C,
Side note: we were very lucky, as EOS M2 is very similar to 100D and other models from the same generation. 1300D was a lot more different (used registers different from all other models, different registers for request and status - unlike all other models - and also different values for driving these GPIOs). Refer to
this commit for the gory details - generally you'll find this kind of changes with cameras from different generations. I expect this kind of changes on DIGIC 6 models - didn't look into this part yet because 1) mixed ARM/Thumb code is a lot harder to reverse engineer (at least with the tools I know) and 2) I don't have any MPU communication logs from a DIGIC 6 models (it might work with replaying one from a recent DIGIC 5, no idea).
Still, after enabling the MPU registers, there's very little MPU activity:
[MPU] Received: 06 04 02 00 00 00 (unknown spell)
[MPU] Received: 0a 08 03 57 10 2f 00 01 00 00 (unknown spell)
[MPU] Received: 08 07 03 6a 01 08 00 00 (unknown spell)
And these warnings:
[MPU] FIXME: no MPU spells for EOSM2.
[MPU] FIXME: no MPU button codes for EOSM2.
Let's try our luck by assuming the MPU communication is similar to 100D. That model already boots Canon GUI, so it looks like a perfect match. Lookup this message in the source code to see what file you should edit next:
grep -nr "no MPU spells" qemu-2.5.0/
qemu-2.5.0/hw/eos/mpu.c:742: MPU_EPRINTF("FIXME: no MPU spells for %s.\n", s->model->name);
So we have to edit mpu.c (near line 742). Open it and notice this similarity trick worked on a few other models (such as 1200D or 1100D). Add an entry for EOS M2, using the 100D as model (look for MPU_SPELL_SET_OTHER_CAM).
Looks like it's working! There's a lot of MPU activity now.
Still, the screen is filled with DL messages. Let's look it up in other models - it's already patched on EOS M:
EOSM/debugmsg.gdb:17:# patch DL to avoid DL ERROR messages
EOSM/debugmsg.gdb-18-set *(int*)0xFF1BE4AC = 0xe3a00015
Looks like it might be exactly what we need.
Wait a minute - what's up with these black magic values? The first one is a ROM address (obvious if you managed to follow the walkthrough until here), but what about the second one?
The code near that address, on EOS M, looks like this:
ROM:FF1BE4AC BL sub_FF1BDFD4
ROM:FF1BE4B0 CMP R0, #0x15
In other words, it calls a function and checks whether it returns 0x15. Therefore, 0xe3a00015 must be some ARM instruction. You could throw it at a disassembler (tip: there's even
an online disassembler on Twitter 
) or you could find a similar pattern in arm-mcr.h. Whatever method you choose, you'll find out it's MOV R0, #0x15.
Use your pattern matching skills to find the same piece of code on EOS M2 (nearby string: "IsPossibleActiveSweep OVERRUN") and add the patch to EOSM2/debugmsg.gdb.
Run the EOSM2 firmware under GDB and notice it now gets stuck at localI2C_Write. Look it up in the GDB scripts and notice the same thing was (again) patched on EOSM.
EOSM/debugmsg.gdb:20:# patch localI2C_Write to always return 1 (success)
EOSM/debugmsg.gdb-21-set *(int*)0xFF3460C4 = 0xe3a00001
EOSM/debugmsg.gdb-22-set *(int*)0xFF3460C8 = 0xe12fff1e
You may ask: why there are no comments for these black magic values?
1) the ROM addresses have a comment (the name of the function they are referring to).
2) these ARM instructions are obvious to me (how else you could write "return 1" in ARM assembler?)
3) the comment does describe what the patch is doing, what function is patched, what's the meaning of the returned value... what else should I include?
OK, find this one for EOSM2 (easy) and run it again under gdb.
Emulation goes a bit further, and you can spot this message on the last few lines:
61: 203.008 [STARTUP] ERROR SerialFlash Version!! Firm : 6.0.3 SF : 4.2.1
Look up the string in the disassembly, and also the code that references it:
ROM:FF0C4270 MOV R2, #5
ROM:FF0C4274 ADD R1, SP, #0x30
ROM:FF0C4278 ADR R0, a6_0_3 ; "6.0.3"
ROM:FF0C427C BL sub_FF0C8F40
ROM:FF0C4280 CMP R0, #0
ROM:FF0C4284 BEQ loc_FF0C42A4
ROM:FF0C4290 ADR R3, a6_0_3 ; "6.0.3"
ROM:FF0C4294 ADR R2, aErrorSerialfla ; "ERROR SerialFlash Version!! Firm : %s S"...
ROM:FF0C42A0 BL DebugMsg
ROM:FF0C42A4
ROM:FF0C42A4 loc_FF0C42A4
So, to avoid this message, we need sub_FF0C8F40 to return 0. Looking at its arguments, it compares "6.0.3" to something else (something from the stack, likely a local variable), and there's a third argument set to 5. Looking at its code, it appears to do something similar to strncpy. Let's try to bypass this function call and let the caller code behave as if sub_FF0C8F40 would return 0:
# skip SerialFlash version check
set *(int*)0xFF0C427C = 0xe3a00000
We have just replaced the BL sub_FF0C8F40 call with MOV R0, #0.
The emulation goes a lot further now, it initializes RscMgr, FileMgr, PropMgr, starts a bunch of tasks and... gets stuck in an infinite loop at:
[ Startup:ff0c5138 ] (8b:03) Wait LeoLens Complete
Look up the string in the disassembly, and notice the decision for exiting this loop is made here:
ROM:FF0C512C loc_FF0C512C ; CODE XREF: sub_FF0C4E80+2CCj
ROM:FF0C512C ADR R2, aWaitLeolensCom ; "Wait LeoLens Complete"
...
ROM:FF0C5144 LDR R0, [R4,#0x28]
ROM:FF0C5148 CMP R0, #0
ROM:FF0C514C BEQ loc_FF0C512C
...
So, we need R0 to be nonzero in order to avoid the branch that prints "Wait LeoLens Complete". The memory address where R0 is loaded from is R4 + 0x28. What the contents of R4 is supposed to be, is not clear from the disassembly. Hit CTRL-C in gdb and set a breakpoint at FF0C5148 to find out:
(gdb) b *0xFF0C5148
Breakpoint 3 at 0xff0c5148
(gdb) c
Continuing.
Shortly, gdb prompts us again, this time with the program stopped exactly where the loop condition is checked. Examine the registers:
Breakpoint 3, 0xff0c5148 in ?? ()
(gdb) info registers
r0 0x0 0x0
r4 0x8fad4 0x8fad4
So, the memory address the program expects to become nonzero is 0x8fad4+0x28 = 0x8fafc. Look up what other code uses this address (references to either 0x8fad4 - the main data structure - or 0x8fafc - the address of the structure field expected to be updated) and you'll find out this tiny function:
ROM:FF0C35F4 LDR R1, =dword_8FAD4
ROM:FF0C35F8 MOV R0, #1
ROM:FF0C35FC STR R0, [R1,#(dword_8FAFC - 0x8FAD4)]
ROM:FF0C3600 BX LR
OK, so the value at this memory address is expected to become 1 at some point.
Who calls this function? Look it up (references to FF0C35F4) and you'll find this snippet:
ROM:FF0C3B30 LDR R0, =loc_FF0C35F4
ROM:FF0C3B34 MOV R1, #0
ROM:FF0C3B38 BL sub_FF0F7B18
...
ROM:FF0C3B44 ADRNE R2, aInitializeprop ; "InitializePropertySatellite (%#x)"
It must be a tiny function passed as pointer to another function (which is why it wasn't recognized as function by IDA - it's not called directly). When it's supposed to be called? No idea, probably from a missing property that's not present in the serial flash dump we took from 100D. Just a guess.
The property code is usually quite complex - in this case it's a lot easier to just patch the affected loop and hope it will work. If the value would have been clearly retrieved from some MMIO register, or set by some interrupt handler, it would probably have been better to emulate that register or that interrupt (because, on the way to that function expected to be called, the code may do a bunch of other initializations, side effects and whatnot).
In this case, let's just patch the value in gdb and see how it goes:
(gdb) set *(int*)($r4 + 0x28) = 1
(gdb) c
Continuing.
[ Startup:ff0c5138 ] (8b:03) Wait LeoLens Complete
Breakpoint 3, 0xff0c5148 in ?? ()
(gdb) c
Continuing.
[ Startup:ff0e29a8 ] (30:03) MOVW_Initialize
[ Startup:0003671c ] task_create(MovWriter, prio=15, stack=2000, entry=36628, arg=67262c)
[ Startup:ff0e6f34 ] (2f:03) MVR_Initialize
[ Startup:0003671c ] task_create(MovieRecorder, prio=11, stack=2000, entry=36628, arg=672d4c)
Looks like the emulation went past that point. Let's add our trick to the gdb script:
# break infinite loop at Wait LeoLens Complete
b *0xFF0C5148
commands
printf "Patching LeoLens (infinite loop)\n"
set *(int*)($r4 + 0x28) = 1
c
end
The emulation goes further, mounts the SD card (CSMgrTask), starts even more tasks, and appears to be stuck at:
167: 851.456 [TCH]Touch IC Ver : 0x0000
At this point, seeing there's no progress after 10 seconds or so, you'll be tempted to hit CTRL-C. Or you can forget the emulation window open (e.g. for posting gibberish like this on the forum), and when you hit ALT+TAB you notice this:
1383: 57907.968 WARN [I2C] localI2C_Read : 378 (Task : CEC)
1384: 57927.680 WARN [I2C] localI2C_Read : 378 (Task : CEC)
1385: 57947.392 WARN [I2C] localI2C_Read : 378 (Task : CEC)
1386: 57966.592 WARN [I2C] localI2C_Read : 378 (Task : CEC)

Wait, what?
Trying to navigate this menu gives no reaction. We forgot to address this warning (at the beginning of the emulation log):
[MPU] FIXME: no MPU button codes for EOSM2.
Use the button codes from 100D and - to quote kichetof - take a beer and enjoy it!

Tip: comment out DebugMsg calls from the GDB script for a much faster boot.
Exercises:
- (easy) patch the loop that times out (probably when initializing the touch IC) and the localI2C_Read loop;
- (easy) print Hello World with the minimal ML target;
- (moderate) print Hello World with the regular ML source code;
- (moderate) implement touch screen emulation;
- (moderate) bring ML menu in QEMU;
- (harder) full ML port, with most features working;
- (extreme) LiveView emulation.