Hacking the Modecom FreeTAB 9000 (2)
After my previous post on the FreeTAB, I noticed that GitHub user archeYR has already made a lot of progress on porting a recent Linux version to SFI-based platforms. His work is spread over three repositories:
- sfi-bootstub contains a bootstub fork that adds support for booting Linux 4.7 and newer versions and implements a framebuffer that can be used both from bootstub itself (using printf statements) and by the Linux kernel (using simplefb)1. This repository was already on my radar as it is referred to by the postmarketOS page on the Teclast P89 Mini, another MID-based Android device.
- intel-ifwi-study is a fork of the alef78/intel-ifwi-study repository of user alef78 that I also forked in my previous post. It contains a modified
mkbootprogram that inserts a text mode font into the boot image for use byprintfcalls from the modified bootstub.unpbootwas not modified, so there is no support for 4KB bootstubs like in my fork. - linux (branch 'intel-sfi') contains a fork of the Linux 5.10 kernel (the last long-term support release that still supports SFI), extended with support for the framebuffer setup by sfi-bootstub, various fixes for Clover Trail+-based devices, and a defconfig for SFI-based systems.
These repositories are relatively light on documentation, so let's see if we can get the bootstub and kernel working on the FreeTAB.
Bootstub #
After cloning the sfi-bootstub repo above, we can build it for the Clover Trail+ platform by running:
PLATFORM=MOORESTOWN make
This will result in a binary bootstub appearing in the root of the repository.
Kernel #
Grab a copy of the intel-sfi branch. Select the defconfig for SFI platforms included in the repository and then build the kernel for the i386 architecture (I like to use Clang/LLVM for cross-compiling):
make ARCH=i386 LLVM=1 sfi_defconfig
make ARCH=i386 LLVM=1 -j$(nproc)
Building a minimal initrd #
For the initrd I decided to go with a statically linked version of BusyBox. Grab the latest version of the BusyBox source, extract it and build a static 32-bit version using:
make defconfig
make ARCH=i386 \
CC="clang --target=i686-linux-gnu" \
LD="clang --target=i686-linux-gnu" \
AR="llvm-ar" \
NM="llvm-nm" \
STRIP="llvm-strip" \
OBJCOPY="llvm-objcopy" \
OBJDUMP="llvm-objdump" \
EXTRA_CFLAGS="-march=atom" \
EXTRA_LDFLAGS="-fuse-ld=lld -static" \
-j$(nproc)
If your host machine is on a recent kernel version (>= 6.8) you might need to set CONFIG_TC=n in .config after running make defconfig, see this bug.
After a few minutes (depending on your machine) the BusyBox binary is available in the root of the source directory. We can now build a minimal initrd:
mkdir initrd && cd initrd
mkdir bin dev proc sys
cp <busybox directory>/busybox bin/busybox
# Create symlinks for common utilities provided by BusyBox
for cmd in \
awk blkid cat cp date dd df dmesg du echo env \
false fdisk find free grep head hostname hwclock id \
insmod install ip kill less ln ls lsmod lsof lspci lsusb \
mkdir modinfo modprobe mount mountpoint mv nproc ping pkill \
poweroff printf ps pwd reboot rm rmdir rmmod sed sh sleep sort \
split stat strings su sysctl tail tar tee time top touch tr true \
umount uname uptime usleep vi wc which xargs yes zcat; do
ln -s busybox bin/$cmd
done
# Create a simple init script
cat <<EOF > bin/init
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
exec /bin/sh
EOF
chmod +x bin/init
find . | cpio -o -H newc | gzip -c -9 > ramdisk
Building archeYR's intel-ifwi-study tools #
Clone archeYR's intel-ifwi-study repository and build the tools using make.
If you are using a recent version of GCC, you might need to add #include <unistd.h> to all .c files.
Building the boot image #
Now we can start building the boot image:
-
Extract the original boot image using my intel-ifwi-study fork.
-
Create a directory
boot.img.unp/in archeYR'sintel-ifwi-study/directory. -
Copy
header.binfrom the extracted boot image to the newboot.img.unp/directory. -
Copy
bootstubfrom thesfi-bootstub/directory to the newboot.img.unp/directory. -
Copy
bzImagefrom the kernel build directory to the newboot.img.unp/directory and rename it tokernel. -
Copy
ramdiskfrom theinitrd/directory to the newboot.img.unp/directory. -
Create a file
cmdlineand add the kernel command line to this file. The exact command line depends on your device, you can use the original (Android) cmdline as a starting point. I ended up with the following:
pci=noearly hsu_dma=7 ehci_hcd.use_sph=1 rdinit=/bin/init loglevel=7- The first three options I kept from the original Android command line.
rdinit=/bin/initspecifies the init script in our initrd as the initial userspace process to run.loglevel=7changes the default log level from 4 (warnings) to 7 (debug messages).
-
Add the font as described in the README:
wget https://github.com/viler-int10h/vga-text-mode-fonts/raw/refs/heads/master/FONTS/PC-IBM/VGA8.F16 -O font -
Build the boot image:
bash mkboot.sh boot.img
Testing #
Flash the resulting patched.boot.img file from droidboot using fastboot flash boot patched.boot.img and then reboot the device via fastboot reboot.
After the reboot you should see the bootstub print some messages, and a few seconds later the kernel should begin booting:
Remarks #
1: The modified bootstub also introduced support for the Multiboot specification, as archeYR seems to intend to port ReactOS to SFI-based platforms.
- Previous post: Hacking the Modecom FreeTAB 9000 (1)
- Next post: Connecting a Kamst-IR Gateway to Home Assistant via REST