By popular demand (one reader), I'm posting my steps to compile and flash the kernel for the Cosmo.
How to compile and flash the Linux and Android kernels for the CosmoThe following document describes how I compiled both the Linux and the Android kernels for the Cosmo. I also explain how to create a rooted Android image. I used an x86_64 Gentoo development machine for all work and nothing was compiled directly on the Cosmo. I also used live kernel configs as a starting point, not predefined configs from the kernel tree, in an attempt to keep the configuration as close to stock as possible before customizing.
Step 1: Prepare the kernel development treeCreate a directory where you will perform all of your kernel development work:
mkdir -p /path/to/cosmo/kernel
Retrieve the Cosmo Linux kernel source code:
cd /path/to/cosmo/kernel
git clone https://github.com/gemian/cosmo-linux-kernel-4.4.git
Retrieve the Cosmo Android kernel source code:
cd /path/to/cosmo/kernel
git clone https://github.com/dguidipc/cosmo-android-kernel.git
Retrieve and build mkbootimg for manipulating ramdisk boot images:
cd /path/to/cosmo/kernel
git clone https://github.com/osm0sis/mkbootimg.git
cd mkbootimg
make
cd ..
Retrieve the prebuilt gcc arm64 cross compiler tools:
cd /path/to/cosmo/kernel
git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b nougat-release --depth 1
Retrieve Planet Computers' Linux v3 firmware:
cd /path/to/cosmo
wget http://support.planetcom.co.uk/download/cosmo-customos-installer-v3.zip
unzip cosmo-customos-installer-v3.zip \
cosmo-customos-installer/linux-cosmo-boot.img \
cosmo-customos-installer/twrp.img \
cosmo-customos-installer/root-boot.img
"linux-cosmo-boot.img" is the stock Linux ramdisk boot image which contains a ramdisk and the Linux kernel image.
"twrp.img" is the handy TWRP rescue image.
"root-boot.img" is the stock rooted Android boot image with ramdisk and kernel.
Unpack the stock Linux boot image:
cd /path/to/cosmo/kernel
mkdir linux_boot
mkbootimg/unpackbootimg -i ../cosmo-customos-installer/linux-cosmo-boot.img -o linux_boot
It prints this:
BOARD_KERNEL_CMDLINE bootopt=64S3,32N2,64N2
BOARD_KERNEL_BASE 40078000
BOARD_NAME
BOARD_PAGE_SIZE 2048
BOARD_HASH_TYPE sha1
BOARD_KERNEL_OFFSET 00008000
BOARD_RAMDISK_OFFSET 14f88000
BOARD_SECOND_OFFSET 00e88000
BOARD_TAGS_OFFSET 13f88000
And it creates linux-cosmo-boot.img-ramdisk.gz which we will use later.
Unpack the stock rooted Android boot image:
cd /path/to/cosmo/kernel
mkdir android_root_boot
mkbootimg/unpackbootimg -i ../cosmo-customos-installer/root-boot.img -o android_root_boot
It prints this:
BOARD_KERNEL_CMDLINE bootopt=64S3,32N2,64N2 buildvariant=user veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f
BOARD_KERNEL_BASE 40078000
BOARD_NAME
BOARD_PAGE_SIZE 2048
BOARD_HASH_TYPE sha1
BOARD_KERNEL_OFFSET 00008000
BOARD_RAMDISK_OFFSET 14f88000
BOARD_SECOND_OFFSET 00e88000
BOARD_TAGS_OFFSET 13f88000
BOARD_OS_VERSION 9.0.0
BOARD_OS_PATCH_LEVEL 2021-01
BOARD_DT_SIZE 1
And it creates root-boot.img-ramdisk.gz which we will use later.
Retrieve live kernel configs. Boot stock Linux or stock Android. Transfer the file /proc/config.gz to your development machine, unzip, and rename:
cd /path/to/cosmo/kernel/cosmo-linux-kernel-4.4 # or cosmo-android-kernel
mv config.gz config-from-live-stock-kernel.gz
gunzip config-from-live-stock-kernel.gz
cp config-from-live-stock-kernel .config
Your kernel development directory tree should now resemble this:
/path/to/cosmo/
`-- cosmo-customos-installer-v3.zip # retrieved 2020-11-18
`-- cosmo-customos-installer/ # from cosmo-customos-installer-v3.zip
`-- linux-cosmo-boot.img # stock Linux boot image
`-- root-boot.img # stock rooted Android boot image
`-- twrp.img # TWRP rescue image
`-- kernel/
`-- aarch64-linux-android-4.9/ # from https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9
`-- cosmo-android-kernel/ # from https://github.com/dguidipc/cosmo-android-kernel.git
`-- config-from-live-stock-kernel
`-- .config
`-- cosmo-linux-kernel-4.4/ # from https://github.com/gemian/cosmo-linux-kernel-4.4.git
`-- config-from-live-stock-kernel
`-- .config
`-- mkbootimg/ # from https://github.com/osm0sis/mkbootimg.git
`-- android_root_boot/ # from mkbootimg/unpackbootimg
`-- root-boot.img-ramdisk.gz
`-- linux_boot/ # from mkbootimg/unpackbootimg
`-- linux-cosmo-boot.img-ramdisk.gz
Step 2: Prepare the kernel source for buildingIn my build environment, the kernel build fails "out of the box" with a truckload of #include errors, plus harmless warnings that are treated as errors. Please note that other kernel build methods with other cross compilers and/or other host distributions may not experience the same build difficulties I did, and judging from other kernel compilation posts, most don't. But in case you do, I'm including every issue I hit and how to work around it.
First modify some Makefiles to disable treating warnings as errors.
cd /path/to/cosmo/kernel/cosmo-linux-kernel-4.4/
Edit drivers/misc/mediatek/Makefile:
# SHUNTCAP: remove this subdir-ccflags-y += -Werror
Edit: drivers/Makefile:
# SHUNTCAP: remove this subdir-ccflags-y += -Werror
Edit Makefile:
#SHUNTCAP: remove this KBUILD_CFLAGS += $(call cc-option,-Werror=implicit-int)
Now for the messy part. In my case, the build could not find a large number of header files. Here is an example from my Gemini build, but the Cosmo build has the same issues (for me):
/devel/gemini/kernel/aarch64-linux-android-4.9/bin/aarch64-linux-android-gcc -Wp,-MD,drivers/misc/mediatek/leds/.mtk_leds_drv.o.d -nostdinc -isystem /devel/gemini/kernel/aarch64-linux-android-4.9/bin/../lib/gcc/aarch64-linux-android/4.9/include -I./arch/arm64/include -Iarch/arm64/include/generated/uapi -Iarch/arm64/include/generated -Iinclude -I./arch/arm64/include/uapi -Iarch/arm64/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -I./drivers/misc/mediatek/include -I. -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -mgeneral-regs-only -fno-pic -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -Wno-maybe-uninitialized -O2 --param=allow-store-data-races=0 -DCC_HAVE_ASM_GOTO -Wframe-larger-than=2800 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -I./drivers/misc/mediatek/hibcore -I./drivers/misc/mediatek/include -I./drivers/misc/mediatek/include/mt-plat/mt6771/include -I./drivers/misc/mediatek/include/mt-plat -I./drivers/mmc/host/mediatek/mt6771 -I./drivers/misc/mediatek/leds/mt6771 -I./drivers/misc/mediatek/video/include -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(mtk_leds_drv)" -D"KBUILD_MODNAME=KBUILD_STR(mtk_leds_drv)" -c -o drivers/misc/mediatek/leds/.tmp_mtk_leds_drv.o drivers/misc/mediatek/leds/mtk_leds_drv.c
drivers/misc/mediatek/leds/mtk_leds_drv.c:26:26: fatal error: mtk_leds_drv.h: No such file or directory
#include <mtk_leds_drv.h>
This happens because the compiler is called from the toplevel directory on drivers/misc/mediatek/leds/mtk_leds_drv.c, while mtk_leds_drv.h is in drivers/misc/mediatek/leds, but drivers/misc/mediatek/ is not in the -I include path. According to gcc documentation, <...h> will not search the current directory unless supplied with the -I directive. And the build doesn't enter that directory anyway, so it has no way to find the header file even if we add "-I." to the toplevel Makefile. In this case, drivers/misc/mediatek/leds/Makefile lacks an -I directive to include drivers/misc/mediatek/leds. #include "mtk_leds_drv.h" would have found it, though.
Fix broken build include paths (again, this may not be necessary in other build environments, but it is in mine):
cd /path/to/cosmo/kernel/cosmo-linux-kernel-4.4/drivers/misc/mediatek/include
ln -s ../../../devfreq/*.h .
rm mtk_dvfsrc_reg.h # Avoid ambiguity with misc/mediatek/base/power/spm_v4/*.h
ln -s ../../../input/fingerprint/aw6302_driver/*.h .
ln -s ../../../input/keyboard/mediatek/*.h .
ln -s ../../../misc/mediatek/base/power/cm_mgr_v1/*.h .
ln -s ../../../misc/mediatek/base/power/mt6771/*.h .
ln -s ../../../misc/mediatek/base/power/ppm_v3/src/mach/mt6771/*.h .
ln -s ../../../misc/mediatek/base/power/spm_v4/*.h .
ln -s ../../../misc/mediatek/base/power/swpm_v1/mt6771/*.h .
ln -s ../../../misc/mediatek/cameraisp/src/isp_50/inc .
ln -s ../../../misc/mediatek/ccu/src/mt6771/ccu_ext_interface .
ln -s ../../../misc/mediatek/cmdq/v3/*.h .
ln -s ../../../misc/mediatek/cmdq/v3/mt6771/*.h .
ln -s ../../../misc/mediatek/eccci/*.h .
ln -s ../../../misc/mediatek/eccci/hif .
ln -s ../../../misc/mediatek/eccci/hif/*.h .
ln -s ../../../misc/mediatek/emi/mt6771/*.h .
ln -s ../../../misc/mediatek/ext_disp/mt6771/*.h .
ln -s ../../../misc/mediatek/leds/*.h .
ln -s ../../../misc/mediatek/m4u/mt6771/*.h .
ln -s ../../../misc/mediatek/mu3phy/*.h .
ln -s ../../../misc/mediatek/sspm/*.h .
ln -s ../../../misc/mediatek/sspm/mt6771/*.h .
ln -s ../../../misc/mediatek/timer/timesync/*.h .
cd inc
ln -s ../../../../usb_c/tcpc/inc/* .
cd ..
ln -s ../../../misc/mediatek/video/common/layering_rule_base/v1.1/*.h .
ln -s ../../../misc/mediatek/video/mt6771/dispsys/*.h .
ln -s ../../../misc/mediatek/video/mt6771/videox/*.h .
ln -s ../../../misc/mediatek/vpu/mt6771/*.h .
ln -s ../../../mmc/host/mediatek/ComboA/*.h .
ln -s ../../../pinctrl/mediatek/*.h .
ln -s ../../../power/mediatek/battery/*.h .
ln -s ../../../watchdog/mediatek/wdt/common/wdt_v2/*.h .
Edit drivers/devfreq/helio-dvfsrc.c:
// SHUNTCAP: Ambiguous ./drivers/misc/mediatek/include/mtk_dvfsrc_reg.h symlink must be removed.
// SHUNTCAP: Causes Oops due to pulling wrong DVFSRC_LEVEL* definition (lacking DVFSRC_BASE + offset).
// SHUNTCAP: Shouldn't even need these symlinks, but the build system is broken with MTK using the
// SHUNTCAP: angled includes below when the -I directives don't contain the correct paths. My
// SHUNTCAP: workaround is to create symlinks to the required header files and place them in
// SHUNTCAP: ./drivers/misc/mediatek/include/ for all MTK source to see despite angled includes.
//#include <helio-dvfsrc.h> // SHUNTCAP
#include "drivers/devfreq/helio-dvfsrc.h" // SHUNTCAP
//#include <helio-dvfsrc-opp.h> // SHUNTCAP
#include "drivers/devfreq/helio-dvfsrc-opp.h" // SHUNTCAP
//#include <mtk_dvfsrc_reg.h> // SHUNTCAP
#include "drivers/devfreq/mtk_dvfsrc_reg.h" // SHUNTCAP
And only for the Android kernel, these required files weren't even in the tree:
ln -s ../../../../../cosmo-linux-kernel-4.4/include/uapi/linux .
cd /path/to/cosmo/kernel/cosmo-android-kernel/net/netfilter
ln -s ../../../cosmo-linux-kernel-4.4/net/netfilter/xt_HL.c .
ln -s ../../../cosmo-linux-kernel-4.4/net/netfilter/xt_TCPMSS.c .
cd -
Also only for the Android build, I had to change drivers/devfreq/helio-dvfsrc.c to the following (different include path than with the Linux build):
#include "helio-dvfsrc.h" // SHUNTCAP
#include "helio-dvfsrc-opp.h" // SHUNTCAP
#include "mtk_dvfsrc_reg.h" // SHUNTCAP
Step 3: Add exFAT support (optional)It's frustrating to insert an exFAT-formatted SD card into the Cosmo only to find out there's no support for the filesystem! So let's add it. Credit goes to
https://github.com/arter97/exfat-linux/.
cd /path/to/cosmo/kernel/
wget https://github.com/arter97/exfat-linux/archive/old.zip -O exfat-linux-old.zip # (do not git clone; it will pull one requiring Linux 4.9+)
unzip exfat-linux-old.zip
cp -a exfat-linux-old cosmo-linux-kernel-4.4/fs/exfat # if you're compiling Linux kernel
cp -a exfat-linux-old cosmo-android-kernel/fs/exfat # if you're compiling Android kernel
cd cosmo-linux-kernel-4.4 # or cosmo-android-kernel
Edit fs/Kconfig, add exfat:
source "fs/fat/Kconfig"
source "fs/exfat/Kconfig"
Edit fs/Makefile, add exfat:
obj-$(CONFIG_FAT_FS) += fat/
obj-$(CONFIG_EXFAT_FS) += exfat/
Step 4: Configure the kernelMake any changes to the kernel configuration before building:
cd /path/to/cosmo/kernel/cosmo-linux-kernel-4.4 # or cosmo-android-kernel
CROSS_COMPILE=../aarch64-linux-android-4.9/bin/aarch64-linux-android- ARCH=arm64 make menuconfig
Don't forget to enable exFAT if you added the sources in step 3:
File systems -> DOS/FAT/NT Filesystems
<*> exFAT fs support
Step 5: Compile the kernelNow compile the kernel:
cd /path/to/cosmo/kernel/cosmo-linux-kernel-4.4 # or cosmo-android-kernel
CROSS_COMPILE=../aarch64-linux-android-4.9/bin/aarch64-linux-android- ARCH=arm64 make LOCALVERSION= -j8
You may wish to adjust the -j8 parameter based on your CPU. -j8 will compile using eight threads. For example, on a quad-core processor, this number comes from having two threads per core.
Note that you can also use clang to compile your kernel if you prefer. The stock kernels were built with clang. If you have installed arm64 clang on your development system and prefer it, use this command instead:
make ARCH=arm64 CC=clang CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=aarch64-linux-android- V=1 LOCALVERSION= -j8
V=1 is optional and will produce a more verbose output.
The stock Cosmo kernel was built with clang-4691093, which you can obtain here:
https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+archive/android-9.0.0_r1/clang-4691093.tar.gzStep 6: Create a boot imageNow create the Linux kernel boot image:
cd /path/to/cosmo/kernel
mkbootimg/mkbootimg \
--kernel cosmo-linux-kernel-4.4/arch/arm64/boot/Image.gz-dtb \
--ramdisk linux_boot/linux-cosmo-boot.img-ramdisk.gz \
--base 0x40078000 \
--second_offset 0x00e88000 \
--cmdline "bootopt=64S3,32N2,64N2" \
--kernel_offset 0x00008000 \
--ramdisk_offset 0x14f88000 \
--tags_offset 0x13f88000 \
--pagesize 2048 \
--hash sha1 \
-o linux_test.img
You will now have a new Linux boot image in
/path/to/cosmo/kernel/linux_test.img
Alternatively, create the Android boot image:
cd /path/to/cosmo/kernel
mkbootimg/mkbootimg \
--kernel cosmo-android-kernel/arch/arm64/boot/Image.gz-dtb \
--ramdisk android_root_boot/root-boot.img-ramdisk.gz \
--base 0x40078000 \
--second_offset 0x00e88000 \
--cmdline "bootopt=64S3,32N2,64N2 buildvariant=user veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f" \
--kernel_offset 0x00008000 \
--ramdisk_offset 0x14f88000 \
--tags_offset 0x13f88000 \
--pagesize 2048 \
--hash sha1 \
--os_version 9.0.0 --os_patch_level 2021-01 \
-o android_test.img
You will now have a new Android boot image in
/path/to/cosmo/kernel/android_test.img
Note that this Android boot image does not have root capability. If you want rooted Android, continue to step 7. Otherwise, skip to step 8.
Step 7: Root the Android boot image (optional)To root your Android boot image, boot the Cosmo into Android. Install Magisk Manager. Transfer /path/to/cosmo/kernel/android_test.img to the Cosmo, placing it in /sdcard/. You can use adb from your development machine:
adb -s <Cosmo_Serial_Num> push /path/to/cosmo/kernel/android_test.img /sdcard/
Open Magisk Manager, tap the Install button, select android_test.img, and let it root the image. Now transfer the rooted image back to your development machine:
adb -s <Cosmo_Serial_Num> pull /sdcard/kernel/android_test.img rooted_android_test.img
Step 8: Flash your new kernel boot imageThe Cosmo has four boot partitions which are accessible by /dev/block/platform/bootdevice/by-name/<partition_name>, where <partition_name> is one of the following:
boot - normal Android (not rooted)
ROOTED_ANDROID - rooted Android
DEBIAN_KDE - Linux
TWRP - TWRP rescue image
We will flash our newly created kernel boot image onto one of these partitions.
IMPORTANT: Before flashing, make sure you have a way to reflash a working Linux kernel if your test kernel is broken. You can rely on either rooted Android or TWRP and use adb to push your test kernel onto the Cosmo, then flash from there. In other words, if you don't want to use Planet's SD card method of reflashing your Linux or Android boot partitions, install TWRP or rooted Android
NOW.
To flash from Cosmo Linux: first transfer linux_test.img to the Cosmo using the means of your choice. My personal build script ftp's to the Cosmo at 10.15.19.82 (the Cosmo's RNDIS address as presented when plugged into the development machine's USB port). Then either ssh into the Cosmo or directly type these commands on it:
dd if=/path/to/linux_test.img of=/dev/block/platform/bootdevice/by-name/DEBIAN_KDE
Or from Android or TWRP via adb on your development machine:
adb -s <Cosmo_Serial_Num> push ../linux_test.img /sdcard/
adb -s <Cosmo_Serial_Num> shell
su
dd if=/sdcard/root_test.img of=/dev/block/platform/bootdevice/by-name/DEBIAN_KDE
To flash an Android boot image, use the same dd command but flash to either "ROOTED_ANDROID" or "boot". For example, for non-rooted Android:
dd if=/sdcard/android_test.img of=/dev/block/platform/bootdevice/by-name/boot
Or for rooted Android:
dd if=/sdcard/rooted_android_test.img of=/dev/block/platform/bootdevice/by-name/ROOTED_ANDROID
I actually have a backup Linux boot image on "boot" and a working Android image on ROOTED_ANDROID.
You can also transfer and flash the stock boot images (see step 1 for names).
Now you can reboot and see if your new kernel boots or not.
Step 9: Find out what went wrongWhat, your new kernel didn't boot the first time? Neither did mine. At this point, you can either flash a stock boot image back (see step 8 above), or boot to an alternative OS such as TWRP or rooted Android and check the last kernel log to see what went wrong during boot.
Inspect this file on the Cosmo: /proc/last_kmsg
In my case, the kernel source referenced an ambiguous driver header and the wrong one was compiled. I noted this in /proc/last_kmsg:
[ 0.991933] -(6)[1:swapper/0]Unable to handle kernel NULL pointer dereference at virtual address 000000e0
[ 0.991945] -(6)[1:swapper/0]pgd = ffffff800a109000
[ 0.991953] [000000e0] *pgd=00000000ffffe003, *pud=00000000ffffe003, *pmd=0000000000000000
[ 0.991971] -(6)[1:swapper/0]Internal error: Oops: 96000045 [#1] PREEMPT SMP
[ 0.991981] disable aee kernel api
[ 0.991984] -(6)[1:swapper/0]Kernel Offset: 0x0 from 0xffffff8008000000
[ 0.991996] Modules linked in:
[ 1.992010] -(6)[1:swapper/0]Non-crashing CPUs did not react to IPI
[ 1.992022] -(6)[1:swapper/0]CPU: 6 PID: 1 Comm: swapper/0 Tainted: G S W 4.4.146+ #3
[ 1.992036] -(6)[1:swapper/0]Hardware name: MT6771V/CT (DT)
[ 1.992044] -(6)[1:swapper/0]task: ffffffc05ff58000 task.stack: ffffffc05ff6c000
[ 1.992060] -(6)[1:swapper/0]PC is at dvfsrc_init.part.0+0x44/0x3ac <-- NOTE THIS FUNCTION NAME: CRASH IS HERE
[ 1.992069] -(6)[1:swapper/0]LR is at dvfsrc_init.part.0+0x38/0x3ac
... spew ...
[ 2.005768] -(6)[1:swapper/0]<4>[111951692] mtk_wdt_probe+0x14c/0x388
[ 2.006373] -(6)[1:swapper/0]****************dump wdt reg end*************
[ 2.006943] -(6)[1:swapper/0]wdt_arch_reset: sw reset happen!
From there I saw that it was crashing in drivers/misc/mediatek/base/power/spm_v4/mtk_spm_vcorefs_mt6771.c:dvfsrc_init(). To fix it, I had to patch drivers/devfreq/helio-dvfsrc.c to include the correct header. At least one other OESF user had the same problem:
https://www.oesf.org/forum/index.php?topic=36147.msg295276#msg295276This concludes my instructions on compiling and flashing the kernel. I hope this helps some of you.