Initial commit: boot, wifi and ssh work
Signed-off-by: Maurizio Porrato <maurizio.porrato@gmail.com>
|
|
@ -0,0 +1,6 @@
|
||||||
|
*.img
|
||||||
|
!config/
|
||||||
|
config/*
|
||||||
|
!config/etc/
|
||||||
|
config/etc/*
|
||||||
|
!config/etc/motd
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
.PHONY: sdcard images clean
|
||||||
|
|
||||||
|
A=./artifacts
|
||||||
|
R=./resources
|
||||||
|
S=./scripts
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Tunable parameters are in this section
|
||||||
|
ALPINE_VERSION?=latest
|
||||||
|
FACTORY_IMAGE?=factory.img
|
||||||
|
SD_SIZE?=250M
|
||||||
|
RESOURCES_SIZE?=8M
|
||||||
|
ROOTFS_SIZE?=100M
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
SPL=$(A)/spl.img
|
||||||
|
UBOOT=$(A)/u-boot.img
|
||||||
|
ENV=$(A)/env.img
|
||||||
|
RESOURCES=$(A)/boot-resources.img
|
||||||
|
BOOT=$(A)/boot.img
|
||||||
|
BOOTCFG=$(A)/bootimg.cfg
|
||||||
|
KERNEL=$(A)/zImage
|
||||||
|
INITRD=$(A)/initramfs
|
||||||
|
FIRMWARE_TAR=$(A)/firmware.tar
|
||||||
|
MODULES_TAR=$(A)/modules.tar
|
||||||
|
ROOTFS_TAR=$(A)/rootfs.tar
|
||||||
|
ROOTFS=$(A)/rootfs.img
|
||||||
|
IMAGES=$(SPL) $(UBOOT) $(ENV) $(RESOURCES) $(BOOT) $(ROOTFS)
|
||||||
|
SD=$(A)/alpine-h700.img
|
||||||
|
|
||||||
|
sdcard: $(SD)
|
||||||
|
|
||||||
|
images: $(IMAGES)
|
||||||
|
|
||||||
|
$(SD): $(IMAGES)
|
||||||
|
$(RM) $@
|
||||||
|
truncate -s $(SD_SIZE) $@
|
||||||
|
$(S)/mkpart.sh $@ $^
|
||||||
|
|
||||||
|
$(SPL) $(UBOOT): $(FACTORY_IMAGE)
|
||||||
|
$(S)/extract-blobs.py $^ -o $(A)
|
||||||
|
|
||||||
|
$(ENV): env.txt
|
||||||
|
$(S)/mkenv.py $^ $@
|
||||||
|
|
||||||
|
$(BOOT): $(BOOTCFG) $(KERNEL) $(INITRD)
|
||||||
|
abootimg --create $@ -f $(BOOTCFG) -k $(KERNEL) -r $(INITRD)
|
||||||
|
|
||||||
|
$(KERNEL) $(BOOTCFG): $(FACTORY_IMAGE)
|
||||||
|
$(S)/extract-kernel.sh $^ $(A)
|
||||||
|
|
||||||
|
$(INITRD):
|
||||||
|
$(S)/mkinitrd.sh $(ALPINE_VERSION)
|
||||||
|
|
||||||
|
$(RESOURCES): $(shell find $(R) -type f -print0 | xargs -0)
|
||||||
|
$(RM) $@
|
||||||
|
truncate -s $(RESOURCES_SIZE) $@
|
||||||
|
$(S)/mkfsimage.sh $@ 0 vfat resources $(R)
|
||||||
|
|
||||||
|
$(ROOTFS_TAR):
|
||||||
|
$(S)/build-rootfs.sh $(ALPINE_VERSION) $(A)
|
||||||
|
|
||||||
|
$(FIRMWARE_TAR) $(MODULES_TAR): $(FACTORY_IMAGE)
|
||||||
|
$(S)/extract-modules.sh $< $(A)
|
||||||
|
|
||||||
|
$(ROOTFS): $(ROOTFS_TAR) $(FIRMWARE_TAR) $(MODULES_TAR)
|
||||||
|
$(RM) $@
|
||||||
|
truncate -s $(ROOTFS_SIZE) $@
|
||||||
|
$(S)/mkfsimage.sh $@ 0 ext4 rootfs $(ROOTFS_TAR) $(FIRMWARE_TAR):/lib/firmware/ $(MODULES_TAR):/lib/modules/ config
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(A)/*
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
# Alpine Linux for the Allwinner H700 SoC
|
||||||
|
|
||||||
|
This repository contains a collection of scripts to create a custom Alpine
|
||||||
|
Linux based SD card image bootable on Allwinner H700 based devices.
|
||||||
|
|
||||||
|
In the standard configuration, a very basic system is installed, providing
|
||||||
|
a login prompt on `/dev/ttyS0`, automatic connection to a WiFi netowk on boot
|
||||||
|
and an SSH daemon running.
|
||||||
|
|
||||||
|
The scripts have been tested on a Fedora Linux 40 system and the generated
|
||||||
|
image has been tested on an Anbernic RG35XX Plus portable console.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
The scripts require the following software:
|
||||||
|
|
||||||
|
- `make` (specifically, GNU Make) to orchestrate the build and track dependencies
|
||||||
|
- `python3` to run some of the provided scripts; only modules from the standard
|
||||||
|
library are used
|
||||||
|
- `sgdisk` to manipulate GPT partition tables
|
||||||
|
- `guestfish` to manipulate filesystem images without root privileges
|
||||||
|
- `podman` to provide an Alpine Linux environment
|
||||||
|
- `qemu-user-static-aarch64` to enable `podman` to run aarch64 container
|
||||||
|
images on a different architecture like x86_64
|
||||||
|
|
||||||
|
An image of a stock SD card is required in order to extract components that are
|
||||||
|
specific to the H700 SoC that do not have open source alternatives yet; those
|
||||||
|
components are:
|
||||||
|
|
||||||
|
- the SPL
|
||||||
|
- the U-Boot bootloader
|
||||||
|
- the kernel
|
||||||
|
- the kernel's modules
|
||||||
|
- various firmware blobs
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Some extra configuration must be provided to connect to a WiFi network and
|
||||||
|
allow SSH connections.
|
||||||
|
|
||||||
|
Anything under the `config` directory will be injected in the rootfs image.
|
||||||
|
|
||||||
|
A good staring point would be something like this (replace `$ssid` and
|
||||||
|
`$password` with the correct network name and password for your WiFi network):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir -p config/etc/wpa_supplicant
|
||||||
|
wpa_passphrase '$ssid' '$password' >config/etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
|
||||||
|
mkdir -p config/root/.ssh
|
||||||
|
cat ~/.ssh/id_*.pub >config/root/.ssh/authorized_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stock SD card image
|
||||||
|
|
||||||
|
The scripts expect to find an image of the stock SD card in a file called
|
||||||
|
`factory.img` in the root of the repository. It can be either an image file or
|
||||||
|
a link to the actual image file or device, as long as the user running the
|
||||||
|
scripts has permission to read it. The name of the image can be overridden by
|
||||||
|
specifying a different path in the `FACTORY_IMAGE` variable when calling the
|
||||||
|
makefile.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To build an image, just run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, to use a path to the stock image other than the default:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
make FACTORY_IMAGE=/tmp/RG35XX+-P-V1.1.3-EN16GB-240614.IMG
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting image will be saved to `./artifacts/alpine-h700.img` and can be
|
||||||
|
flashed to an SD card, for example, if the card is presented to the system as
|
||||||
|
`/dev/sde`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
dd if=artifacts/alpine-h700.img of=/dev/sde bs=1M oflag=dsync status=progress
|
||||||
|
```
|
||||||
|
|
||||||
|
There are other tunable settings: for an exaustive list, see the top of
|
||||||
|
`Makefile`. Keep in mind that tweaking those values between builds may require
|
||||||
|
forcing a clean build by issuing a `make clean`.
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org/>
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
Welcome to Alpine!
|
||||||
|
|
||||||
|
This is an unofficial port to the Allwinner H700 SoC: please report
|
||||||
|
issues to https://github.com/mporrato/alpine-h700 .
|
||||||
|
|
||||||
|
The Alpine Wiki contains a large amount of how-to guides and general
|
||||||
|
information about administrating Alpine systems.
|
||||||
|
See <https://wiki.alpinelinux.org/>.
|
||||||
|
|
||||||
|
You may change this message by editing /etc/motd.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
earlyprintk=sunxi-uart,0x05000000
|
||||||
|
initcall_debug=0
|
||||||
|
console=ttyS0,115200
|
||||||
|
rootfstype=ext4
|
||||||
|
nand_root=/dev/nand0p4
|
||||||
|
mmc_root=/dev/mmcblk0p4
|
||||||
|
init=/sbin/init
|
||||||
|
loglevel=4
|
||||||
|
selinux=0
|
||||||
|
cma=64M
|
||||||
|
mac=
|
||||||
|
wifi_mac=
|
||||||
|
bt_mac=
|
||||||
|
specialstr=
|
||||||
|
keybox_list=hdcpkey,widevine
|
||||||
|
setargs_nand=setenv bootargs earlyprintk=${earlyprintk} initcall_debug=${initcall_debug} console=${console} loglevel=${loglevel} rootfstype=${rootfstype} root=${nand_root} init=${init} partitions=${partitions} cma=${cma} snum=${snum} mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac} selinux=${selinux} specialstr=${specialstr} gpt=1
|
||||||
|
setargs_mmc=setenv bootargs earlyprintk=${earlyprintk} initcall_debug=${initcall_debug} console=${console} loglevel=${loglevel} rootfstype=${rootfstype} root=${mmc_root} init=${init} partitions=${partitions} cma=${cma} snum=${snum} mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac} selinux=${selinux} specialstr=${specialstr} gpt=1
|
||||||
|
boot_normal=sunxi_flash read 45000000 boot;bootm 45000000
|
||||||
|
boot_recovery=sunxi_flash read 45000000 recovery;bootm 45000000
|
||||||
|
boot_fastboot=fastboot
|
||||||
|
recovery_key_value_max=0x13
|
||||||
|
recovery_key_value_min=0x10
|
||||||
|
fastboot_key_value_max=0x8
|
||||||
|
fastboot_key_value_min=0x2
|
||||||
|
bootdelay=0
|
||||||
|
bootcmd=run setargs_nand boot_normal
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
features="base"
|
||||||
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 58 B |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 337 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 900 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
a1sp9maKde37ee6c-6dc4-4d74-86f0-db32116efb53e0e40ccf-7a66-406b-88c3-415b4a62a8f7777622ab-6bd0-464f-9da5-4cc203e855ea8ce5671f-e8b5-442e-9300-2ee6836c538aabf5f481-c961-4895-8245-631f74851d0c2bbb4229-55a8-4929-a165-3f406f0ee441ab5d09a9-c4dc-44bb-a175-cfb7c978a062329ea51e-1ddc-44ff-ac09-9ef7b64e0c52a712e47d-13f7-4490-9fea-bdcd587b8a4a5ed4d4e6-0ba3-45c5-a778-3232a42d4d960a9b7466-d7b3-4087-b8ff-c51763b852a50cd78bb6-a6d5-43a8-8661-fb91abd346433e8a86ee-711e-49c1-ad54-b59dd01fe513e22b0d8b-647f-4417-a115-9806c5d64eec
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# This script runs inside an aarch64 alpine linux container and creates a
|
||||||
|
# base rootfs tarball with wifi support and an ssh daemon active at boot.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
target="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$target"' 0
|
||||||
|
|
||||||
|
apk update
|
||||||
|
apk -X "$(awk '/\/alpine\/[^\/]+\/main$/{print;exit}' /etc/apk/repositories)" \
|
||||||
|
--keys-dir /etc/apk/keys -U -p "$target/" --initdb \
|
||||||
|
add alpine-base alpine-release ca-certificates wpa_supplicant dropbear
|
||||||
|
cp /etc/apk/repositories "$target/etc/apk/"
|
||||||
|
echo "nameserver 8.8.8.8" >"$target/etc/resolv.conf"
|
||||||
|
sed -Ei 's/^(tty[0-9]+:)/#\1/;s/^#ttyS0:/ttyS0:/' "$target/etc/inittab"
|
||||||
|
echo h700 >"$target/etc/hostname"
|
||||||
|
echo 8821cs >"$target/etc/modules"
|
||||||
|
cat >"$target/etc/network/interfaces" <<__EOF__
|
||||||
|
auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
auto wlan0
|
||||||
|
iface wlan0 inet dhcp
|
||||||
|
__EOF__
|
||||||
|
for svc in devfs dmesg mdev ; do
|
||||||
|
chroot "$target" rc-update add "$svc" sysinit
|
||||||
|
done
|
||||||
|
for svc in hwclock modules sysctl hostname bootmisc syslog wpa_supplicant networking ; do
|
||||||
|
chroot "$target" rc-update add "$svc" boot
|
||||||
|
done
|
||||||
|
for svc in mount-ro killprocs savecache ; do
|
||||||
|
chroot "$target" rc-update add "$svc" shutdown
|
||||||
|
done
|
||||||
|
chroot "$target" rc-update add dropbear default
|
||||||
|
|
||||||
|
tar cf "${1:-/tmp/rootfs.tar}" -C "$target" .
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
podman run --arch=aarch64 --security-opt=label=disable \
|
||||||
|
-v "${2:-./artifacts}:/artifacts" \
|
||||||
|
-v ./scripts/_build.sh:/usr/local/bin/_build.sh \
|
||||||
|
--rm "docker.io/library/alpine:${1:-latest}" \
|
||||||
|
sh /usr/local/bin/_build.sh /artifacts/rootfs.tar
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Extract SPL and U-Boot images from an Allwinner boot image
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import mmap
|
||||||
|
from pathlib import Path
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
SPL_SIGNATURE = b"eGON.BT0"
|
||||||
|
# The SPL can be located at different locations depending on the SoC type
|
||||||
|
SPL_OFFSETS = [8 * 1024, 128 * 1024, 256 * 1024]
|
||||||
|
SPL_FILENAME = "spl.img"
|
||||||
|
|
||||||
|
UBOOT_SIGNATURE = b"sunxi-package"
|
||||||
|
UBOOT_OFFSET = 16400 * 1024
|
||||||
|
UBOOT_FILENAME = "u-boot.img"
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidImageError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def extract_blobs(image: Path, output_dir: Path = Path(), verbose: bool = True):
|
||||||
|
with image.open("rb") as f:
|
||||||
|
# The first partition starts at 36MB: map all space before that into memory
|
||||||
|
mm = mmap.mmap(f.fileno(), 36 * 1024**2, prot=mmap.PROT_READ)
|
||||||
|
spl_offset = spl_size = None
|
||||||
|
for offset in SPL_OFFSETS:
|
||||||
|
sig_offset = offset + 4
|
||||||
|
if mm[sig_offset : sig_offset + len(SPL_SIGNATURE)] == SPL_SIGNATURE:
|
||||||
|
spl_offset = offset
|
||||||
|
(spl_size,) = struct.unpack("<I", mm[offset + 16 : offset + 16 + 4])
|
||||||
|
break
|
||||||
|
if spl_offset is None:
|
||||||
|
raise InvalidImageError("Can't find SPL")
|
||||||
|
if verbose:
|
||||||
|
print(
|
||||||
|
f"Found SPL at offset {spl_offset / 1024}KiB, size {spl_size / 1024}KiB"
|
||||||
|
)
|
||||||
|
if mm[UBOOT_OFFSET : UBOOT_OFFSET + len(UBOOT_SIGNATURE)] != UBOOT_SIGNATURE:
|
||||||
|
raise InvalidImageError("Can't find U-Boot")
|
||||||
|
(uboot_size,) = struct.unpack(
|
||||||
|
"<I", mm[UBOOT_OFFSET + 36 : UBOOT_OFFSET + 36 + 4]
|
||||||
|
)
|
||||||
|
if verbose:
|
||||||
|
print(
|
||||||
|
f"Found U-Boot at offset {UBOOT_OFFSET / 1024}KiB, size {uboot_size / 1024}KiB"
|
||||||
|
)
|
||||||
|
if not output_dir.exists():
|
||||||
|
output_dir.mkdir(mode=0o755, parents=True)
|
||||||
|
spl_image = output_dir / SPL_FILENAME
|
||||||
|
if verbose:
|
||||||
|
print(f"Writing SPL image to {spl_image}")
|
||||||
|
spl_image.write_bytes(mm[spl_offset : spl_offset + spl_size])
|
||||||
|
uboot_image = output_dir / UBOOT_FILENAME
|
||||||
|
if verbose:
|
||||||
|
print(f"Writing U-Boot image to {uboot_image}")
|
||||||
|
uboot_image.write_bytes(mm[UBOOT_OFFSET : UBOOT_OFFSET + uboot_size])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Extract Allwinner H700 binary blobs from SD card images"
|
||||||
|
)
|
||||||
|
parser.add_argument("image", type=Path, help="source image or device")
|
||||||
|
parser.add_argument(
|
||||||
|
"--output", "-o", type=Path, default=Path(), help="output directory"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--verbose", "-v", action="store_true", help="show what's being done"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
extract_blobs(args.image, args.output, args.verbose)
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
sys.stderr.write(f"{e}\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Extract the kernel and boot image configuration from the given
|
||||||
|
# android boot image.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
image="$1"
|
||||||
|
outdir="${2:-./artifacts}"
|
||||||
|
|
||||||
|
boot_part="$(sgdisk -p "$image" | awk '$7=="boot"{print $2 " " $3-$2+1;exit}')"
|
||||||
|
read -r -a boot <<<"$boot_part"
|
||||||
|
|
||||||
|
block_shift="$(factor -h "${boot[@]}" | grep -Eo "2\^[0-9]+" | sed 's/^2\^//' | sort -n | head -n1)"
|
||||||
|
block_size="$((2 ** block_shift))"
|
||||||
|
start_blocks="$((boot[0] / block_size))"
|
||||||
|
size_blocks="$((boot[1] / block_size))"
|
||||||
|
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmp"' 0
|
||||||
|
|
||||||
|
dd if="$image" of="$tmp/boot.img" bs="$((512 * block_size))" skip="$start_blocks" count="$size_blocks" conv=sparse status=none
|
||||||
|
abootimg -x "$tmp/boot.img" "$outdir/bootimg.cfg" "$outdir/zImage" /dev/null /dev/null
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Extracts kernel modules and firmware blobs from the given
|
||||||
|
# rootfs image.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# -lt 2 ]] ; then
|
||||||
|
echo "Syntax: $0 IMAGE OUTDIR [PARTNO]"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
image="$1"
|
||||||
|
outdir="$2"
|
||||||
|
partno="${3:-5}"
|
||||||
|
|
||||||
|
device="/dev/sda$partno"
|
||||||
|
|
||||||
|
guestfish --ro --format=raw -a "$image" <<__EOF__
|
||||||
|
run
|
||||||
|
mount "$device" /
|
||||||
|
tar-out /lib/modules "$outdir/modules.tar"
|
||||||
|
tar-out /lib/firmware "$outdir/firmware.tar"
|
||||||
|
__EOF__
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Create a U-Boot environment image from a text environment file
|
||||||
|
|
||||||
|
This is required because the Anbernic environment format is not compatible
|
||||||
|
with the binary format produced by the mkenvimage tool from the uboot-tools
|
||||||
|
package
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
|
||||||
|
ENCODING = "utf-8"
|
||||||
|
DEFAULT_IMG_SIZE = 128 * 1024
|
||||||
|
DEFAULT_IMG_FLAGS = 0
|
||||||
|
|
||||||
|
|
||||||
|
class EnvError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def makebinenv(infile, outfile, size, flags):
|
||||||
|
"""
|
||||||
|
Create a U-Boot environment image from a text environment file
|
||||||
|
"""
|
||||||
|
|
||||||
|
buf = b""
|
||||||
|
for line in infile:
|
||||||
|
clean_line = line.strip()
|
||||||
|
if clean_line and not clean_line.startswith("#"):
|
||||||
|
buf += bytes(clean_line, ENCODING) + b"\0"
|
||||||
|
infile.close()
|
||||||
|
buf += b"\0"
|
||||||
|
if flags is not None:
|
||||||
|
buf = bytes([flags]) + buf
|
||||||
|
envsize = 4 + len(buf)
|
||||||
|
if envsize > size:
|
||||||
|
raise EnvError(f"Insufficient environment space: need at least {envsize} bytes")
|
||||||
|
buf += bytes(size - envsize)
|
||||||
|
crc = zlib.crc32(buf, 0)
|
||||||
|
buf = struct.pack("<I", crc) + buf
|
||||||
|
outfile.write(buf)
|
||||||
|
outfile.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="mkenv.py",
|
||||||
|
description=(
|
||||||
|
"Create an Anbernic U-Boot environment image from a text environment file"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"textfile",
|
||||||
|
type=argparse.FileType("r", encoding=ENCODING),
|
||||||
|
help="input text environment file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"binfile",
|
||||||
|
type=argparse.FileType("wb"),
|
||||||
|
help="output binary environment image file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--size",
|
||||||
|
type=int,
|
||||||
|
default=DEFAULT_IMG_SIZE,
|
||||||
|
help=(f"size of the output binary image in bytes (default={DEFAULT_IMG_SIZE})"),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--flags",
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
help=f"binary image flags (default={DEFAULT_IMG_FLAGS})",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
makebinenv(args.textfile, args.binfile, args.size, args.flags)
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
sys.stderr.write(f"{e}\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Create a new filesystem and populate it with the specified files.
|
||||||
|
# Automatically extracts tarballs.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# -lt 5 ]] ; then
|
||||||
|
echo "Syntax: $0 IMAGE PART# FSTYPE LABEL SOURCE [...]"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
image="$1" ; shift
|
||||||
|
partition="$1" ; shift
|
||||||
|
fstype="$1" ; shift
|
||||||
|
label="$1" ; shift
|
||||||
|
|
||||||
|
device="/dev/sda"
|
||||||
|
[[ $partition -ne 0 ]] && device="$device$partition"
|
||||||
|
|
||||||
|
script=(
|
||||||
|
"run"
|
||||||
|
"mkfs $fstype $device label:$label"
|
||||||
|
"mount $device /"
|
||||||
|
)
|
||||||
|
|
||||||
|
while [ $# -gt 0 ] ; do
|
||||||
|
src="$1"
|
||||||
|
if [[ "$src" =~ .+:.+ ]] ; then
|
||||||
|
dest="${src##*:}"
|
||||||
|
src="${src%%:*}"
|
||||||
|
script+=("mkdir-p \"$dest\"")
|
||||||
|
else
|
||||||
|
dest="/"
|
||||||
|
fi
|
||||||
|
if [ -d "$src" ] ; then
|
||||||
|
for item in "$src"/* ; do
|
||||||
|
cmd="copy-in \"$item\" \"$dest\""
|
||||||
|
script+=("$cmd")
|
||||||
|
done
|
||||||
|
else
|
||||||
|
case "$src" in
|
||||||
|
*.tar) cmd="tar-in \"$src\" \"$dest\"" ;;
|
||||||
|
*.tar.gz) cmd="tar-in \"$src\" \"$dest\" compress:gzip" ;;
|
||||||
|
*) cmd="copy-in \"$src\" \"$dest\"" ;;
|
||||||
|
esac
|
||||||
|
script+=("$cmd")
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
script+=("fstrim /")
|
||||||
|
|
||||||
|
for cmd in "${script[@]}"; do
|
||||||
|
echo "$cmd"
|
||||||
|
done | guestfish --format=raw -a "$image"
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
podman run --arch=arm64 --security-opt=label=disable \
|
||||||
|
-v "${2:-./artifacts}:/artifacts" \
|
||||||
|
-v ./mkinitfs.conf:/tmp/mkinitfs.conf:ro \
|
||||||
|
--rm "docker.io/library/alpine:${1:-latest}" \
|
||||||
|
sh -c "apk update && apk add mkinitfs apk-tools && mkinitfs -c /tmp/mkinitfs.conf -n -o /artifacts/initramfs"
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Assemble SPL, U-Boot, U-Boot environment, boot-resources, boot and rootfs
|
||||||
|
# images into a final H700 bootable sdcard image.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# -lt 7 ]] ; then
|
||||||
|
echo "Usage: $0 SDCARD SPL UBOOT ENV BOOT-RESOURCE BOOT ROOTFS"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mb() {
|
||||||
|
# Return the file size in MiB (rounded up)
|
||||||
|
local file_size
|
||||||
|
file_size="$(stat -c "%s" "$1")"
|
||||||
|
echo "$(( (file_size + 1024 ** 2 - 1) / 1024 ** 2 ))M"
|
||||||
|
}
|
||||||
|
|
||||||
|
sgdisk --move-main-table=73696 -I \
|
||||||
|
--new="0:0:+$(mb "$4")" --change-name=0:env --attributes=0:=:c000000000000001 --typecode=0:b000 \
|
||||||
|
--new="0:0:+$(mb "$5")" --change-name=0:boot-resource --attributes=0:=:c000000000000001 --typecode=0:0700 \
|
||||||
|
--new="0:0:+$(mb "$6")" --change-name=0:boot --attributes=0:=:c000000000000001 --typecode=0:a002 \
|
||||||
|
--new="0:0:+$(mb "$7")" --change-name=0:rootfs --attributes=0:=:c000000000000001 --typecode=0:8305 \
|
||||||
|
"$1"
|
||||||
|
|
||||||
|
part_table="$(sgdisk -p artifacts/alpine-h700.img | awk '/^ +[0-9]+ +[0-9]+ +[0-9]+/{print $2 / 2}' | xargs)"
|
||||||
|
read -r -a offsets <<<"$part_table"
|
||||||
|
|
||||||
|
images=("$2" "$3" "$4" "$5" "$6" "$7")
|
||||||
|
offsets=(8 16400 "${offsets[@]}")
|
||||||
|
|
||||||
|
for i in "${!images[@]}"; do
|
||||||
|
img="${images[$i]}"
|
||||||
|
off="${offsets[$i]}"
|
||||||
|
echo "Writing $img at offset ${off}KiB"
|
||||||
|
dd if="$img" of="$1" bs=1K seek="${off}" conv=sparse,notrunc status=none
|
||||||
|
done
|
||||||
|
echo "Your bootable SD image is $1"
|
||||||