The Amlogic S905 System-On-Chip is an ARM processor designed for video applications. It's widely used in Android/Kodi media boxes. The SoC implements the TrustZone security extensions to run a Trusted Execution Environment (TEE) that enables DRM & other security features :

Amlogic S905 System Block Diagram
The SoC contains a Secure Boot mechanism to authenticate the TEE image before loading it in TrustZone. And the first link of this Secure Boot chain is the BootROM code, stored directly in the chip.
This articles describes how to extract the BootROM code from this SoC in the Android-based Inphic Spot i7 device . Technical documentation
Amlogic released a public version of the S905 datasheet thanks to Hardkernel . However, it's heavily redacted, and most parts regarding the Secure Boot or the TrustZone have been removed. But we can still find a lot of technical information in GPL source code packages released by Amlogic & OEMs .
For example, we can find a potential address for the BootROM code:
#define ROMBOOT_START 0xD9040000
#define ROM_SIZE (64*1024)
#define ROMBOOT_END (ROMBOOT_START+ROM_SIZE)
Root access over the UARTWe start by connecting the serial port (or UART) because this interface could provide a quick & easy access to debug messages & serial console on bootloaders and linux kernel.
Identifying the serial port on this board is quite simple since there is a port header with labels for the pinout:

UART on Inphic Spot i7 board
We connect an USB to UART adapter to this port. Once the Linux kernel boot process is finished, we have directly access to a root shell.
We can start to explore the (Non-Secure side of the) system.For example, we can dump the partitions :
root@p200:/ # ls -l /dev/block/platform/d0074000.emmc/
lrwxrwxrwx root root 2015-01-01 00:00 boot -> /dev/block/boot
lrwxrwxrwx root root 2015-01-01 00:00 bootloader -> /dev/block/bootloader
drwxr-xr-x root root 2015-01-01 00:00 by-num
lrwxrwxrwx root root 2015-01-01 00:00 cache -> /dev/block/cache
lrwxrwxrwx root root 2015-01-01 00:00 crypt -> /dev/block/crypt
lrwxrwxrwx root root 2015-01-01 00:00 data -> /dev/block/data
lrwxrwxrwx root root 2015-01-01 00:00 env -> /dev/block/env
lrwxrwxrwx root root 2015-01-01 00:00 instaboot -> /dev/block/instaboot
lrwxrwxrwx root root 2015-01-01 00:00 logo -> /dev/block/logo
lrwxrwxrwx root root 2015-01-01 00:00 misc -> /dev/block/misc
lrwxrwxrwx root root 2015-01-01 00:00 mmcblk0 -> /dev/block/mmcblk0
lrwxrwxrwx root root 2015-01-01 00:00 mmcblk0boot0 -> /dev/block/mmcblk0boot0
lrwxrwxrwx root root 2015-01-01 00:00 mmcblk0boot1 -> /dev/block/mmcblk0boot1
lrwxrwxrwx root root 2015-01-01 00:00 mmcblk0rpmb -> /dev/block/mmcblk0rpmb
lrwxrwxrwx root root 2015-01-01 00:00 recovery -> /dev/block/recovery
lrwxrwxrwx root root 2015-01-01 00:00 reserved -> /dev/block/reserved
lrwxrwxrwx root root 2015-01-01 00:00 rsv -> /dev/block/rsv
lrwxrwxrwx root root 2015-01-01 00:00 system -> /dev/block/system
lrwxrwxrwx root root 2015-01-01 00:00 tee -> /dev/block/tee
While the tee partition (Trusted Execution Environment) turns out to be empty, the bootloader partition contains several bootloaders. But not the BootROMbecause it's stored in the SoC, not the flash.
(Fail at) Reading the BootROMSince we have root permissions and a potential memory address for the BootROM, we can try to read it directly. The provided Android ROM contains a handy debugfs interface to peek & poke physical memory from user-land:
root@p200:/ # echo "d0070000" >/sys/kernel/debug/aml_reg/paddr
root@p200:/ # cat /sys/kernel/debug/aml_reg/paddr
[0xd0070000] = 0x1000254This aml_reg driver uses the ioremap kernel function to set up an appropriate kernel page-table mapping for the requested address.
However, if we try to read the hypotheticalBootROMarea:
root@p200:/ # echo "d9040000" >/sys/kernel/debug/aml_reg/paddr
root@p200:/ # cat /sys/kernel/debug/aml_reg/paddr
[ 376.546491@0] Unhandled fault: synchronous external abort (0x96000010) at 0xffffff80001aa000 [ 376.549396@0] Internal error: : 96000010 [#1] PREEMPT SMP [ 376.554712@0] Modules linked in: dwc_otg dhd(O) aml_thermal(O) mali(O) aml_nftl_dev(PO)The kernel crashes. So either theBootROMaddress is wrong or this memory area is set as secure .
Since we don't have other candidates for theBootROMaddress, let's say theBootROMarea is not accessible fromtheNon-Secure World.
Enter the Secure WorldIn theory, the Secure Boot chain prevents loading unauthorized code in the Secure World.
A quick inspection of debug logs from the UART during the early phases of boot indicates that the bootloaders are based on the ARM Trusted Firmware (ATF) reference implementation.

ARM Trusted Firmware Design
We will now explore some ways to get access to Secure World.
U-Boot bootloaderUsing the console over UART, we can interrupt the U-Boot boot sequence to access to the prompt. From here we can run arbitrary U-boot commands:
Hit any key to stop autoboot: 0
gxb_p200_v1#help
? - alias for 'help'
aml_sysrecovery- Burning with amlogic format package from partition sysrecovery
amlmmc - AMLMMC sub system
amlnf - aml nand sub-system
amlnf_test- AMLPHYNAND sub-system
autoping- do auto ping test
autoscr - run script from memory
However the U-Boot bootloader (named BL33 in the ATF design) runs in Non-Secure mode as we can see in boot logs from the UART console:
INFO: BL3-1: Preparing for EL3 exit to normal world
INFO: BL3-1: Next image address = 0x1000000
INFO: