How to run Magic Lantern into QEMU?!...

Started by jplxpto, September 23, 2012, 08:29:02 PM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

dfort

I see, so we should check if /Volumes/EOS_DIGITAL* exists on OS X.

a1ex

More updates:

* Monitor console available by default as a UNIX socket; that means, during emulation you can interact with it with netcat (for quick commands or from a script), or with socat (for interactive console):

echo "log io" | nc -U qemu.monitor
socat - UNIX-CONNECT:qemu.monitor


* Log DebugMsg calls without GDB (very fast; credits go to @nkls - I've used a modified version of his initial DebugMsg hook).

./run_canon_fw.sh 5D3,firmware="boot=0" -d debugmsg


To use it on plain Canon firmware (any shell):
env QEMU_EOS_DEBUGMSG=0x5b90 ./run_canon_fw.sh 5D3,firmware="boot=0" -d debugmsg
or, with ML loaded (requires bash):
. ./export_ml_syms.sh 5D3.113
./run_canon_fw.sh 5D3,firmware="boot=1" -d debugmsg


* Verbose stack trace (to see where each message is coming from), for both -d debugmsg and GDB scripts (DIGIC 4-6). Example for the former:

./run_canon_fw.sh 5D3,firmware="boot=0" -d debugmsg,callstack,v

Current stack: [14ff80-14ef80] sp=14fed8                                         at [FileMgr:5b90:ff0f9684]
0x17B60(51ec48 &"TaskClass", 17b60, 19980218, 19980218)                          at [FileMgr:de48:14ff78] (pc:sp)
0xFF11B818(51ea28 &"FileMgr", 6, 0, 2)                                          at [FileMgr:17bbc:14ff50] (pc:sp)
  0x178B4(51ec1c &"StateObject", 51ea28 &"FileMgr", 6, 0)                        at [FileMgr:ff11b844:14ff38] (pc:sp)
   0x178EC(51ec1c &"StateObject", 51ea28 &"FileMgr", 6, 0)                       at [FileMgr:178e4:14ff28] (pc:sp)
    0xFF2C8F5C(51ea28 &"FileMgr", 0, 2, ff2c8f5c)                                at [FileMgr:1796c:14ff08] (pc:sp)
     0xFF0C5194(10, 0, 24, ff0c5194)                                             at [FileMgr:ff2c9050:14fef0] (pc:sp)
      0x5B90(0, 3, ff0f9784 "[SEQ] NotifyComplete (Cur = %d, %#x, Flag = %#x)", 4)
                                                                                 at [FileMgr:ff0f9680:14fed8] (pc:sp)
[     FileMgr:ff0f9680 ] (00:03) [SEQ] NotifyComplete (Cur = 4, 0x10, Flag = 0x10)


This tool is very powerful - rather than hunting for several minutes/hours to see where some error message might be coming from, you now get the answer in seconds (example).

* Thorough consistency check to make sure the stack trace gives the same information as if you would follow the call/return trace manually.

More to come (regarding 1300D, digic 6, memory checking, automatic testing of ML builds). Most of these were written some time ago, but it takes a while to integrate everything and make sure they pass the test suite. Though slow, this approach does catch a lot of bugs very early, and I hope to have soon the tools to use a similar development approach for the main ML codebase.

a1ex

Some more:

- 650D GUI (come on guys, it was as simple as copying some 700D definitions and trying it...)
- EOSM2 GUI (see this walkthrough, thanks dfort for following it along)
- 1300D: minor updates
- 70D menu tests (they don't work all the time, figure out why)
- 5D4 emulation updated for latest firmware

- splitgdb.sh updated to use cgdb (installing it from source is recommended)

- run_ml_all_cams.sh can now be used to compile and run ML in QEMU with various options, very customizable

To get started: this compiles ML for 500D and 60D, copies each build to the virtual SD image, runs it for 10 seconds and takes a screenshot.

env ML_PLATFORMS="500D.111/ 60D.111/" TIMEOUT=10 SCREENSHOT=1 ./run_ml_all_cams.sh


Internally, this is how the emulator is invoked:

(
  sleep 10
  echo screendump 60D.111.ppm
  echo quit
) | (
  arm-none-eabi-gdb -x 60D/patches.gdb &
  ./run_canon_fw.sh 60D,firmware='boot=1' \
      -display none -monitor stdio  -s -S
) &> 60D.111.log


More examples: EOSM2 hello world, or running ML from the dm-spy-experiments branch in the emulator (QEMU-dm-spy).




- track direct jumps in call stacks (widely used on DIGIC 6)

Example for 80D:

# in 80D/debugmsg.gdb
macro define PRINT_CALLSTACK 1

./run_canon_fw.sh 80D,firmware="boot=0" -s -S -d callstack & arm-none-eabi-gdb -x 80D/debugmsg.gdb
...
0xFE0D3385(0, fe0d3385, 19980218, 19980218)                                      at [init:8000173d:2e9108] (pc:sp)
0xFE533439(fe0d76f9, 0, fe0d76e5, fe0d76e7)                                     at [init:fe0d407d:2e90f0] (pc:sp)
  0xFE209159(fe0d76f9, 0, fe0d76e5, fe0d76e7)                                    at [init:fe53344f:2e90d8] (pc:sp)
   0xFE3FC0DC -> 0xFF1(fe209254 "PowerMgr", 20, 400, fe2090e1)                   at [init:fe209175:2e90c8] (pc:sp)
[      init:fe209175 ] task_create(PowerMgr, prio=20, stack=400, entry=fe2090e1, arg=0)


On the last line, 0xFE3FC0DC is an ARM wrapper (veneer) for 0xFF1 task_create. Wrappers like this are used in D6 code all over the place. Sometimes there are many different wrappers for the same functions, or even wrappers to wrappers to wrappers - these make the function calls very hard to track down.

Here's an example:

b *0xFE483D42
commands
  silent
  print_current_location_with_callstack
  printf "sei\n"
  c
end



Current stack: [2e9118-2e8118] sp=2e9000                                         at [init:fe483d42:fe483f2d]
0xFE0D3385(0, fe0d3385, 19980218, 19980218)                                      at [init:8000173d:2e9108] (pc:sp)
0xFE3FC204 -> 0x800035E1(8b, 16, fe0d4790 "\n%s ICU Firmware Version %s ( %s )", fe0d39a8)
                                                                                 at [init:fe0d43e9:2e90f0] (pc:sp)
  0x8000579B(3cc000, 0, 2e9044, 2e9048 "[STARTUP] \nK350 ICU Firmware Version 1.0.1 ( 6.2.2 )")
                                                                                 at [init:8000367f:2e9040] (pc:sp)
   0x800061F5(3cc084, 0, ffffffff, 3cc0d4)                                       at [init:8000581b:2e9020] (pc:sp)
    0x800051DC -> 0xFE483F0D(3cc084, 0, ffffffff, 3cc0d4)                        at [init:80006201:2e9010] (pc:sp)
     0xFE3FC00C -> 0xCA9 -> 0x168B -> 0xFE483D43(0, 96, ffffffff, 3cc0d4)        at [init:fe483f29:2e9000] (pc:sp)
[      init:fe483f29 ] sei


Look at those functions from the last line - they do nothing but jumping to the next one:

FE3FC00C 04 F0 1F E5                 LDR             PC, =(sub_CA8+1)

00000CA8 00 F0 EF BC                 B.W             sub_168A

0000168A 43 F6 43 5C+                MOV             R12, #0xFE483D43
00001692 60 47                       BX              R12 ; sub_FE483D42

FE483D42 EF F3 00 81                 MRS.W           R1, CPSR
FE483D46 21 F0 80 01                 BIC.W           R1, R1, #0x80
...



a1ex

More:

- "-d debugmsg" now just works; you no longer need to setup additional stuff, just run something like:


./run_canon_fw.sh 60D,firmware="boot=0" -d debugmsg


- stack trace also available (in a more limited format) without instrumentation; the full stack trace ("-d callstack") requires instrumentation to detect function calls, so it's slower, but also captures function arguments and handles difficult cases better.

To show the stack trace (with any of the two methods):
* it's always enabled for assert in GDB scripts
* "macro define PRINT_CALLSTACK 1" in GDB scripts enables it for all logged functions
* "print_current_location_with_callstack" at GDB prompt
* "-d debugmsg,v" or "-d debugmsg,callstack,v" on the command line (very verbose)
* from custom code, just call eos_callstack_print_verbose

Internally, the two methods were cross-checked to make sure they give the same results or fail gracefully, on every single function call until GUI boot.

The non-instrumented stack trace is also usable in ML, on the camera (e.g. in crash logs).

dfort

Got a really noob QEMU question.

Is it possible to bring up the ML menus using the Trash button? If so, where is the Trash button?

Maybe the Trash button is currently an unknown MPU spell? (If that's the right term.)

I've got the 550D and 1100D working with all sorts of builds including nightlies from the jenkins server but I haven't figured out how to bring up the ML menus.

dmilligan

You probably had trouble finding it b/c you are on a Mac right? Most Mac keyboards lack a dedicated forward delete key. Try: Fn + Delete

dfort

Hi @dmilligan -- Yep, I'm on a Mac. No combination of delete with a modifier key is showing a key event in QEMU. Though hitting random keys brought up this interesting screen:



That's trying to run a full ML on the 1100D and bring up the ML menus. I've been successful running a minimal "Hello World" build but a full ML build doesn't get all the way to the Canon menu. Oh well, Have fun!

a1ex

1100D doesn't have a dedicated "delete" button - it uses Av, which is not emulated in QEMU, and it's not even a regular button - the event it sends is actually a refresh of the info display (Canon calls this OLC). So, we use a very weird heuristic to detect short presses (and I'm not even sure how reliable it works).

PoC: https://builds.magiclantern.fm/jenkins/view/QEMU/job/QEMU-ML-menu/

(still has a few bugs in it)

dfort

That is so cool:

700D in QEMU


So is the next step adapting Canon EF lenses to the computer?

a1ex

Quote from: dfort on July 17, 2017, 06:02:06 PM
So is the next step adapting Canon EF lenses to the computer?

Joking aside, you've probably noticed the Debug -> Lens Info menu is actually usable on some models. This info comes from MPU messages.

That means, you can use the startup-log builds while starting the camera with various lenses, and find out which parts of the log are lens-specific.

If we want to log things such as changing focus distance or focal length in LiveView (where these are reported back to the ARM CPU), we have a small issue: the log buffer fills up really quickly in LiveView. It may make sense to prepare a different set of builds, with reduced verbosity (or maybe skip logging unimportant messages once e.g. half of the buffer is full). Will look into that.

I should also make the mpu_send/recv stubs mandatory, as they are now known to work identically in all models, from digic 2 to digic 6 (not sure about 7 yet). And I'll need such logs from all cameras anyway.

BBA

Sigma firmware updates can be downloaded for their lenses on Canon EF mount.... Don't know which processor they use...What do you think ?

a1ex

Sorry, no experience with Sigma lenses.

a1ex

More stuff:

- found a way to get deterministic execution traces (-icount option in QEMU); a lot of tests were failing because of timing variations and differences in host CPU speed
- a test covering the entire call/return trace, from start to booting the GUI
- option to identify tail function calls ("-d calls,tail" or "-d callstack,tail")
- incomplete 5D3 1.2.3 GUI emulation (boots with black screen, ML loads fully, but no menus)
- option to highlight certain MMIO registers (hardcoded)
- helper to cross-check MMIO register values with the ones from actual hardware (see this commit for usage notes)
- experimental UART emulation in main firmware (Dry-shell, eventproc shell - like this; examples for 5D3, 70D, 500D). See also on CHDK forum.


a1ex

As the current state is pretty much usable and most of the tests are passing, I'm ready to merge it into mainline. Besides the emulation (which is installed out of the ML tree), the "qemu" branch also provides a debugging API, explained below. I've used this API for the new DryOS task hooks (6D, 100D, 70D and EOS M2), so these new ports (all but 6D) depend on "qemu" being merged first.

I just need a second pair of eyes to look over it and make sure:
1) there's nothing broken in the main builds (build system, functionality);
2) the debugging API works as described below.




The main debugging function is qprintf (and its lightweight friends: qprint, qprintn and qdisas). Feel free to use them *anywhere* - they won't get compiled in regular builds (therefore they won't increase the executable size). These functions will print to QEMU console whenever ML (or a subset of it) is compiled with CONFIG_QEMU=y. Example:


cd platform/550D.109
make clean; make                  # regular build
make clean; make CONFIG_QEMU=y    # debug build for QEMU


It works for modules as well:

cd modules/lua
# add some qprintf call in lua_init for testing
make clean; make                  # regular build
make clean; make CONFIG_QEMU=y    # debug build for QEMU


(Side note: as we don't emulate ML shutdown properly yet, you'll have to enable Debug -> Load modules after crash. Solving this is a little above easy coding task level, but doable.)

You can also specify CONFIG_QEMU=y in Makefile.user - but as this is more likely to be used as a temporary option, the command line makes a little more sense to me.

The QEMU debugging API is header-only (qemu-util.h), auto-included by dryos.h. You can use it for either the entire ML, or just for a subset of it - e.g. the source file(s) you are currently editing, or only some modules. The lightweight functions can also be used in very early boot code, where you can't call vsnprintf or you may not even have a stack properly set up.

In a nutshell:

CONFIG_QEMU=n (default):
- regular build
- the executable works in QEMU (within the limitations of the emulation)
- no guest debugging code (no additional debugging facilities)

CONFIG_QEMU=y (optional, on the command line or in Makefile.user):
- debug build for QEMU only
- does not run on the camera (!)
- enables qprintf and friends to print on the QEMU console
- enables unlimited number of ROM patches - useful for dm-spy-experiments (in QEMU you can simply write to ROM as if it were RAM)
- may enable other workarounds for models that are not emulated very well

Additionally, you have better support for debugging ML at source level, in gdb (or any front-end you like). Uncomment the symbol-file line in your GDB script:

symbol-file ../magic-lantern/platform/80D.102/magiclantern

and you can now run ML code step by step in the debugger, or set breakpoints to any ML function:

b my_init_task


For debugging very early boot code (e.g. reboot.c), you'll have to use "autoexec" for symbol-file.

More details on debugging on the EOS M2 thread.

Unfortunately I don't have a good solution for debugging modules in the same way...

Also started a README - proof-reading welcome :)

dfort


kichetof

Hi guys, I'm happy too !

After trying for a long time to get QEMU working on my Mac, it works now!  8)
I finally find how to solve the pixman compilation error.. it was really simple  :o

pixman-mmx.c:100:20: error: constraint 'K' expects an integer constant expression
        : "y" (__A), "K" (__N)

Solved with: brew install pixman

50D 1.0.9






5D3 1.1.3

Unable to play with Canon or ML menus, on startup I've "SD card test (0 --> 100)" and after test

Key has no effect. Try some branches and same bug, black screen (with 2 dots above "was not shut")
Output from terminal (I'll find why grep give an error; line 50 from run_canon_fw.sh; same bug as @dfort found, grep on MacOS)

I've found why, you explain it here, I'll try with debugmsg.gdb




Could you try another keys for keyboards without a numpad ? On my MacBook Pro I don't have one and I can't found keys for Joystick (8 directions & center).

QEMU Readme give a great help to start with emulation! Thanks

Many thanks a1ex to make our DSLR and now our computer to be so cool  8)

a1ex

Very cool, glad to see it's working.

Ideally, those dependencies should be handled in the install script; will look into it.

You can customize the keys in mpu.c. To add alternate keys, see for example Shift, which accepts 2 key codes: left shift and right shift. My keyboard doesn't have a numpad either, but it does have the classic arrow keys - for menu navigation it's working well.

kichetof

Quote from: a1ex on September 16, 2017, 06:42:02 PM
Ideally, those dependencies should be handled in the install script; will look into it.

To fix bug with MacOS, we need to install GNU grep with brew install grep. Personally I don't want to replace MacOS version, so we need to use ggrep instead of grep when -P argument is required.



What do you think about specific cards by model? (to avoid some bugs with wrong build)

I customized run_canon_fw.sh like that:


SD="sd.img"
CF="cf.img"

if [ "$CAM" ] && [ -f sd-$CAM.img ]; then
    SD="sd-$CAM.img"
fi

if [ "$CAM" ] && [ -f cf-$CAM.img ]; then
    CF="cf-$CAM.img"
fi

# run the emulation
env QEMU_EOS_DEBUGMSG="$QEMU_EOS_DEBUGMSG" \
  $QEMU_PATH/arm-softmmu/qemu-system-arm \
    -drive if=sd,format=raw,file=$SD \
    -drive if=ide,format=raw,file=$CF \
    -chardev socket,server,nowait,path=qemu.monitor,id=monsock \
    -mon chardev=monsock,mode=readline \
    -M $*




Some custom on mpu.c (QWERTZ keyboard, simulate numpad with TZU/GHJ/VBN)


    { 0x0014,   BGMT_PRESS_UP_LEFT,     "T",            "Joystick Up Left",             },
    { 0x0094,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x002C,   BGMT_PRESS_UP,          "Z",            "Joystick Up",                  },
    { 0x00AC,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0016,   BGMT_PRESS_UP_RIGHT,    "U" ,           "Joystick Up Right",            },
    { 0x0096,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0022,   BGMT_PRESS_LEFT,        "G",            "Joystick Left",                },
    { 0x00A2,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0023,   BGMT_JOY_CENTER,        "H",            "Joystick center",              },
    { 0x00A3,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0024,   BGMT_PRESS_RIGHT,       "J",            "Joystick Right",               },
    { 0x00A4,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x002F,   BGMT_PRESS_DOWN_LEFT,   "V",            "Joystick Down Left",           },
    { 0x00AF,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0030,   BGMT_PRESS_DOWN,        "B",            "Joystick Down",                },
    { 0x00B0,   BGMT_UNPRESS_UDLR,                                                      },
    { 0x0031,   BGMT_PRESS_DOWN_RIGHT,  "N",            "Joystick Down Right",          },
    { 0x00B1,   BGMT_UNPRESS_UDLR,                                                      },


Nothing happen (50D) when I press Joystick center (I try to play with settings (aperture, speed, ISO,..), for testing :))
Key event: 23 -> 0b01
[MPU] Sending : 06 05 06 0b 01 00
[MPU] Received: 06 05 04 00 09 00  (NotifyGUIEvent - spell #44)
[MPU] Sending : 06 05 04 00 09 01
[MPU] Received: 08 06 00 00 04 00 00 00  (unknown spell)
  1212:  2740.224 [MC] PROP_GUI_STATE 9
  1231:  2740.224 [MC] cam event guimode comp. 9
  1278:  2745.600 [DISP] TurnOnDisplay (PUB) Type=0 fDisplayTurnOn=1
[MPU] Received: 06 05 03 19 00 00  (spell #37)
Key event: a3 -> 0b00
[MPU] Sending : 06 05 06 0b 00 00

a1ex

Quote from: kichetof on September 16, 2017, 11:48:49 PM
What do you think about specific cards by model?

If you have enough free space on the disk, it's a good idea (so it's best to keep it optional). I prefer storing all model-specific files under the $CAM/ directory (where the ROMs are), but otherwise, your change looks fine. Maybe even enabling only one card in the emulation.

Quote
Nothing happen (50D) when I press Joystick center (I try to play with settings (aperture, speed, ISO,..), for testing :))

I don't expect this to work, as it requires MPU communication. If it's a simple protocol, such as sending something about ISO and replying back the same code, it can be solved with custom MPU spells; if it requires some state, it's more difficult, as the current mpu.c is suitable mostly for replaying known messages.

The first step would be to log Canon messages during these actions (using the startup-log build or dm-spy-experiments branch) and understand what messages are for ISO, shutter and aperture, and how these should look like when changing them. Note the change may be initiated from the MPU (when pressing the buttons) or from the main CPU (when changing these parameters from ML menu).

These messages can be cross-checked with Leegong's notes.

kichetof

Quote from: a1ex on September 17, 2017, 07:12:34 AM
I prefer storing all model-specific files under the $CAM/ directory (where the ROMs are), but otherwise, your change looks fine. Maybe even enabling only one card in the emulation.

It will be more beautiful to store under $CAM directory and name it cf.img and sd.img. I'll adapt my script to check in $CAM dir.
To use only one card, we need to know which cam use only SD, SD+CF and only CF to send the right card. Or maybe we can simulate one or the other.

Quote from: a1ex on September 17, 2017, 07:12:34 AM
I don't expect this to work, as it requires MPU communication. If it's a simple protocol, such as sending something about ISO and replying back the same code, it can be solved with custom MPU spells; if it requires some state, it's more difficult, as the current mpu.c is suitable mostly for replaying known messages.

The first step would be to log Canon messages during these actions (using the startup-log build or dm-spy-experiments branch) and understand what messages are for ISO, shutter and aperture, and how these should look like when changing them. Note the change may be initiated from the MPU (when pressing the buttons) or from the main CPU (when changing these parameters from ML menu).

These messages can be cross-checked with Leegong's notes.

Thanks for all these informations! I'll learn how to get and interpret these messages. Lot of stuff to read and learn  ;D

a1ex

Updates:

- emulation is now used to run some automated tests on ML nightly builds (just scratching the surface, but already found a couple of bugs in ML)
- clean shutdown on most models (menu: Machine -> Power Down); 70D is the black sheep here (not sure what the issue is)
- 450D and 1000D GUIs (based on logs from Ant123). For other VxWorks models, you'll have to customize this and get a startup log with mpu_send/recv calls (can be debugged in QEMU).
- 400D GUI starts without any MPU emulation (!), but it's stuck (does not react to any key presses)



Still looking for some help with proof-reading the README, to merge it into mainline (EOSM2, 100D and 70D are waiting for it).

a1ex

Currently experimenting with an updated toolchain, in the qemu branch. I'm following this guide (actually I'm testing it on a fresh Ubuntu VM):


sudo apt install mercurial
hg clone https://bitbucket.org/hudson/magic-lantern
cd magic-lantern
hg update qemu -C
cd contrib/qemu
./install.sh


This asked me for the sudo password to install the dependencies.



After installing some 800MB worth of packages, I've copy/pasted the QEMU compilation commands printed by install.sh (they will be different on your system):

cd /home/alex/qemu/qemu-2.5.0
../configure_eos.sh
make -j1




Copied the ROM files for 5D3 1.1.3, and ran:

./run_canon_fw.sh 5D3




For Canon GUI, we need to run under GDB (patches.gdb):

./run_canon_fw.sh 5D3,firmware="boot=0" -s -S & arm-none-eabi-gdb -x 5D3/patches.gdb





Then compiled ML and ran it in QEMU:

make -C ../magic-lantern/platform/5D3.113 install_qemu
./run_canon_fw.sh 5D3,firmware="boot=1" -s -S & arm-none-eabi-gdb -x 5D3/patches.gdb




Enabled the Lua module, restarted the virtual camera cleanly (Machine -> Power Down) ...


... and ran the Hello World and Sokoban scripts:


Yes, it was that simple 8)

Animation (3MB)

Scripts used (should you want to re-create the above scenario, maybe on another OS):
qemu-demo-xenial.sh and anim.py

Licaon_Kter

Two ideas:

1. Maybe download GCC from the new site: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
wget -c https://developer.arm.com/-/media/Files/downloads/gnu-rm/5_4-2016q3/gcc-arm-none-eabi-5_4-2016q3-20160926-$OS.tar.bz2 && \

2. Why GCC 5.4.1 and not the latest (available there) GCC 6.3.1 ? I build with it and have not encountered any issues, but then again I only build for EOS M :)

a1ex

Noticed the new site after committing :D

GDB from the GCC 6.x package (only available as 64-bit for Linux) is unable to run some of the scripts required for booting the Canon GUI in QEMU; the above scenario only works with 32-bit GDB (available in the GCC 5.x package). Maybe it's time to report a bug to GDB (ideally we should find a way to reproduce with non-proprietary code and on vanilla QEMU).

This is an issue under Windows 10 - WSL (where 32-bit Linux binaries do not work) and also on Mac (where only 64-bit builds are available).

DeafEyeJedi

Rather than double posting (or perhaps should have posted in here first) but here's my first attempt at compiling/installing QEMU which seem to have failed under my stupidity since I am unable to empathize what 'please call configure before running make' means?

I'd really like to try and get this whole QEMU experiment under my belt. It's been long overdue. Thanks for any help!
5D3.113 | 5D3.123 | EOSM.203 | 7D.203 | 70D.112 | 100D.101 | EOSM2.* | 50D.109