Language / Idioma: [🟢 English] | Português
Automated installer to transfer Armbian from USB/SD to eMMC on AMLogic TV Boxes, with special support for locked bootloader devices. Specifically developed for Armbian, but adaptable to other ARM Linux distributions with technical knowledge.
Author: Pedro Rigolin
Project: Developed for the TVBox Project at Federal Institute of São Paulo (IFSP), Salto Campus
- 📦 About the TVBox Project
- 🔍 Overview
- ✨ Features
- 🚀 Quick Start
- 🔧 Manual Installation
- 📱 Usage
- 🔧 Technical Details
- 🔬 U-Boot Variables Extraction
- ➕ Adding New Devices
- 📋 Logs and Debug
- 💡 Technical Notes and Advanced Tips
- 🔧 Troubleshooting
- 🙏 Credits
- 👥 Contributors
- 📄 License
⚠️ Legal Disclaimer
This installer was developed as part of the TVBox Project at IFSP Salto Campus, an initiative aimed at giving new purpose to TV Box devices seized by the Federal Revenue Service.
The project decharacterizes this equipment, transforming them into functional mini PCs with Linux, providing:
- Hardware reuse that would otherwise be discarded
- Digital inclusion through donations to communities
- Reduced environmental impact (e-waste)
- Technical training for students
This code was specifically developed to automate Armbian installation on AMLogic devices (S905X/X2/X3), facilitating large-scale reconfiguration processes.
Standard Armbian uses a single ext4 partition, but many AMLogic devices (especially TV Boxes with S905X/X2/X3/X4 SoCs) require dual partitioning to work correctly:
Partition 1: BOOT (FAT32) → Kernel, DTB, boot scripts
Partition 2: ROOTFS (ext4) → Root file system
💡 Need to convert your Armbian image to the dual partition format?
The armbian-amlogic-image-repacker (also from the TVBox Project) automates exactly this step — it repacks the standard Armbian image into theBOOT (FAT32) + ROOTFS (ext4)structure expected by these devices.
The Problem:
When the Armbian system is converted to this 2-partition structure (required for these devices), the official Armbian installer (armbian-install) stops working, as it was designed exclusively for single ext4 partitions.
The Solution:
This installer restores automation for system transfer to internal eMMC, specifically adapted for the dual partition structure required by AMLogic TV Boxes. Additionally, it offers:
- ✅ Automated installation of dual-partition Armbian to eMMC
- ✅ U-Boot variable injection (why?) for locked devices
- ✅ Interactive interface (TUI) for device and profile selection
- ✅ Device-specific profile support (custom offsets)
The installer assumes the current system is running from a USB/SD card with the following structure:
Partition 1: BOOT (FAT32, up to 512MB)
Partition 2: ROOTFS (ext4, remaining space)
This installer was specifically developed for Armbian, optimized for its boot structure and configuration files (armbianEnv.txt, DTBs, etc.).
| Device | SoC | Profile | Status | Notes |
|---|---|---|---|---|
| HTV H8 | AMLogic S905X4 | htv_h8.conf |
✅ Tested | 128 MB offset, regenerated variables |
| BTV E10 | AMLogic S905X3 | btv_e10.conf |
✅ Tested | 136 MB offset, preserved Amlogic structure |
| ATV A5 | AMLogic S905X3 | atv_a5.conf |
✅ Tested | 136 MB offset, preserved Amlogic structure |
| Generic | AMLogic S905X/X2/X3/X4 | No profile | Default 128 MB offset, no U-Boot variable injection |
About generic installation:
⚠️ Only works for devices with unlocked bootloader⚠️ Does not inject custom U-Boot variables⚠️ May result in black screen if bootloader cannot find kernel- ✅ Useful for initial testing on new devices
- 💡 Recommended: Extract U-Boot variables and create custom profile
Can it be adapted to other Linux distributions?
✅ Yes, as long as the distribution follows the same partition structure (BOOT FAT32 + ROOTFS ext4). Examples:
- Debian with similar partitioning
- Ubuntu for ARM
- Other Debian/Ubuntu-based distros
- Understanding of U-Boot and boot scripts
- Modification of paths and configuration files in code
- Adjustment of Armbian-specific checks
- Extensive testing to ensure correct boot
Recommendation: If you don't have experience with ARM bootloaders and advanced shell scripting, use the installer only with Armbian as designed.
- ✅ Interactive interface with dialog menus
- ✅ Automatic detection of available eMMC disks
- ✅ Device-specific profiles (ATV A5, BTV E10, HTV H8)
- ✅ U-Boot variable injection (why?) for locked devices
- ✅ Detailed logging for debugging (
/tmp/armbian-install-amlogic.log) - ✅ Automatic cleanup system (unmounts on error/interruption)
- ✅ Dependency checking with automatic installation
- ✅ Single instance lock (prevents simultaneous executions)
- ✅ Customizable partitioning per device profile
This repository contains three distinct scripts with complementary roles — it is important not to confuse them:
| Script | Role |
|---|---|
armbian-install-amlogic.sh |
The main installer. Transfers Armbian from USB/SD to the device's internal eMMC. This is what the end user runs on the target hardware. |
install-to-system.sh |
System installer. Injects armbian-install-amlogic.sh and device profiles into the Armbian system already running from USB/SD, preparing it for the eMMC installation. |
install-to-image.sh |
Image installer. Injects armbian-install-amlogic.sh and device profiles directly into an Armbian .img file, before it is flashed to USB/SD. Useful for preparing the image on a computer before taking it to the hardware. |
The typical flow is: use install-to-system.sh or install-to-image.sh to prepare the environment → boot the device from USB/SD → run armbian-install-amlogic to install to eMMC.
During installation via install-to-system.sh or install-to-image.sh, the installer asks for the U-Boot asset format for each selected profile:
- Compressed (
.img.gz) — recommended: occupies significantly less disk space (typically 90%+ reduction).armbian-install-amlogic.shdecompresses the asset automatically viapigzduring eMMC injection, with no prior decompression needed. Ideal for keeping multiple profiles on USB/SD without wasting space. - Decompressed (
.img): eliminates the decompression overhead at the time of eMMC installation. Only relevant on hardware with a very limited CPU wherepigzdecompression would be a noticeable bottleneck — which rarely occurs in practice.
Recommendation: use
.img.gzin almost all cases. The difference in installation time is imperceptible in practice, and the space savings are substantial.
Use install-to-system.sh when the Armbian system is already running directly from USB/SD on the target hardware or any Debian/Ubuntu machine. The installer automatically detects and installs dependencies via apt, presents an interactive menu for profile selection, and copies all necessary files to the correct destinations.
📍 Context: Run on the Armbian system from USB/SD, before executing
armbian-install-amlogicto install to eMMC.
# Clone the repository
git clone https://github.com/projetotvbox/armbian-install-amlogic.git
cd armbian-install-amlogic
# Run the installer
sudo chmod +x ./install-to-system.sh
sudo ./install-to-system.shThe installer will:
- Check and automatically install dependencies via
apt - Present a checklist for selecting desired device profiles — including the generic installation option (no specific profile)
- For each profile with an asset, ask the installation format (
.img.gzor.img) - Copy the main script, profiles and assets to the correct destinations (
/usr/bin/and/etc/armbian-install-amlogic/) - Set appropriate permissions
After installation, run the main installer to transfer the system to eMMC:
sudo armbian-install-amlogicUse install-to-image.sh when you want to prepare the Armbian image on a computer before flashing it to USB/SD. The script attaches the image via losetup, automatically identifies the rootfs partition, and injects all files, leaving the image ready for use.
⚠️ Host requirements:dialog,pigz,losetup,blkid,fdisk. The script checks and lists which ones are missing, but does not install automatically — the host system can be any Linux distribution.
# Clone the repository
git clone https://github.com/projetotvbox/armbian-install-amlogic.git
cd armbian-install-amlogic
# Run the installer passing the image path as argument
sudo chmod +x ./install-to-image.sh
sudo ./install-to-image.sh /path/to/Armbian.imgThe installer will:
- Check dependencies on the host system
- Attach the image as a loop device via
losetup -fPand identify the rootfs (ext4) partition viablkid - Present a checklist for selecting desired device profiles — including the generic installation option
- For each profile with an asset, ask the installation format (
.img.gzor.img) - Mount the rootfs, inject the files, sync and safely unmount
After injection, the image is ready to be flashed to USB/SD. Once booted, run:
sudo armbian-install-amlogicUse this section only if you prefer not to use the automatic installers, or if you need greater control over the process.
📍 Context: The commands below should be executed on the Armbian system running from USB/SD card.
The .img.gz assets are automatically resolved by the installer. Decompress manually only if you prefer to eliminate decompression overhead:
cd armbian-install-amlogic/assets/ && gunzip -k *.img.gz && cd ../..sudo cp armbian-install-amlogic.sh /usr/bin/armbian-install-amlogic
sudo chmod +x /usr/bin/armbian-install-amlogicsudo cp -r armbian-install-amlogic /etc/sudo chmod -R 755 /etc/armbian-install-amlogic
sudo find /etc/armbian-install-amlogic -type f -exec chmod 644 {} \;sudo armbian-install-amlogicTo inject the installer into a .img image without using install-to-image.sh:
LOOP_DEV=$(sudo losetup -fP --show /path/to/Armbian.img)
echo "Loop device: $LOOP_DEV"# List partitions and their filesystem types
sudo blkid ${LOOP_DEV}p*The rootfs partition will be the one with type ext4, usually ${LOOP_DEV}p2.
sudo mkdir -p /mnt/armbian-rootfs
sudo mount ${LOOP_DEV}p2 /mnt/armbian-rootfs# Main script
sudo cp armbian-install-amlogic.sh /mnt/armbian-rootfs/usr/bin/armbian-install-amlogic
sudo chmod +x /mnt/armbian-rootfs/usr/bin/armbian-install-amlogic
# Profiles and assets
sudo mkdir -p /mnt/armbian-rootfs/etc/armbian-install-amlogic
sudo cp -r armbian-install-amlogic/profiles /mnt/armbian-rootfs/etc/armbian-install-amlogic/
sudo cp -r armbian-install-amlogic/assets /mnt/armbian-rootfs/etc/armbian-install-amlogic/
# Permissions
sudo chmod -R 755 /mnt/armbian-rootfs/etc/armbian-install-amlogic
sudo find /mnt/armbian-rootfs/etc/armbian-install-amlogic -type f -exec chmod 644 {} \;sync
sudo umount /mnt/armbian-rootfs
sudo losetup -d "$LOOP_DEV"The image is ready to be flashed.
The installer presents an interactive interface (TUI) that will guide you through the process:
-
Target eMMC disk selection
- Automatically detects available disks
- Excludes current system disk
-
Device profile selection
- Lists available profiles (ATV A5, BTV E10, HTV H8)
- "Generic" option for unlisted devices
-
Safety confirmations
- Data erasure warnings
- Correct device confirmation
-
Automatic installation
- Disk wipe
- U-Boot variable injection (if applicable)
- Partitioning and formatting
- Data copy
- Boot configuration
Select the profile corresponding to your device. The installer will:
- ✅ Load specific configurations
- ✅ Inject U-Boot variables (if needed)
- ✅ Apply correct partition offsets
- ✅ Maximize successful boot chances
Supported devices:
- ATV A5 (S905X3)
- BTV E10 (S905X2)
- HTV H8 (S905X4)
For devices with unlocked bootloader or unlisted:
⚠️ Does not inject U-Boot variables⚠️ Uses conservative offset (128MB / sector 262144)⚠️ May result in black screen on locked devices- ℹ️ Use only if you know what you're doing
When to use:
- Device has unlocked bootloader
- You're sure you don't need custom variables
- Testing a new model
The script automatically checks and installs the following dependencies:
pv- Progress viewer for disk operationsncurses-bin- Providestput(required bydialog)dialog- TUI interface for interactive menusdosfstools- FAT32 filesystem tools (mkfs.vfat)e2fsprogs- ext4 filesystem tools (mkfs.ext4)util-linux- Provideslsblk,blkid,flock,dmesg,mount,umountfdisk- Partition table editor (resolved by binary detection: on systems where it's already bundled inutil-linux, it is not installed separately)parted- Providespartprobeto notify the kernel of partition changeshexdump- Binary data hex inspection (resolved by binary detection:bsdextrautilson Debian 11+,bsdmainutilson Ubuntu and older versions)pigz- Parallel gzip compression, used for on-the-fly asset decompressionrsync- Efficient file synchronizationudev- Providesudevadm
⚠️ Warning: The packages above will be automatically installed if not already present on the system. The script automatically detects the correct package forhexdumpandfdiskbased on the distribution in use, ensuring compatibility with Debian 11+, Ubuntu Focal, and derivatives. If you wish to remove them after installation, usesudo apt remove <package>. Note: packages such asutil-linuxandudevare essential system components — do not remove them unless you are certain they are not used by other programs.
armbian-install-amlogic/
├── armbian-install-amlogic.sh # Main installer script
└── armbian-install-amlogic/
├── assets/ # U-Boot variables (binary .img files)
│ ├── uboot_envs_atv_a5.img.gz
│ ├── uboot_envs_btv_e10.img.gz
│ └── uboot_envs_htv_h8.img.gz
└── profiles/ # Device-specific configurations
├── atv_a5.conf
├── btv_e10.conf
└── htv_h8.conf
The .img files in assets/ contain pre-configured U-Boot environment variables. These binaries are injected directly into eMMC at specific offsets, instructing the bootloader where to find the Linux kernel.
Why is this necessary?
The factory bootloader from Amlogic typically comes with restrictive U-Boot variables, only allowing boot on specific systems for which they were originally configured.
The problem:
-
TV Box manufacturers modify these variables to be more permissive, facilitating:
- Boot on multiple operating systems
- Recovery processes
- Greater firmware flexibility
-
During eMMC wipe/zeroing, these permissive variables customized by manufacturers are erased
-
After installation, the bootloader reverts to Amlogic's restrictive factory settings
-
Result: The installed Armbian system cannot boot, even though it's correctly installed
The solution (Assets):
The .img files in assets preserve and reinject the manufacturer's permissive variables after installation, ensuring that:
- Armbian boots correctly from eMMC
- Boot scripts (
s905_autoscript,emmc_autoscript) are found - Alternative boot via SD/USB continues working
- System has the same flexibility as original Android/firmware
When are assets NOT needed?
If your device has unlocked or factory-permissive bootloader (not customized by manufacturer), you can safely use generic installation without U-Boot variable injection. In this case:
- Bootloader already searches for kernels on multiple media (SD/USB/eMMC)
- No custom variables that will be lost during wipe
- Installation will work normally without assets
Each .conf file contains:
| Field | Description |
|---|---|
BOARD_NAME |
Human-readable device name (e.g., "ATV A5 (S905X3)") |
AUTHOR |
Profile author |
ENV_OFFSET |
Sector where to inject U-Boot variables (usually 0) |
ENV_FILE |
Path to variables .img file |
LINUX_START_SECTOR |
First partition start sector (device-customized) |
eMMC Layout:
┌─────────────────────┬──────────────────┬───────────────────────┐
│ Reserved Area │ BOOT (FAT32) │ ROOTFS (ext4) │
│ (varies by profile)│ (512MB) │ (remaining) │
│ Start → Offset │ Offset+ │ Calculated │
└─────────────────────┴──────────────────┴───────────────────────┘
- Reserved Area: Initial region reserved for injected U-Boot variables (size varies by device)
- BOOT Partition: 512MB FAT32, contains kernel, DTB, boot scripts
- ROOTFS Partition: ext4, occupies all remaining space
Each device defines its own LINUX_START_SECTOR (where BOOT partition starts):
| Profile | LINUX_START_SECTOR | Reserved Size | Extraction Method |
|---|---|---|---|
| HTV H8 | 262144 | 128 MB | Method 1 (Regeneration) |
| BTV E10 | 278528 | 136 MB | Method 2 (Ampart) |
| ATV A5 | 278528 | 136 MB | Method 2 (Ampart) |
The correct offset is determined during the U-Boot variables extraction process (see U-Boot Variables Extraction).
The installer uses a profile-customized initial offset to ensure Linux partitions don't overwrite injected U-Boot variables.
Examples of used offsets:
| Device | Offset (sectors) | Size (MB) | Method / Reason |
|---|---|---|---|
| HTV H8 | 262144 | 128 MB | Method 1 - Regenerated variables, conservative offset |
| BTV E10 | 278528 | 136 MB | Method 2 - Amlogic structure preserved via ampart |
| ATV A5 | 278528 | 136 MB | Method 2 - Amlogic structure preserved via ampart |
| Generic | 262144 | 128 MB | No profile - Conservative margin |
Why is offset necessary?
- Leave space for injected U-Boot variables
- Avoid conflict with residual Android structures
- Ensure proper alignment for eMMC performance
- Accommodate different AMLogic device layouts
Golden Rule: Each profile defines its LINUX_START_SECTOR based on extraction method used (Method 1 or 2). The installer never starts Linux partitions before this safe position.
This diagram shows the internal execution flow of the installer, including all verification, partitioning, and variable injection steps:
flowchart TD
A[Start] --> B{Check<br/>Root}
B -->|No| C[Error: Run as root]
B -->|Yes| D[List Available Profiles]
D --> E[User Selects Profile]
E --> F{ENV_FILE<br/>specified?}
F -->|Yes| G{File<br/>exists?}
F -->|No| H[Generic Mode: No Injection]
G -->|No| I[Error: ENV_FILE not found]
G -->|Yes| J[Detect Boot Source]
H --> J
J --> K{SD/USB<br/>or eMMC?}
K -->|eMMC| L[Error: Already installed on eMMC]
K -->|SD/USB| M[Select Target Device]
M --> N[Confirm Installation]
N --> O[eMMC Wipe]
O --> P{ENV_FILE<br/>exists?}
P -->|Yes| Q[Inject U-Boot Variables]
P -->|No| R[Skip Injection]
Q --> S[Partition eMMC]
R --> S
S --> T[Format Partitions]
T --> U[Mount Partitions]
U --> V[Copy System]
V --> W[Update UUIDs]
W --> X[Sync Data]
X --> Y[Unmount Partitions]
Y --> Z[Installation Complete]
Z --> AA[End]
C --> AA
I --> AA
L --> AA
Note for Developers:
- Profile validation: The installer resolves
ENV_FILEin two steps: first tests the exact path defined in.conf(expected as.img); if not found, tests the same path with.gzsuffix. If.gzis found, runs integrity validation viapigz -tbefore proceeding. If neither exists, aborts with error.- Variable injection: If the resolved
ENV_FILEis.gz, decompression is done on-the-fly viapigz -dcpiped directly todd. Profile.conffiles always point to.img— resolution to.gzis transparent.- Generic Mode: If
ENV_FILEandENV_OFFSETare not defined in profile, installer automatically disables injection but continues installation.
# Complete wipe
dd if=/dev/zero | pv | dd of=/dev/mmcblkX bs=1M oflag=direct
# Partition creation (fdisk)
- MBR partition table
- P1: Bootable, Type 0xC (W95 FAT32 LBA), 512MB
- P2: Type 0x83 (Linux), remaining
# Formatting
mkfs.vfat -F 32 -n BOOT /dev/mmcblkXp1
mkfs.ext4 -F -q -L ROOTFS /dev/mmcblkXp2BOOT Partition:
rsync -rtHL --no-owner --no-group --no-perms /mnt/src_boot/ /mnt/tgt_boot/ROOTFS Partition:
rsync -aAXv --delete \
--exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} \
/mnt/src_root/ /mnt/tgt_root/# Decompressed asset (.img): direct injection
dd if=uboot_envs_device.img of=/dev/mmcblkX bs=512 seek=$ENV_OFFSET conv=notrunc
# Compressed asset (.img.gz): on-the-fly decompression via pigz
pigz -dc uboot_envs_device.img.gz | dd of=/dev/mmcblkX bs=512 seek=$ENV_OFFSET conv=notruncWrites variables directly to specified offset (usually sector 0). The installer automatically detects whether the asset is compressed and chooses the appropriate method.
- armbianEnv.txt: Updates
rootdev=UUID=xxxxwith new UUID- If file already exists: only updates root UUID
- If doesn't exist: creates from scratch and requests DTB selection
- fstab: Updates BOOT and ROOTFS entries with new UUIDs
- DTB Selection (only if armbianEnv.txt doesn't exist): Interactive menu to select correct Device Tree Blob for hardware
This section is intended for developers and advanced enthusiasts who want to add support for new devices. The process requires hardware knowledge and serial interface.
Unlike standard PCs, each TV Box model can have completely different bootloader architecture:
- HTV H8: Bootloader auto-regenerates variables after wipe → Method 1
- BTV E10 / ATV A5: Rigid bootloader, requires structure preservation → Method 2
- Your device: Could be any of the above cases
There is no silver bullet. There is diagnosis, testing, and adaptation. The methods below are reverse engineering tools, not fixed recipes.
-
Functional Linux ARM system running from USB/SD on target AMLogic device
- Can be Armbian, Debian, Ubuntu ARM, etc.
- Required to access internal eMMC and execute analysis/extraction commands
- System needs to boot correctly for shell access
-
TTL Serial Adapter (UART) of good quality (3.3V, NEVER 5V!)
-
Soldering skills to access TX/RX/GND on board
-
Serial terminal software (PuTTY, Minicom, picocom)
-
Patience and methodology
🔴 Attention: UART serial interface is mandatory for BOTH extraction methods presented in this section. There's no way to properly extract and configure U-Boot variables without serial bootloader access.
Typical Serial Configuration:
- Baud Rate: 115200 (Amlogic standard) or 1500000 (some models)
- Data Bits: 8
- Stop Bits: 1
- Parity: None
- Flow Control: None
# Example with picocom
picocom -b 115200 /dev/ttyUSB0
# If nothing appears, try alternative baud rate
picocom -b 1500000 /dev/ttyUSB0Before any experiment, make complete eMMC backup:
# Bit-by-bit backup with compression (saves space on USB)
sudo dd if=/dev/mmcblkX bs=1M status=progress | gzip -c > backup_emmc_full.img.gz
# To restore in case of disaster:
# gunzip -c backup_emmc_full.img.gz | sudo dd of=/dev/mmcblkX bs=1M status=progressWhy gzip? A 16GB backup becomes ~2-4GB compressed, saving much space.
This method works on devices where the factory bootloader (usually in SPI Flash or protected partitions) can recreate its environment variables at a favorable offset after total wipe.
After backup, completely destroy eMMC structure:
# Zero ENTIRE eMMC (no mercy)
sudo dd if=/dev/zero of=/dev/mmcblkX bs=1M status=progress conv=fsync- Power off the box from outlet
- Connect serial interface to TX/RX/GND pins
- Open serial terminal on PC (e.g.,
picocom -b 115200 /dev/ttyUSB0) - Power on box and repeatedly press Enter or Space
- You'll drop into U-Boot prompt (e.g.,
sc2_ah212=>or=>)
Execute the following commands one at a time in U-Boot prompt:
setenv start_autoscript 'if mmcinfo; then run start_mmc_autoscript; fi; if usb start; then run start_usb_autoscript; fi; run start_emmc_autoscript'
setenv start_emmc_autoscript 'if fatload mmc 1 1020000 emmc_autoscript; then setenv devtype "mmc"; setenv devnum 1; autoscr 1020000; fi;'
setenv start_mmc_autoscript 'if fatload mmc 0 1020000 s905_autoscript; then setenv devtype "mmc"; setenv devnum 0; autoscr 1020000; fi;'
setenv start_usb_autoscript 'for usbdev in 0 1 2 3; do if fatload usb ${usbdev} 1020000 s905_autoscript; then setenv devtype "usb"; setenv devnum 0; autoscr 1020000; fi; done'
setenv bootcmd 'run start_autoscript'
setenv upgrade_step 2
setenv bootdelay 1
Save and reboot:
saveenv
reset
💡 Important Tip: These variables configured above (
start_autoscript,start_emmc_autoscript, etc.) are highly recommended for both methods (Method 1 and Method 2). They ensure the bootloader searches for boot scripts on different media (eMMC, SD/USB) in correct order, allowing Armbian to start properly.
After reboot, intercept U-Boot again and verify:
printenv
Result analysis:
- ✅ Variables present? Board passed the test! Continue to Step 5.
- ❌ Variables disappeared? Bootloader doesn't regenerate reliably. Skip to Method 2 (Ampart).
Connect USB with Armbian and let boot proceed. After system starts:
Diagnostic Logic:
Since we formatted entire eMMC with zeros (0x00), any non-zero data is something U-Boot wrote when executing saveenv.
# Search for "bootcmd=" string in first 138MB
sudo hexdump -C -n 144703488 /dev/mmcblkX | grep -C 5 "bootcmd="Example output (HTV H8):
07400000 00 00 00 00 62 6f 6f 74 63 6d 64 3d 72 75 6e 20 |....bootcmd=run |
07400010 73 74 61 72 74 5f 61 75 74 6f 73 63 72 69 70 74 |start_autoscript|
Note first column: 07400000 (hexadecimal) = 116 MB in decimal.
skip to jump to identified offset.
Calculation based on example (HTV H8):
- Variables start offset: 116 MB (0x07400000 from hexdump)
- Size to extract: 8 MB (typical safe for U-Boot variables)
# Extract ONLY variables region (116MB to 116MB+8MB)
sudo dd if=/dev/mmcblkX of=uboot_envs_htv_h8.img bs=1M skip=116 count=8 status=progressParameter explanation:
skip=116: Skip first 116 MB (offset where variables start)count=8: Extract only 8 MB from this point- Result: 8 MB file containing exactly U-Boot variables
Note for profile:
1. Calculate ENV_OFFSET (in sectors):
# Formula: MB × 2048 = sectors
# Example HTV H8: 116 MB of variables
echo $((116 * 2048)) # Result: 237568 sectorsENV_OFFSET= 237568 sectors- Why? Installer uses
ddwithseek=$ENV_OFFSETto inject.imgfile at correct position on target eMMC - Conversion: 116 MB × 2048 = 237568 sectors (1 sector = 512 bytes)
- Why? Installer uses
2. Calculate LINUX_START_SECTOR:
📊 Conditional Rule:
# Base formula: offset_mb + header_size_mb + 4 (margin)
# If result < 128 MB → use 128 MB (safe minimum)
# If result ≥ 128 MB → use exact calculation
# Example HTV H8:
# offset_mb=116, header_size=8, margin=4
# Calculation: 116 + 8 + 4 = 128 MB
# Since 128 >= 128 → use 128 MB
echo $((128 * 2048)) # Result: 262144 sectorsConditional example (if calculation gives < 128 MB):
# Assuming offset_mb=50, header_size=8, margin=4
# Calculation: 50 + 8 + 4 = 62 MB
# Since 62 < 128 → use 128 MB (minimum standard)
echo $((128 * 2048)) # Result: 262144 sectorsConditional example (if calculation gives > 128 MB):
# Assuming offset_mb=120, header_size=10, margin=4
# Calculation: 120 + 10 + 4 = 134 MB
# Since 134 > 128 → use 134 MB (exact calculation)
echo $((134 * 2048)) # Result: 274432 sectorsLINUX_START_SECTOR= 262144 sectors (128 MB) → HTV H8 case- Why 128 MB minimum? Ensures sufficient space for bootloader structures and U-Boot variables
- 4 MB margin: Additional safety against fragmentation/alignment
- Logic:
max(128 MB, offset_mb + header_size + 4)
This method is necessary when device doesn't regenerate environment variables reliably after total wipe.
⚠️ Requirement: Like Method 1, this method also requires UART serial interface to intercept U-Boot and apply recommended variables from Step 3. The difference is in file extraction strategy.
The ampart tool is specific to Amlogic devices and doesn't come pre-installed:
# Clone repository
git clone https://github.com/7Ji/ampart.git
cd ampart
# Compile and install
make
sudo make install
# Verify installation
ampart --helpSource: 7Ji/ampart
If tried Method 1 and failed, restore original backup:
gunzip -c backup_emmc_full.img.gz | sudo dd of=/dev/mmcblkX bs=1M status=progressWith original system (or restored backup) running:
# Simulate partition table reorganization
sudo ampart /dev/mmcblkX --mode dclone data::-1:4Ampart will display an EPT (Extended Partition Table) table. Look for env and data lines:
Example output:
EPT report: 5 partitions in the table
0: bootloader 0 ( 0.00M) 400000 ( 4.00M)
1: reserved 400000 ( 4.00M) 4000000 ( 64.00M)
2: cache 4400000 ( 68.00M) 800000 ( 8.00M)
3: env 7400000 ( 116.00M) 800000 ( 8.00M)
4: data 8400000 ( 132.00M) 39ba00000 ( 14.43G)
Critical Interpretation:
| Partition | Offset | Size | Meaning |
|---|---|---|---|
bootloader |
0 MB | 4 MB | Primary bootloader |
reserved |
4 MB | 64 MB | Reserved area (DTB, etc.) |
cache |
68 MB | 8 MB | Cache (usually ignored) |
env |
116 MB | 8 MB | U-Boot Variables (CRITICAL!) |
data |
132 MB | remaining | Free space start |
Extraction Rule:
Extract from byte 0 to data partition start (132 MB in example).
# Extract exactly first 132 MB (per ampart report)
sudo dd if=/dev/mmcblkX of=uboot_envs_btv_e10.img bs=1M count=132 status=progressNote for profile:
1. Calculate ENV_OFFSET:
ENV_OFFSET= 0 (zero)- Why? In Method 2, we extract from byte 0 (including bootloader, reserved, cache, env)
- During installation,
ddinjects entire file from eMMC start - U-Boot variables are already at correct position inside extracted file
2. Calculate LINUX_START_SECTOR:
📊 Conditional Rule:
# Base formula: data_start_mb + 4 (margin)
# If result < 128 MB → use 128 MB (safe minimum)
# If result ≥ 128 MB → use exact calculation
# Example BTV E10:
# data_start=132 MB (from ampart report), margin=4
# Calculation: 132 + 4 = 136 MB
# Since 136 > 128 → use 136 MB (exact calculation)
echo $((136 * 2048)) # Result: 278528 sectorsConditional example (if calculation gives < 128 MB):
# Assuming data_start=100 MB, margin=4
# Calculation: 100 + 4 = 104 MB
# Since 104 < 128 → use 128 MB (minimum standard)
echo $((128 * 2048)) # Result: 262144 sectorsLINUX_START_SECTOR= 278528 sectors (136 MB) → BTV E10 case- Why 128 MB minimum? Ensures sufficient space for preserved Android/Amlogic structures
- Logic:
max(128 MB, data_start_mb + 4) - Conversion: 136 MB × 2048 = 278528 sectors
To ensure correct capture:
# Check if "bootcmd" exists in extracted file
strings uboot_envs_btv_e10.img | grep -i "bootcmd"If you find strings like bootcmd=, start_autoscript, etc., extraction was successful!
💡 Important Recommendation: Before finalizing extraction, it's highly recommended to access U-Boot via serial UART and configure variables from Step 3: Variable Configuration (Method 1 section). After applying these variables (
setenv start_autoscript,saveenv, etc.), extract again withddto ensure.imgfile contains optimized boot configurations. This ensures better compatibility and boot on different media (SD/USB/eMMC).
| Aspect | Method 1 (Wipe & Regen) | Method 2 (Ampart) |
|---|---|---|
| Complexity | Medium | High |
| Resulting File | Clean (only zeros + env) | Dirty (Android remnants) |
| Typical Size | 32-64 MB | 132 MB |
| Requires Serial UART | ✅ Mandatory | ✅ Mandatory |
| Example | HTV H8 | BTV E10, ATV A5 |
⚠️ Important: Both methods require UART serial interface to intercept U-Boot and configure boot variables. The difference is in variable file extraction strategy.
This section is critical for correctly configuring ENV_OFFSET and LINUX_START_SECTOR values in device profiles.
- 1 sector = 512 bytes
- 1 MB = 1024 × 1024 bytes = 1048576 bytes
- 1 MB = 2048 sectors (simplified formula: MB × 2048)
1. Hexadecimal (hexdump) → Decimal (bytes):
# Example: 0x07400000 from hexdump
echo $((0x07400000)) # Result: 121634816 bytes2. Bytes → Megabytes:
# Divide by 1024 twice (or 1048576)
echo $((121634816 / 1024 / 1024)) # Result: 116 MB3. Megabytes → Sectors (MOST IMPORTANT!):
# Simplified formula: MB × 2048
echo $((116 * 2048)) # Result: 237568 sectors
# Complete formula (MB × 1024 × 1024 / 512):
echo $((116 * 1024 * 1024 / 512)) # Result: 237568 sectors4. Sectors → Megabytes (reverse verification):
# Divide by 2048
echo $((237568 / 2048)) # Result: 116 MBExample 1: HTV H8 (Method 1)
# Hexdump shows: 07400000
# Step 1: Hex → Decimal
echo $((0x07400000)) # = 121634816 bytes
# Step 2: Bytes → MB
echo $((121634816 / 1024 / 1024)) # = 116 MB
# Step 3: MB → Sectors (ENV_OFFSET)
echo $((116 * 2048)) # = 237568 sectors ✅
# Step 4: LINUX_START_SECTOR (116 + 8 extracted + 4 margin = 128 MB)
echo $((128 * 2048)) # = 262144 sectors ✅Result:
ENV_OFFSET=237568LINUX_START_SECTOR=262144
Example 2: BTV E10 (Method 2 - Ampart)
# Ampart report shows 'data' partition at 132 MB
# ENV_OFFSET = 0 (we extract from beginning)
# LINUX_START_SECTOR: data (132 MB) + margin (4 MB) = 136 MB
echo $((136 * 2048)) # = 278528 sectors ✅Result:
ENV_OFFSET=0LINUX_START_SECTOR=278528
Save this alias in your ~/.bashrc for quick conversion:
# Add to ~/.bashrc
alias mb2sec='echo "MB → Sectors Conversion:"; read -p "Enter MB: " mb; echo "$((mb * 2048)) sectors"'
alias hex2mb='echo "Hex → MB Conversion:"; read -p "Enter hex (e.g., 0x07400000): " hex; echo "$((hex / 1024 / 1024)) MB"'
# Reload bashrc
source ~/.bashrc
# Usage:
mb2sec # Enter 116 → Result: 237568 sectors
hex2mb # Enter 0x07400000 → Result: 116 MBThis is the most important rule to ensure device boots correctly:
# Rule: LINUX_START_SECTOR = max(128 MB, base_calculation)
# Where base_calculation varies by method:
# Method 1: offset_mb + header_size_mb + 4
# Method 2: data_start_mb + 4
# Examples:
# If base_calculation = 62 MB → use 128 MB (262144 sectors)
# If base_calculation = 128 MB → use 128 MB (262144 sectors)
# If base_calculation = 136 MB → use 136 MB (278528 sectors)Why is 128 MB the absolute minimum?
- Ensures sufficient space for bootloader, reserved partitions, and U-Boot variables
- Avoids conflicts with residual structures from original Android system
- Provides safety margin against fragmentation and sector misalignment
- Compatibility with most AMLogic S905X/X2/X3/X4 devices
After extracting variables using one of the methods above:
Copy and compress extracted .img file to assets directory:
# Copy file to assets directory
cp uboot_envs_mydevice.img armbian-install-amlogic/assets/
# Compress with maximum compression (IMPORTANT for Git)
gzip -9 armbian-install-amlogic/assets/uboot_envs_mydevice.imgWhy compress?
.img files exceed GitHub's 100MB limit. Gzip compression drastically reduces size (typically >90%), allowing Git versioning. Users decompress before installing (see Initial Preparation section).
Result: You'll have uboot_envs_mydevice.img.gz ready for commit.
Create new configuration file in armbian-install-amlogic/profiles/:
Scenario: Hexdump showed variables at 0x07400000, we extracted 8 MB.
Calculations:
# ENV_OFFSET: convert hex offset to sectors
echo $((0x07400000 / 1024 / 1024)) # = 116 MB
echo $((116 * 2048)) # = 237568 sectors ✅
# LINUX_START_SECTOR: apply conditional rule
# Base: offset + extracted_size + margin = 116 + 8 + 4 = 128 MB
# Rule: if < 128 MB → use 128 MB, else use calculation
# Since 128 >= 128 → use 128 MB
echo $((128 * 2048)) # = 262144 sectors ✅File: armbian-install-amlogic/profiles/mydevice_method1.conf
BOARD_NAME="My Device Method1 (S905X4)"
AUTHOR="Your Name"
ENV_OFFSET=237568
ENV_FILE="/etc/armbian-install-amlogic/assets/uboot_envs_mydevice.img"
LINUX_START_SECTOR=262144
⚠️ Important: The same applies here —ENV_FILEpoints to.img, regardless of whether the asset is compressed on disk. Resolution to.img.gzis handled internally by the installer.
Scenario: Ampart showed data partition starting at 132 MB, we extracted from byte 0.
Calculations:
# ENV_OFFSET: Method 2 always uses 0 (extraction from start)
# ENV_OFFSET = 0 ✅
# LINUX_START_SECTOR: apply conditional rule
# Base: data_start + margin = 132 + 4 = 136 MB
# Rule: if < 128 MB → use 128 MB, else use calculation
# Since 136 > 128 → use 136 MB (exact calculation)
echo $((136 * 2048)) # = 278528 sectors ✅File: armbian-install-amlogic/profiles/mydevice_method2.conf
BOARD_NAME="My Device Method2 (S905X3)"
AUTHOR="Your Name"
ENV_OFFSET=0
ENV_FILE="/etc/armbian-install-amlogic/assets/uboot_envs_mydevice.img"
LINUX_START_SECTOR=278528
⚠️ Important: The same applies here —ENV_FILEpoints to.img, regardless of whether the asset is compressed on disk. Resolution to.img.gzis handled internally by the installer.
Before saving profile, validate:
# 1. ENV_OFFSET must be integer number of sectors
# 2. LINUX_START_SECTOR must be greater than ENV_OFFSET (if ENV_OFFSET != 0)
# 3. LINUX_START_SECTOR minimum: 262144 (128 MB) - never less!
# 4. LINUX_START_SECTOR typical: 262144 (128 MB) or 278528 (136 MB)
# Verify conversion is correct (example 116 MB):
echo $((116 * 2048)) # Should return 237568
echo $((237568 / 2048)) # Should return 116 (reverse check)
# Validate conditional rule:
# If your calculation gave < 128 MB, ALWAYS use 128 MB (262144 sectors)- Partitions overwriting U-Boot variables → Device won't boot
- Incorrect offsets → Bootloader can't find variables → Black screen
- LINUX_START_SECTOR < 128 MB → Insufficient space → Guaranteed failure
With the new profile and asset in the repository, use the installer to inject into the running system or image:
Via installer (recommended):
# On running Armbian system (USB/SD)
sudo ./install-to-system.sh
# On a .img image
sudo ./install-to-image.sh /path/to/Armbian.imgThe installer will present the new profile in the selection menu with the BOARD_NAME defined in the .conf.
Manually (if you prefer not to use the installer): see the Manual Installation section.
Run installer and verify new profile appears in selection list:
sudo armbian-install-amlogicIf everything is correct, device name (BOARD_NAME) will appear in selection menu.
⚡ Mandatory Real Test: Profile appearing in menu is not enough! Execute complete installation to eMMC and verify device actually boots correctly. Test:
- Successful eMMC boot
- Correct hardware detection
- Connectivity (Ethernet/Wi-Fi)
- General system functionality
Only consider profile functional after successful real boot!
If profile works perfectly, contribute to the project! See the Contribution Guide for detailed instructions on how to submit new device profiles.
All logs are written to: /tmp/armbian-install-amlogic.log
Includes:
- Hardware detection
- Partition state
- Executed commands
- Exit codes
- Detailed error messages
For debugging, run script and check log after any failure.
eMMC memories are slower than SSDs. Kernel takes time to create device files (/dev/mmcblkXp1) after partitioning operations. Installer implements active waiting:
partprobe /dev/mmcblkX # Force table re-read
udevadm settle # Wait for udev stabilization
sleep 2 # Additional marginOn very slow devices, increase sleep to 5 seconds.
Many TV Box eMMCs don't properly support TRIM. Using discard flags in mount or mkfs can cause:
- I/O errors during formatting
- Silent data corruption
- Degraded performance
Installer doesn't use discard by default for maximum compatibility.
# Buffered (faster, but may not write immediately)
dd if=file.img of=/dev/mmcblkX bs=1M
# Direct (slower, but guarantees physical write)
dd if=file.img of=/dev/mmcblkX bs=1M oflag=direct conv=fsyncInstaller uses oflag=direct on wipe to ensure zeros are actually written to eMMC, not just cache.
Always validate if extracted variable file contains relevant data:
# Check size
ls -lh uboot_envs_device.img
# Search for recognizable strings
strings uboot_envs_device.img | grep -E "bootcmd|bootdelay|start_autoscript"
# View in hex (first 512 bytes)
hexdump -C uboot_envs_device.img | head -32If file is empty or full of zeros, extraction failed.
Cause: Incorrect U-Boot variables, wrong DTB, or inadequate partition offset.
Solution:
- Verify you selected correct device profile
- Confirm correct DTB for your SoC:
- S905X:
meson-gxl-s905x-*.dtb - S905X2:
meson-g12a-s905x2-*.dtb - S905X3:
meson-sm1-s905x3-*.dtb
- S905X:
- New device without profile? Follow U-Boot Variables Extraction section to create custom profile
Cause: U-Boot variables not injected correctly or .img file is corrupted.
Solution:
- Verify
ENV_FILEexists at path specified in profile - Validate extracted file content:
strings /etc/armbian-install-amlogic/assets/uboot_envs_device.img | grep -i "bootcmd"
- If empty or without relevant data, redo extraction via Method 1 or 2
Cause: Partitions not created correctly or race condition (Kernel hasn't created /dev/mmcblkXp1 yet).
Solution:
- Check log in
/tmp/armbian-install-amlogic.log - Installer already has race condition protections:
partprobe /dev/mmcblkX udevadm settle sleep 2
- On very slow eMMCs, may need to increase
sleep
Cause: Bootloader lacks permission or space to write to eMMC, or environment region is corrupted.
Symptoms:
- Executes
saveenvwithout errors - After
resetandprintenv, variables disappeared
Solution:
-
Try unlocking write:
mmc dev 1 mmc infoCheck if device is write-protected
-
Use Method 2 (Ampart): Device probably doesn't regenerate variables reliably. Restore backup and follow Ampart method to preserve original structure.
Cause: U-Boot still configured for SD/USB boot.
Solution:
- Run installation again
- On locked devices, ensure using profile (not generic)
This is an independent project, developed from scratch with its own objectives and architecture.
Developed for TVBox Project at Federal Institute of São Paulo (IFSP), Salto Campus.
The TVBox Project is a social impact initiative that transforms TV Boxes seized by Federal Revenue Service into mini PCs with Linux, promoting:
- Sustainability through hardware reuse
- Digital inclusion in underserved communities
- Technical training for students
- E-waste reduction
During development, the following projects were studied as technical reference:
- Studied for reference: ophub/amlogic-s9xxx-armbian
- Conceptual inspiration: unifreq/openwrt_packit
- Tool used (ampart): 7Ji/ampart
- Pedro Rigolin - Lead developer and project maintainer
This project thanks all who contributed with code, documentation, tests, and feedback:
See the complete list of contributors at: Contributors
All contributions are welcome! To learn how to contribute to the project, see our Contribution Guide.
Ways to contribute:
- 🆕 Add support for new devices (profiles and assets)
- 🐛 Report bugs and issues found
- 📝 Improve documentation (fixes, translations, examples)
- 💻 Contribute code (features, fixes, improvements)
👉 Read the complete contribution guide »
This project is licensed under the MIT License.
MIT License
Copyright (c) 2026 Pedro Rigolin
Developed for Projeto TVBox - Instituto Federal de São Paulo (IFSP), Campus Salto
See LICENSE file for more details.
MIT license allows free use (including commercial), modification and distribution, as long as original credits are maintained.
This installer modifies device eMMC memory. Incorrect operations may result in:
- Total data loss
- Unbootable device ("brick")
- Warranty void
Always backup important data before using this installer.
Compatibility: This installer was developed and tested specifically for Armbian. Use with other Linux distributions has not been tested and may result in boot failures or system issues.
The author is not responsible for hardware damage or data loss.