Overview

This is the file format for the 3DS' Firmware, it contains four 'sections' of ARM code (ARM9 and ARM11). The firmware sections are not encrypted in the FIRM format.

The ARM9 section contains the ARM9 kernel and the ARM9 process(exheader process name is "Process9"). The ARM11 section(s) contains the ARM11 kernel, and the ARM11 process(es). For NATIVE_FIRM/SAFE_MODE_FIRM these ARM11 processes are sm, fs, pm, loader, and pxi. Normally the 4th section is not used. The code loaded from FIRM is constantly running on the system until another FIRM is launched. The ARM11 kernel is hard-coded to always decompress the FIRM ARM11 modules ExeFS .code, the exheader compression bit is not checked.

FIRM Header

OFFSET SIZE DESCRIPTION
0x000 4 Magic 'FIRM'
0x004 4 Reserved1
0x008 4 ARM11 Entrypoint
0x00C 4 ARM9 Entrypoint
0x010 0x030 Reserved2
0x040 0x0C0 (0x030*4) Firmware Section Headers
0x100 0x100 RSA-2048 signature of the FIRM header, using SHA-256.

Firmware Section Headers

OFFSET SIZE DESCRIPTION
0x000 4 Offset
0x004 4 Address
0x008 4 Size
0x00C 4 Firmware Type ('0'=ARM9/'1'=ARM11)
0x010 0x020 SHA-256 Hash of Firmware Section

NATIVE_FIRM and SAFE_MODE_FIRM

NATIVE_FIRM is the FIRM which is installed to the NAND firm partitions, which is loaded by bootrom. SAFE_MODE_FIRM and NATIVE_FIRM for the initial versions are exactly the same, except for the system core version fields. SAFE_MODE is used for running the System Updater.

TWL_FIRM and AGB_FIRM

TWL_FIRM handles DS(i) backwards compatibility, while AGB_FIRM handles running GBA VC titles. The ARM9 FIRM section for TWL_FIRM and AGB_FIRM are exactly the same(for TWL_FIRM and AGB_FIRM versions which were updated with the same system-update).

TWL_FIRM

The 3DS-mode ARM9 core seems to switch into DSi-mode(for running DSi-mode ARM9 code) by writing to a PDN register(this changes the memory layout to DSi-mode / etc, therefore this register poke *must* be executed from ITCM). This is the final 3DS-mode register poke before the ARM9 switches into DSi-mode. It's unknown how exactly DS(i)-mode ARM7 code is run. Trying to read from the exception-vector region(address 0x0) under this DSi-mode ARM7 seems to only return 0x00/0xFF data. Also note that this DSi-mode ARM7 runs code(stored in TWL_FIRM) which pokes some DSi-mode registers that on the DSi were used for disabling access to the DSi bootROMs, however these registers do not affect the 3DS DSi-mode ARM9/ARM7 "bootrom" region(exceptionvector region + 0x8000) at all.

For shutting down the system(?), TWL_FIRM writes u8 value 8 to I2C MCU register 0x20. For returning to 3DS-mode, TWL_FIRM writes value 4 to that MCU register to trigger a hardware system reboot.

FIRM Launch Parameters

The FIRM-launch parameters structure is located at FCRAM+0, size 0x1000-bytes. The ARM11-kernel copies this structure elsewhere, then clears the 0x1000-bytes at FCRAM+0.

OFFSET SIZE DESCRIPTION
0x400 0x4 Flags
0x410 0xC This is used for overriding the FIRM_* fields in Configuration_Memory, when the flag listed below is set, in the following order(basically just data-copy from here to 0x1FF80060): "FIRM_?", FIRM_VERSIONREVISION, FIRM_VERSIONMINOR, FIRM_VERSIONMAJOR, FIRM_SYSCOREVER, and FIRM_CTRSDKVERSION.
0x438 0x4 The kernel checks this field for value 0xFFFF, if it matches the kernel uses the rest of these parameter fields, otherwise FIRM-launch parameters fields are ignored by the kernel.
0x440 0x10 Titleinfo structure, used by NS during NS startup, to launch the specified title when the below flag is set.
0x450 0x10 Titleinfo structure. This might be used for returning to the specified title, once the above launched title terminates?
0x460 0x4 Bit0: 0 = titleinfo structure isn't set, 1 = titleinfo structure is set.

Flags from offset 0x400:

OFFSET SIZE DESCRIPTION
0x0 0x1 This can be used for overriding the default FCRAM memory-regions allocation sizes(APPLICATION, SYSTEM, and BASE). The values for this is the same as Configmem-APPMEMTYPE. Values 0-1 are handled the same way by the kernel. However for NS, 0=titleinfo structure for launching a title isn't set, while non-zero=titleinfo structure is set.
0x1 0x3 Setting bit0 here enables overriding the FIRM_* fields in Configuration_Memory.