- Still missing kernel modules (from sysdrv/source/objs_kernel/drv_ko/lib/modules/, not copied in for some reason?)
Start by getting the Luckfox Pico SDK at https://github.com/LuckfoxTECH/luckfox-pico
Set it up by running:
# 1. Configure the Environment
cd luckfox-pico
./build.sh env
# SELECT: [2] Luckfox Pico Mini B -> [0] SDCard -> [0] Buildroot
# 2. Build U-Boot
./build.sh uboot
# 3. Build Kernel
cd luckfox-pico
./build.sh kernelconfig
# Keep default or change as needed, then we build kernel:
./build.sh kernel4. Build alpine rootfs (skip ./build.sh rootfs) We build the rootfs ourself using https://github.com/alpinelinux/alpine-make-rootfs
sudo APK_OPTS="--arch armhf --allow-untrusted --no-progress" \
./alpine-make-rootfs \
--keys-dir ./keys \
--branch v3.21 \
--timezone Asia/Jakarta \
--packages "alpine-baselayout busybox openrc apk-tools shadow \
bash bash-completion nano htop btop file \
grep sed gawk \
tar gzip bzip2 xz zstd \
pigz zip unzip 7zip \
wget curl openssh openssh-sftp-server \
iw net-tools iproute2 wpa_supplicant wireless-tools \
bind-tools ca-certificates \
ethtool tcpdump socat \
sudo parted mmc-utils \
e2fsprogs e2fsprogs-extra \
cloud-utils-growpart \
usbutils util-linux util-linux-misc usb-modeswitch \
lm-sensors i2c-tools libgpiod rng-tools \
tmux fastfetch chrony \
python3 git \
linux-firmware-none \
linux-firmware-brcm \
linux-firmware-cypress \
linux-firmware-ath10k \
linux-firmware-ath9k_htc \
linux-firmware-rtlwifi \
linux-firmware-realtek \
linux-firmware-mediatek
linux-firmware-other \
wireless-regdb"\
./alpine-armhf-ultimate.tar.gz --script-chroot - <<'SHELL'
# ==========================================
# CONFIGURATION
# ==========================================
TARGET_DISK="/dev/mmcblk1"
ROOT_PART_NUM="7"
ROOT_PARTITION="${TARGET_DISK}p${ROOT_PART_NUM}"
# Export PATH for tools
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# --- 1. Filesystem Setup ---
mkdir -p /dev/pts /proc /sys
cat > /etc/fstab <<EOF
devpts /dev/pts devpts gid=5,mode=620 0 0
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
# $ROOT_PARTITION / ext4 noatime 0 1
EOF
# --- 2. Service Setup ---
rc-update add devfs sysinit
rc-update add procfs sysinit
rc-update add sysfs sysinit
rc-update add networking boot
rc-update add wpa_supplicant boot
rc-update add sshd default
rc-update add chronyd default
rc-update add rngd boot
# --- 3. FIRST BOOT PROVISIONING SCRIPT ---
# We use EOF (unquoted) so $ROOT_PARTITION expands NOW (during build),
# but we escape \$KERNEL_VERSION so it expands LATER (during boot).
cat > /etc/init.d/firstboot-provision <<EOF
#!/sbin/openrc-run
depend() {
after localmount
}
start() {
# --- STAGE 2: Post-Reboot Provisioning ---
if [ -f /etc/rootfs-expanded ]; then
# A. Resize Filesystem
ebegin "Provisioning: Resizing Filesystem ($ROOT_PARTITION)"
if [ -x /sbin/resize2fs ]; then
/sbin/resize2fs $ROOT_PARTITION > /dev/null
elif [ -x /usr/sbin/resize2fs ]; then
/usr/sbin/resize2fs $ROOT_PARTITION > /dev/null
fi
eend \$?
# B. Move Kernel Modules
if [ -d "/oem/usr/ko" ]; then
ebegin "Provisioning: Installing Kernel Modules"
# ESCAPED VARIABLES HERE (So they run on the device, not the builder)
KERNEL_VERSION=\$(uname -r)
MODULES_DIR="/lib/modules/\$KERNEL_VERSION"
mkdir -p "\$MODULES_DIR"
# Move files to the variable path
mv /oem/usr/ko/*.ko "\$MODULES_DIR/" 2>/dev/null
# Generate dependency map
depmod -a
# Cleanup
rm -rf /oem/usr/ko
eend \$?
else
ewarn "Provisioning: No OEM modules found in /oem/usr/ko"
fi
# C. Create Swapfile
if [ ! -f /swapfile ]; then
ebegin "Provisioning: Creating 512MB Swapfile"
fallocate -l 512M /swapfile
chmod 600 /swapfile
mkswap /swapfile > /dev/null
swapon /swapfile > /dev/null
echo '/swapfile none swap sw 0 0' >> /etc/fstab
eend \$?
fi
# D. CLEANUP
rm -f /etc/rootfs-expanded
rc-update del firstboot-provision default
rm -f /etc/init.d/firstboot-provision
# --- STAGE 1: First Boot Partition Expand ---
else
ebegin "Provisioning: Expanding Partition Table"
growpart $TARGET_DISK $ROOT_PART_NUM > /dev/null 2>&1
touch /etc/rootfs-expanded
eend \$?
ebegin "Rebooting to apply partition changes..."
reboot
fi
}
EOF
chmod +x /etc/init.d/firstboot-provision
rc-update add firstboot-provision default
# --- 4. SSH Configuration ---
ssh-keygen -A
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sed -i 's|^#*Subsystem.*sftp.*|Subsystem sftp /usr/lib/ssh/sftp-server|' /etc/ssh/sshd_config
# --- 5. Console ---
sed -i '/^tty[1-6]::/d' /etc/inittab
echo "ttyFIQ0::respawn:/sbin/agetty --autologin root ttyFIQ0 vt100" >> /etc/inittab
echo ttyFIQ0 >> /etc/securetty
# --- 6. Network ---
echo "auto eth0" >> /etc/network/interfaces
echo "iface eth0 inet dhcp" >> /etc/network/interfaces
# --- 7. User Configuration ---
awk -F: 'FNR==NR {seen[$1]=1; next} !($1 in seen) {print $1":!:19700:0:99999:7:::"}' /etc/shadow /etc/passwd >> /etc/shadow
echo "root:linux" | chpasswd
adduser -D -s /bin/bash alpine
awk -F: 'FNR==NR {seen[$1]=1; next} !($1 in seen) {print $1":!:19700:0:99999:7:::"}' /etc/shadow /etc/passwd >> /etc/shadow
echo "alpine:linux" | chpasswd
addgroup alpine wheel
echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/wheel
SHELL5. Copy rootfs
Copy the rootfs (alpine-armhf-ultimate.tar.gz) to luckfox-pico-alpinecopy/sysdrv/custom_rootfs/alpine-armhf-ultimate.tar.gz
6. Modify build.sh
Update __PACKAGE_ROOTFS to
function __PACKAGE_ROOTFS()
{
local rootfs_tarball _target_dir _install_dir
# --- Start Merged Instruction Logic ---
# Determine the rootfs tarball path (Default vs Custom)
if [ -z "$RK_CUSTOM_ROOTFS" ]; then
rootfs_tarball="$RK_PROJECT_PATH_SYSDRV/rootfs_${RK_LIBC_TPYE}_${RK_CHIP}.tar"
# Verify default tarball exists
if [ ! -f "$rootfs_tarball" ]; then
msg_error "Not found rootfs tarball: $rootfs_tarball"
exit 1
fi
# Extract default to Project Output
tar xf "$rootfs_tarball" -C "$RK_PROJECT_OUTPUT"
else
rootfs_tarball="$RK_CUSTOM_ROOTFS"
# Verify custom tarball exists
if [ ! -f "$rootfs_tarball" ]; then
msg_error "Not found rootfs tarball: $rootfs_tarball"
exit 1
fi
# Ensure destination directory exists and extract
if [ ! -d "$RK_PROJECT_PACKAGE_ROOTFS_DIR" ]; then
mkdir -p "$RK_PROJECT_PACKAGE_ROOTFS_DIR"
fi
echo "USING CUSTOM ROOTFS: $rootfs_tarball extract to $RK_PROJECT_PACKAGE_ROOTFS_DIR"
tar xf "$rootfs_tarball" -C "$RK_PROJECT_PACKAGE_ROOTFS_DIR"
fi
# --- End Merged Instruction Logic ---
# --- Start Preserved Target Logic ---
# Handle Ubuntu specific configurations (e.g., Wifi)
if [ "$RK_BOOT_MEDIUM" == "emmc" ] && [ "$LF_TARGET_ROOTFS" == "ubuntu" ]; then
if [ -f "$WIFI_CONF" ]; then
cp "$WIFI_CONF" "$RK_PROJECT_PACKAGE_ROOTFS_DIR/etc"
fi
fi
# Handle Buildroot/Busybox SDK info generation
if [ "$LF_TARGET_ROOTFS" == "buildroot" ] || [ "$LF_TARGET_ROOTFS" == "busybox" ]; then
build_get_sdk_version
cat >"$RK_PROJECT_PACKAGE_ROOTFS_DIR/bin/sdkinfo" <<EOF
#!/bin/sh
echo Build Time: $(date "+%Y-%m-%d-%T")
echo SDK Version: ${GLOBAL_SDK_VERSION}
EOF
chmod a+x "$RK_PROJECT_PACKAGE_ROOTFS_DIR/bin/sdkinfo"
__COPY_FILES "$RK_PROJECT_PATH_APP/root" "$RK_PROJECT_PACKAGE_ROOTFS_DIR"
fi
# Copy media and external files
__COPY_FILES "$RK_PROJECT_PATH_MEDIA/root" "$RK_PROJECT_PACKAGE_ROOTFS_DIR"
__COPY_FILES "$SDK_ROOT_DIR/external" "$RK_PROJECT_PACKAGE_ROOTFS_DIR"
# Handle IQ Files symlink
if [ -d "$RK_PROJECT_PACKAGE_ROOTFS_DIR/usr/share/iqfiles" ]; then
(
cd "$RK_PROJECT_PACKAGE_ROOTFS_DIR/etc"
ln -sf ../usr/share/iqfiles ./
)
fi
# Copy Rootfs initialization script
if [ -f "$RK_PROJECT_FILE_ROOTFS_SCRIPT" ]; then
chmod a+x "$RK_PROJECT_FILE_ROOTFS_SCRIPT"
cp -f "$RK_PROJECT_FILE_ROOTFS_SCRIPT" "$RK_PROJECT_PACKAGE_ROOTFS_DIR/etc/init.d"
fi
}7. Update .BoardConfig.mk Set CMA to 1M, disable install app to oem partition, remove the shadow overlay, and add our custom rootfs
# Config CMA size in environment
export RK_BOOTARGS_CMA_SIZE="1M"
#...
# enable install app to oem partition
export RK_BUILD_APP_TO_OEM_PARTITION=n
#...
# declare overlay directory
export RK_POST_OVERLAY="overlay-luckfox-config overlay-luckfox-buildroot-init"
# Configure custom image directory
export RK_CUSTOM_ROOTFS=../sysdrv/custom_rootfs/alpine-armhf-ultimate.tar.gz# 8. Build firmware
sudo ./build.sh firmware
# 9. Generate Partition Info & Flash Image
cd output/image
# Fix rootfs partition size in env config
sed -i 's/6G(rootfs)/100G(rootfs)/' .env.txt
# Generate env image
../../sysdrv/tools/pc/uboot_tools/mkenvimage -s 0x8000 -p 0x0 -o env.img .env.txt
# Pack the final image
./blkenvflash ../../alpine.img