For tech details, see
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition. Understanding and using this does require knowledge of ARM assembly.
It's now known that the main ARM cores in DIGIC 7, 8, X are ARM Cortex A9.
There have been occasional comments about using the MMU, but I don't remember seeing any actual research or code.
So, here's this as a start.
The Cortex A9 can address 4GB memory. About the half of that can be RAM.
All DIGIC 7 and later cameras seem to have a very similar memory layout, see
this post from a1ex for example.
Most of physical memory is mapped to the same virtual address - except for the first 4kB.
When reviewing the memory mapping related routines on my D7 and D8 cameras, I found that the main firmware (EOS and PowerShot) uses the ROM translation tables when it starts.
The ROM tables are located at the start of ROM (address 0xe0000000), their complete size is 0x4900 bytes.
They consist of the following:
- 0x4000 bytes of L1 table for both cores, describing logical addresses from 32MB upwards
- 0x400 bytes of L2 table describing logical address range 0...1024kB, core0
- 0x400 bytes of L2 table describing logical address range 0...1024kB, core1
- 0x80 bytes of L1 table describing logical address range 0...32MB, core0
- 0x80 bytes of L1 table describing logical address range 0...32MB, core1
It turned out recently that DIGIC X models use a RAM copy of the tables. I have not done any review on a DIGIC X firmware, so it could be that my D7 and D8 findings do not apply there.
So, below is for DIGIC 7 and 8.
There is a RAM copy of translation tables. On PowerShot firmware models, their location is at 0xdffc0000, EOS firmware uses an _uncached_ dynamically allocated RAM copy.
The firmware switches to the RAM copy whenever it is about to write into ROM (and switches back when it's done). I _think_ that mostly happens just before a clean shutdown.
If it turns out that it can happen during normal camera operation, one will have to patch the routines responsible for switching the translation tables.
For my current experiment on my D7 camera, I don't do that.
I have to note that there is a tradeoff between fine-grained memory mapping and CPU performance. The less L2 tables, the better performance.
The Canon tables are pretty efficient, supersections (16MB granularity) are used mostly.
In my current implementation, I settled for 64kB granularity when doing ROM replacement.
Replacing parts of ROM with modified RAM copy.
Since the firmware doesn't change mapping while it runs, it is possible to make a modified static mapping at boot time (when autoexec.bin executes).
Making the modified tables is a job for one CPU core, but both cores need to be set to the new tables.
It is also important to make sure that both cores have their caches in sync before they are set to use the new tables.
In order to be able to replace larger amounts of ROM, one needs RAM that is not used by any part of the camera.
- RAM for the translation tables (0x4900 bytes for copying the Canon tables and 0x400 bytes for each L2 table).
The Canon tables need to be copied to a 16kB-aligned address, the alignment of L2 tables is 0x400 bytes.
- RAM for the replaced ROM pages, 64kB (aligned) for each page.
To find that RAM, one can start with reviewing the output of smemShowFix, looking for holes, preferably in the common section. The hole needs to be verified by reviewing the disassembly/disassemblies, looking for addresses that fall into the hole's range.
In some cases, the firmware of other (ARM, Xtensa) cores needs to be reviewed too.
The other way of making sure a memory area is unused is dumping the suspected hole's content to a file before/after doing all sorts of camera operations, and then comparing the dumps.
When one or more suitable holes are found, one can start doing what I did in my EOS M100 port.
I wrote a few words about that
here.
The (currently) latest source can be found attached to
this post (the 7z archive).
Files of interest are
platform/m100/sub/mmuutils.c
platform/m100/sub/100a/boot.c (usage example)
platform/m100/sub/100a/replaced.c (usage example)
platform/m100/sub/100a/stubs_entry_2.S (related stubs)
See also comments in those files.
Some other notes:
Changes made to the ROM content are only visible to the main ARM cores. For example, it is not possible to modify ROM data that is later transferred from ROM by DMA.
I'm sure there is a lot I did not mention, I'll try to answer questions. Corrections and different approaches are also welcome.