Linux Kernel for Surface RT. Build your own working Linux kernel for Surface RT.

Building a Kernel is an advanced process for most beginners. We suggest people to read this article first to understand kernel bootup on ARM devices. I'd also recommend reading Jay Carlson's excellent notes on Embedded Linux here - as an overview.

Get the kernel source

You may want to build grate-driver/linux instead of mainline. It includes the latest device tree and experimental patches for tegra in general. Take reference from the EFI compiling page and just use the different config settings from here. Recommened for users who know what they are doing.

Download and unpack the kernel and open the directory in terminal wget tar -xf linux-5.10.10.tar.xz cd linux-5.10.10/

Modify the source


This is very important a wrong devicetree can damage your device!

Go to ./arch/arm/boot/dts, this is the devicetree directory Place tegra30-microsoft-surfaceRT.dts there. Add the new devicetree to the build system by a adding: tegra30-microsoft-surfaceRT.dtb to ./arch/arm/boots/dts/Makefile below dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) +=(see image)

Configure the Kernel

SoC config

A basic configuration for Tegra SoC's can be loaded by using tegra_defconfig Type: make ARCH=arm tegra_defconfig This will place a .config file in the kernel root directory with the default config for Tegra CPUs.

Surface RT config

At the moment we use a "all inclusive" kernel. It consists of the kernel, devicetree and command-line parameters. This reduces amount of work the bootloader has to do and reduces the amount of error the bootloader could make. e.g. loading devicetree to wrong address.

This can be done with [g|x|menu]config or by simply modifying the lines below in the .config file

CONFIG_CMDLINE="root=/dev/mmcblk0p2 console=tty0 console=ttyS0,115200n8 [email protected] clk_ignore_unused earlyprintk initcall_debug"

Debug config


Optional: add#define DEBUG in the top of arch/arm/boot/compressed/head.S to enable decompressor output to see uart ouput as soon as possible

Build the kernel using command line

Type: make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j $(nproc) - $(nproc) sets the number of threads to your CPU core count

It asks for some further configuration:

Supplement the appended DTB with traditional ATAG information (ARM_ATAG_DTB_COMPAT) [N/y/?] (NEW) n
Kernel command line type
> 1. Use bootloader kernel arguments if available (CMDLINE_FROM_BOOTLOADER) (NEW)
choice[1-3?]: 1

If compiling was successful you should see some output similar to this: (This doesn't need to be a the end of the log. Scroll up a bit ;) ) CALL scripts/ CALL scripts/atomic/ CHK include/generated/compile.h Kernel: arch/arm/boot/Image is ready Kernel: arch/arm/boot/zImage is ready

Append devicetree

Append the devicetree to zImage to make a single Image which contains the kernel and the devicetree. This allows to use simpler bootloaders and minimizes errors that the bootloader can make.

cat ./arch/arm/boot/zImage ./arch/arm/boot/dts/tegra30-microsoft-surfaceRT.dtb > ./arch/arm/boot/zImageSRT

Your kernel with appended devicetree should be located at ./arch/arm/boot/zImageSRT

Build the kernel using shell script

You can create a .sh script in kernel root to speed up your workflow
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j $(nproc)
sleep 1
cat ./arch/arm/boot/zImage ./arch/arm/boot/dts/tegra30-microsoft-surfaceRT.dtb > ./arch/arm/boot/zImageSRT