============= 8051 CPU core ============= There appears to be an 8051 CPU core which acts as an interface controller. In this case, it implements a USB Mass Storage device. The 8051 firmware is only 8 kB, and it appears to be a single generic firmware image that's shared by the bootloader and all versions of application firmware observed. All application firmwares have an identical image that's signed at the end with "~I_blieve:)Faith". The bootloader contains an image that is signed with random-looking hex bytes but which is otherwise identical. Both the 8051 and ARM implement "main loops" which seem to consist entirely of processing messages received over inter-processor communication pipes. So, it would not appear on first inspection that either processor is really in the driver's seat, but ultimately any code or data which differentiates the functionality of the bootloader versus the normal firmware must live on the ARM side of the channel. So this tells us that the tiny 8051 firmware image is probably intended to be very generic. From the perspective of a firmware engineer on the optical drive, this is probably a "black box" binary blob that makes the USB controller work. It seems like we can use this processor for whatever we like; the firmware doesn't seem to be stored in flash, it appears to be in a memory mapped region initialized by the ARM. Of all the weird modified 8051 cores people use, this one seems to be quite tame. In fact, it seems to be fairly light on features. No additional SFRs beyond the standard ones that I can see, only 128 bytes of internal RAM. All the I/O occurs via XDATA, which doesn't seem to have any RAM attached to it. The main I/O idiom is to use one XDATA address as a hardware FIFO to read or write bytes. This is pretty fast, especially if the 8051 runs at a high clock rate. (seems likely) Memory Regions -------------- - Program Memory 8 kB region Serves as the "Internal ROM" in 8051 architecture Loaded/mapped by the ARM core. An example of this region (not necessarily execute-in-place) is at 0xE000 in the bootloader flash. These images are easily recognized by a signature at offset +0x60, "MoaiEasterIslandThomasYoyo(^o^)/". It's unknown whether this string is checked or if it's just a greeting. The "Thomas" part appears again later, in what seems like a very low-level debug message. - Internal RAM 128 bytes, from 00 to 7F. - XDATA (Partially mapped to ARM memory at 41f0000) 4100 - 41ff Shared MMIO [4180] Write IPC? FIFO [4181] On init, write 1C D4 here [4185] IPC? FIFO busy flag 4b00 - 4cff Shared MMIO - USB [4b01] [4b04] [4b06] Flags [4b08] Flags [4b0b] [4b0e] [4b20] Read 8-byte SETUP packet [4b24] Write to 13-byte USB command status buffer [4b32] [4b34] [4b35] [4b50] [4b63] [4b70] [4b71] [4b72] Write trigger for USB reply at [4b24] [4b73] [4bf7] Error response? [4b84] [4b85] [4b86] [4b87] [4b88] [4b94] [4b95] [4b98] [4b9c] [4b9d] [4b9e] [4b9f] [4bc0] [4bc1] [4bc2] [4bc3] [4bc4] [4bc5] [4bc6] [4bc7] [4bc8] [4bc9] [4bca] [4bd2] [4bd3] [4bd9] [4bde] [4bf4] 4d00 - 4dff Shared MMIO [4d01] [4d03] [4d04] [4d0c] [4d50] Write to firmware memory [4d51] Firmware memory read/write flags [4d52] Read from firmware memory [4d70] SCSI CDB [4d90] Firmware-defined opcode byte [4d91] Firmware-defined status byte [4db2] Reset control? 30 -> delay -> 20 -> 30 -> longer delay -> 20 [4da5] [4dad] [4db1] [4dcc] Processor reset flags [4dd0] [4dd1] [4dd4] 8000 - 81ff Local RAM Inter-Processor Communication ----------------------------- The 8051 and ARM processors communicate via a memory mapped FIFO and/or shared memory regions. Firmware region 0010 - 009c This is copied to RAM (just above the stack, at 2000D80) early during boot Overlaps with the 8051 interrupt vector table. This seems to be related to the "Shared Block" described in bootloader.txt Shared Block ------------ [BOOT] 2000d80 - 2000e0b [TS01] 2000cec - In [60]: rdw 2000c00 02000c00 00000200 0000000a 00000000 0a0a0000 00000002 00002100 00000000 00000000 02000c20 435aa000 c6d42700 00000000 00000000 00044000 00044000 0000413a 00004193 02000c40 008d008d 00000000 00920043 00000000 00000000 00000000 00000000 00000000 02000c60 00000000 00000000 ff200000 000000ff 00000000 00000000 00000000 00000000 02000c80 00000000 00000000 00000000 00000000 00000000 00000250 00110000 00000000 02000ca0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000cc0 00000000 0000aa67 00400100 00000000 00000000 00000000 00000000 10000000 02000ce0 01000083 00000100 00000000 003e0000 01c08000 00347600 02000eec 00000000 02000d00 00000001 ff000001 00000009 0000001e 00000000 00000000 ffffff00 00000001 02000d20 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000d40 00000000 00000000 00000001 00000000 00000000 00000000 00000000 00000000 02000d60 00000000 00000000 ff0a2e7c 00030000 ffff0a00 00000000 ffff0000 00050e5f 02000d80 00050096 00001000 00000001 01f5b96d 01f58b5e 00600000 00000465 00000000 02000da0 ffffff00 00000000 00000601 ffffff00 00000000 ffffff00 00000000 00000000 02000dc0 0000ff00 ffff0000 00000000 00000000 ffffff00 0035ef80 00000000 00000000 02000de0 ffffff00 00000000 00000000 00000000 00000000 ffffff00 00000000 00000000 02000e00 00050096 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000e20 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000e40 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000e60 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000e80 00000000 00000000 028fff04 0bb813c0 00000527 00000000 00000000 00000000 02000ea0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000ec0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000ee0 00000011 00000070 ac0c0080 636f6cac 02000ea0 0000001c 00000070 00000000 02000f00 00000000 00000000 00000000 00000000 00000000 000c0000 00000000 00000000 02000f20 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000f40 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 02000f60 00000000 00000000 00000000 00000000 c0c45ee1 53202394 aeee98ba 487e0043 02000f80 8401c20c cd2f0bbf c7159453 d809252b d19e4090 88caab35 e817504c 76b67caa 02000fa0 936a69bf db04180c 76fbfeb3 7848fb80 a9b383a8 06a0930c 983173ee 3e3fe540 02000fc0 bb0c8a12 6e2a7c9c 4e3b433a 369fb227 9cc40895 aee1d615 1228bb9c e4d3461a 02000fe0 34950556 bd40dbec 51dac434 003cff48 b4006c69 81063908 0ef862f9 87f3a0d9 [*] Most of these notes are still from static analysis prior to cmshell, and the numbers are really suspicious. The above dump is much more recent. Seems to be shared by the 8051 and ARM processors. Been abbreviating this as ref[index]. b [ 0] b [ 1] b [ 2] = 0 b [ 3] Oneshot bool flag, if set send SCSI 5 24 0 "Invalid field" error and clear flag. These fields must be to reduce code size. They're redundant with the other SCSI error reporting fields below, but for commonly used errors it's less code repetition to set this bit instead of a full SCSI error code. b [ 4] b [ 5] b [ 6] On command completion, set to 1 by ARM SCSI code b [ 7] = 0 b [ 8] Oneshot bool error flag, SCSI 0 29 6 b [ 9] hf [ a] Transfer length word [ c] Pointer to SCSI command data block (early bootloader main loop) word [10] Address (ARM) 1e2000 1ffff8 >= 200000 Causes exit from bootloader into firmware word [14] Residual byte count < 10000 Different bootloader paths word [18] Address (8051) Stored (low 24 bits) in [4032010] word [1c] Total byte count word [20] ARM address of mapped 8051 memory Aligned on a 16MB boundary (low 24 bits are zero?) +0000 Might be RAM? Related to signature checking? +1000 Start of firmware RAM Calculated based on address from [4030f5c], but the specifics may depend on hardware version. word [24] Index of what I'll call the "working packet" inside the 8051 mapped area, abbreviated wp[] word [28] SCSI command response word [2c] word [30] word [3c] word [40] Current ARM address inside from wp[] word [68] Another shared block, used much less. Been calling this zr[index] (zero reference) since I saw a reference associated with a zero'ed (bss) segment in the 8051 MCU setup. Whereas the regular shared block is referenced to 0xE010 in the 8051 image, zr is referenced to 0xE09C. It's right after the other shared block: 2000e0c - 2000ee7 b [31] Checked early on in INQUIRY? b [3d] b [5c] SCSI command data block, starting with opcode byte b [bc] Internal error code byte, translated to scsi Main Loop --------- A typical main loop on this processor handles inter-processor calls coming in from the ARM. One-time setup: [4B94] = 0 [4D01] = 3 [4D04] = 46 'F' [4B98] = 0 [4d92] = FE [4b95] = 6 [4b73] = 94 [4d84] = 0 Each loop: Ready? [4d91] = 1 Sync? Read FIFO [4d90], repeat until byte is nonzero Read opcode byte, opcode = [4d90] Opcode switch Opcodes: 02 Takes some parameters, some data block parsing? 04 Send SCSI status, "USBS" packets 05 USB block copy, optional "USBS" response 06 Variant of 08 07 Variant of 08 08 Copy USB header from IO memory to RAM ... 09 Variant of 08 0b Variant of 0d 0a Variant of 0d 0c Variant of 0d 0d Implements an entire transfer of some sort, with setup, loop, and status 0e Read 8 byte struct from IO, simple parsing loop 0f Very simple, 8-byte tag/length update? 16 Variant of 04 17 Variant of 05 18 Wrapper for other opcodes: 04 09 07 22 1e 1e Complicated; involves timer, 32-bit length comparisons, two looping transfers 1f Variant of 08 20 Variant of 08 21 SCSI completion: some small USB transfers, optionally fall through to 04 22 Variant of 08 23 SCSI completion: another small USB thing, falls through to 04 24 Variant of 23 25 Variant of 23 27 USB things, may fall through to 0e 28 Variant of 27 with different size calculation 29 Variant of 0d 3b Store 2 bytes: Could be system mode or version info. Same address was cleared by a weird table-driven startup loop. 3c Hardware reset? [4db2]=30 delay [4db2]=20 [4db2]=30 delay [4db2]=20 3f Low-level protocol thing, part of main loop. Sends IPC 83 'A' 'N' [4d91]. Get write/read count? IPCs from ARM often come packed as a 32-bit opcode and up to 12 bytes of params. On the ARM bootloader, this comes in via ipc_message at 46F2. (Possible that these aren't actually IPCs at all, but they're debug logging?) Codes: 49 'I' 49a100aa - Three startup messages, depending on HW type? 49a200aa 49a300aa 49a400aa - Another group of three 49a500aa 49a600aa 49a700aa - Also in init 49ab00aa 49ad00aa 49ae04ea 49af04ea 49b000aa 49b100aa 49b200aa 49b70302 49b800aa 49ca09f2 49cb00aa 49cc00aa 49cd00aa 49ce00aa 49cf00aa 49d100aa 49d200aa 49d300aa 49d500aa 49d708fa 49d808fa 49d908fa 49df0302 49e00302 49e506da 49e600aa 49e800aa 4a 'J' 4a9800aa 4a9e00aa 4aa000aa 4ac800aa 4ac9012a 4aca04ea 4acb04ea 4acc04ea 4acd012a 4ace012a 4acf00aa 4ad0012a 4ad104ea 4ad204ea 4ad304ea 4ad4012a 4ad5012a 4ad6012a 02 02110400 (byte)ref[c], (uint24be)ref[28] R0=code R1=arg1 R2=arg2 R3=arg3 Code is a packed structure { uint8 typeof_args uint8 sizeof_args uint16 opcode } typeof_args: packed list, 2 bits each, MSB to LSB 00=byte 01=half 10=skip 11=word examples: aa=void 2a=byte ea=word fa=word,word f2=word,word,byte Uses zr[c] as command buffer: initiator byte (arg size + e3) opcode high (49, 4a, 02) opcode low argument types byte arguments (variable length) complement of initiator byte (for synchronization?) Opcode groupings Theory: The top byte encodes transfer type or direction info. "__" row lists which ops are implemented in 8051 firmware. 02 11 --- 49 a1 a2 a3 a4 a5 a6 a7 ab ad ae af b0 b1 b2 b7 b8 ca cb cc cd ce cf d1 d2 d3 d5 d7 d8 d9 df e0 e5 e6 e8 4a 98 9e a0 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 __ 02 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 16 17 18 1e 1f 20 21 22 23 24 25 27 28 29 3b 3c 3f Sample messages sent by the 8051, via FIFO at [4180]. (Not sure if these are IPC or not... could be SPI or some other on-chip bus.) Procedure: Loop reading [4185] until bit0 is zero Write (four?) bytes to [4180] Write 1 to [4185] Bytes seen: 83 "232" <-- During boot. Related to moai string? 83 "Tho" 83 "mas" 83 "Spt" 83 "1" 08 00 83 "2" 07 ff 83 "3" f8 00 83 "4" 06 00 83 "spl" 83 46 47 [4d93] 83 [4d79] [4d80] [4d81] 40 91 ea (byte) [4d0c] [4d0c] 83 [4d16] [4d15] [4d14] 40 91 ea 9c [4b94] [4b98] 40 91 ea cb 70 [4d94] USB Descriptors --------------- To focus on one case study where more of the unknowns are known... USB descriptors were found in RAM on the ARM side of the fence. During init: IPC/log code 49b100aa USB init - two different versions based on "appselect" [4002058] register - includes descriptor copy and many other steps - descriptor copy function is the same in both cases Descriptor copy Uses the "working packet" wp[], at ref[24] (8051) via the ref[20] ARM mapping base. - Copy 8 bytes from boot USB descriptor table header to wp[18f0] on 8051 side: 0 1 1 0 0 0 0 0 - Copy device descriptor to wp[18f8]: 12 1 0 2 0 0 0 40 8d e 56 19 0 0 1 2 3 1 - Copy configuration descriptor, 0x20 bytes to wp[190a] - Copy string descriptors starting at wp[192a] - Copy device qualifier descriptor to wp[1a2a] A 6 0 2 0 0 0 40 1 0 IPC/log code 49b200aa ~MeS`14