commit 3216669497d53a0e4935561e1b1f28874c6810a9 Author: Maurizio Porrato Date: Sun Jun 23 18:03:33 2024 +0100 Initial commit: boot, wifi and ssh work Signed-off-by: Maurizio Porrato diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..935f048 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.img +!config/ +config/* +!config/etc/ +config/etc/* +!config/etc/motd diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9041a6c --- /dev/null +++ b/Makefile @@ -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)/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d64958 --- /dev/null +++ b/README.md @@ -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`. diff --git a/UNLICENSE b/UNLICENSE new file mode 100644 index 0000000..c32dd18 --- /dev/null +++ b/UNLICENSE @@ -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 \ No newline at end of file diff --git a/artifacts/.gitignore b/artifacts/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/artifacts/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/config/etc/motd b/config/etc/motd new file mode 100644 index 0000000..0ff9c60 --- /dev/null +++ b/config/etc/motd @@ -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 . + +You may change this message by editing /etc/motd. + diff --git a/env.txt b/env.txt new file mode 100644 index 0000000..66ed10b --- /dev/null +++ b/env.txt @@ -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 diff --git a/mkinitfs.conf b/mkinitfs.conf new file mode 100644 index 0000000..bb0587a --- /dev/null +++ b/mkinitfs.conf @@ -0,0 +1 @@ +features="base" diff --git a/resources/bat/bat0.bmp b/resources/bat/bat0.bmp new file mode 100644 index 0000000..bc1c837 Binary files /dev/null and b/resources/bat/bat0.bmp differ diff --git a/resources/bat/bat1.bmp b/resources/bat/bat1.bmp new file mode 100644 index 0000000..216c489 Binary files /dev/null and b/resources/bat/bat1.bmp differ diff --git a/resources/bat/bat10.bmp b/resources/bat/bat10.bmp new file mode 100644 index 0000000..417efdf Binary files /dev/null and b/resources/bat/bat10.bmp differ diff --git a/resources/bat/bat2.bmp b/resources/bat/bat2.bmp new file mode 100644 index 0000000..33642c1 Binary files /dev/null and b/resources/bat/bat2.bmp differ diff --git a/resources/bat/bat3.bmp b/resources/bat/bat3.bmp new file mode 100644 index 0000000..542e4b3 Binary files /dev/null and b/resources/bat/bat3.bmp differ diff --git a/resources/bat/bat4.bmp b/resources/bat/bat4.bmp new file mode 100644 index 0000000..b3b87c2 Binary files /dev/null and b/resources/bat/bat4.bmp differ diff --git a/resources/bat/bat5.bmp b/resources/bat/bat5.bmp new file mode 100644 index 0000000..9b7379a Binary files /dev/null and b/resources/bat/bat5.bmp differ diff --git a/resources/bat/bat6.bmp b/resources/bat/bat6.bmp new file mode 100644 index 0000000..83a10e1 Binary files /dev/null and b/resources/bat/bat6.bmp differ diff --git a/resources/bat/bat7.bmp b/resources/bat/bat7.bmp new file mode 100644 index 0000000..5615840 Binary files /dev/null and b/resources/bat/bat7.bmp differ diff --git a/resources/bat/bat8.bmp b/resources/bat/bat8.bmp new file mode 100644 index 0000000..a13d6d6 Binary files /dev/null and b/resources/bat/bat8.bmp differ diff --git a/resources/bat/bat9.bmp b/resources/bat/bat9.bmp new file mode 100644 index 0000000..8e90e20 Binary files /dev/null and b/resources/bat/bat9.bmp differ diff --git a/resources/bat/bat_blank.bmp b/resources/bat/bat_blank.bmp new file mode 100644 index 0000000..9075011 Binary files /dev/null and b/resources/bat/bat_blank.bmp differ diff --git a/resources/bat/bat_htmp.bmp b/resources/bat/bat_htmp.bmp new file mode 100644 index 0000000..7706d59 Binary files /dev/null and b/resources/bat/bat_htmp.bmp differ diff --git a/resources/bat/bat_ltmp.bmp b/resources/bat/bat_ltmp.bmp new file mode 100644 index 0000000..db1a410 Binary files /dev/null and b/resources/bat/bat_ltmp.bmp differ diff --git a/resources/bat/battery.bmp b/resources/bat/battery.bmp new file mode 100644 index 0000000..ed17fba Binary files /dev/null and b/resources/bat/battery.bmp differ diff --git a/resources/bat/battery_charge.bmp b/resources/bat/battery_charge.bmp new file mode 100644 index 0000000..a550d41 Binary files /dev/null and b/resources/bat/battery_charge.bmp differ diff --git a/resources/bat/bempty.bmp b/resources/bat/bempty.bmp new file mode 100644 index 0000000..91dd947 Binary files /dev/null and b/resources/bat/bempty.bmp differ diff --git a/resources/bat/bootlogo.bmp b/resources/bat/bootlogo.bmp new file mode 100644 index 0000000..524345b Binary files /dev/null and b/resources/bat/bootlogo.bmp differ diff --git a/resources/bat/low_pwr.bmp b/resources/bat/low_pwr.bmp new file mode 100644 index 0000000..7c2ea42 Binary files /dev/null and b/resources/bat/low_pwr.bmp differ diff --git a/resources/bootlogo.bmp b/resources/bootlogo.bmp new file mode 100644 index 0000000..8dede69 Binary files /dev/null and b/resources/bootlogo.bmp differ diff --git a/resources/fastbootlogo.bmp b/resources/fastbootlogo.bmp new file mode 100644 index 0000000..b410721 Binary files /dev/null and b/resources/fastbootlogo.bmp differ diff --git a/resources/font24.sft b/resources/font24.sft new file mode 100644 index 0000000..bf1ba18 Binary files /dev/null and b/resources/font24.sft differ diff --git a/resources/font32.sft b/resources/font32.sft new file mode 100644 index 0000000..c19f1f9 Binary files /dev/null and b/resources/font32.sft differ diff --git a/resources/magic.bin b/resources/magic.bin new file mode 100644 index 0000000..3f8b8af --- /dev/null +++ b/resources/magic.bin @@ -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 \ No newline at end of file diff --git a/scripts/_build.sh b/scripts/_build.sh new file mode 100755 index 0000000..b94f1f6 --- /dev/null +++ b/scripts/_build.sh @@ -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" . diff --git a/scripts/build-rootfs.sh b/scripts/build-rootfs.sh new file mode 100755 index 0000000..fd44814 --- /dev/null +++ b/scripts/build-rootfs.sh @@ -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 diff --git a/scripts/extract-blobs.py b/scripts/extract-blobs.py new file mode 100755 index 0000000..799eb1a --- /dev/null +++ b/scripts/extract-blobs.py @@ -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(" size: + raise EnvError(f"Insufficient environment space: need at least {envsize} bytes") + buf += bytes(size - envsize) + crc = zlib.crc32(buf, 0) + buf = struct.pack("