Aptina MT9V113 internal MCU stuff
The Aptina cameras have an internal 68HC11-based MCU. Parts of its address space can be accessed through the XDMA registers (0x98c, 0x990, reachable over I2C)
There's a "physical" address range (0x0000..0x1fff) and a "virtual"/"logical" one (0x2000..0x3fff). The former can be used to access "system" and "user RAM" (resp. 0x0000..0x03ff and 0x0400..0x7ff), as well as "Special Function Registers" (SFRs), basically just MMIO regs of the HC11. The latter allows access to the variable spaces of several "firmwares"/"services" running on the MCU, used for autofocus, autowhitebalance, etc. Each camera has a separate HC11.
The above is already kinda known, but now for the new stuff. (
Keep this section of GBATEK at hand while reading this, as I guess only a handful people ever looked at the cameras to begin with.)
(NOTE: as the HC11 is an 8/16-bit MCU, pointers etc. are 16-bit (its address space is 16 bits wide). Also, it's a big-endian architecture, keep that in mind.)
SFRs
- 0x1040: watchdog reset: write 0 to this address to calm down the watchdog timer.
- 0x1048: "high-precision timer": 32-bit timer value that probaly increases by 1 every 16 MHz tick.
- 0x1050: "pagetable" pointer: pointer to a list of 16 addresses used to determine to which physical addresses the virtual ones will resolve.
- 0x1060..0x1066: "ring bus access" or so, not too sure what this is, but it looks like it gives you some sort of DMA access. Sadly, I don't know which registers in this range are address ones, and which ones are used for data.
- 0x1070: GPIO (already documented on GBATEK, didn't touch it myself.)
Address translation
As alluded to in the previous part, SFR 0x1050 is used to set the mapping. Its value is 0x0100, which means we can access and modify the "pagetable mapping" over I2C. (I'm using quotes here because it's far from anything like a real MMU.)
At 0x0100, a list of 16 pointes can be found: 0x0140 (MONITOR), 0x0000 (SEQ), 0x005d (AF), 0x0165 (AWB), 0x01d4 (FD), 0, 0, 0x282 (MODE), 0, 0, 0, 0x0220 (HG), and then more zeros.
This matches what you'll find when dumping the 0x2000..0x2fff area. While system RAM has space for 16 more pointers (starting at 0x0120) for addresses 0x3000..0x3fff, in practice these are mirrors of the 0x2*** range.
Setting a pagetable entry to an address of 0x2000 or higher seems to return 0 values, maybe there's a carveout, or maybe there's just nothing behind those addresses. Additionally, it does seem to mirror the upper half of memory (0x8000 and up) to the lower half, which is *quite* suspicious as a datasheet says there's 32 kilobytes of firmware ROM, and the exception vectors of the HC11 are at 0xfffe etc. (6502-style) So I'm betting the firmware ROM is in the upper half of MCU memory.
System RAM layout
With the above, we can start building a map of the system RAM space. As one datasheet (links at the end of this post) alludes to the stack of the HC11 firmware also being in system RAM and being 128 bytes in size, it's not too hard to guess where it is.
- 0x000..0x047: SEQ
- 0x05d..0x0c0: AF
- 0x100..0x11f: page table
- 0x120..0x13f: unused shadow pagetable? idk
- 0x140..0x168: MONITOR
- 0x165..0x1d2: AWB
- 0x1d4..0x1f4: FD
- 0x220..0x286: HG
- 0x282..0x2ea: MODE (yes this overlaps with HG)
- 0x300..0x37f: ??? (maybe stack but I doubt it)
- 0x380..0x3ff: stack
The 0x380 region seems to be 0xdeadbeef (big-endian)-filled and grows from high addresses to low ones. Additionally, it's one of the RAM regions that seems to get reset regularly (see below). This gives me a relatively high conficence to say it is the stack of the HC11.
User RAM (0x0400 and on) doesn't seem to be writable, sadly. Or maybe I'm missing some kind of magic switch.
Running code on the HC11
A datasheet alludes to using the MONITOR variables to run code: arg1 is the pointer of the code to run, arg2 an optional argument (where is this put in? the accumulators?), and then set cmd to 0x01 to start the code.
Sadly, this did not work for me: it resets the MCU, while doing not much else. Maybe it needs some kind of CRC (which the datasheet also alludes to), or maybe the feature is just locked away. (EDIT: maybe the resetting thing would be added to have the XDMA thing avoid messing with internal state. But does using the virtual addressing mode bypass it? Would chaining using another peripheral (the "ring bus access" maybe?) be able to be used as a bypass? I haven't tested.)
Then I tried putting some shellcode in low system RAM and filling the stack with bad addresses (that is at the same time a NOP sled). Sadly this didn't work either, as the MCU also got reset before it got to execute my code. Maybe I'm triggering some kind of (bad) crash, or maybe there's a safety mechanism that automatically resets everything. (I hope it's not the latter.)
(MCU resets seem to clear/reset the pagetable, stack (0x0380 and up), and some of the "logical variable" spaces in system RAM. 0x300..0x37f seems to be preserved, as well as some other small places in low system RAM.)
Maybe this is a fun challenge for someone else here?
P.S. I used Pk11's
dsi-camera proof-of-concept as a base to mess with the cameras. Not really publishing my code because it's mostly just a spaghetti of I2C accesses and FIFO ugliness. I used
vasm as HC11 assembler, though be aware that it gets some opcodes wrong, check with
A09 (which doesn't seem to be able to process "org" directives) and
this and
this opcode listing I found. For more info on the HC11, see
this (original DIP CPU info) and
this (more modern microcontroller impl, only gave it a cursory glance, idk how useful it is outside of the instruction set info).
Datasheets
Also a neat link:
https://files.niemo.de/aptina_pdfs/