(Compiling the GuruPlug Kernel)
 
(15 intermediate revisions by one user not shown)
Line 4: Line 4:
 
=== ARM Cross Compiler ===
 
=== ARM Cross Compiler ===
  
To compile the linux kernel for the GuruPlug, you must first have an ARM cross compiler installed. I use gcc-4.7-arm-linux-gnueabi-base that comes with Ubuntu 13.04. To install the compiler run:
+
To compile the Linux kernel for the GuruPlug, you must first have an ARM cross compiler installed. I use gcc-4.7-arm-linux-gnueabi-base that comes with Ubuntu 13.04. To install the compiler run:
  
 
<PRE>
 
<PRE>
Line 10: Line 10:
 
</PRE>
 
</PRE>
  
=== uBoot mkimage ===
+
=== U-Boot mkimage ===
  
The bootloader used on the GuruPlug is [http://www.denx.de/wiki/U-Boot u-boot]. u-boot has a special image format called uImage. It includes parameters such as descriptions, the machine/architecture type, compression type, load address, checksums etc. To make these images, you need to have a mkimage tool that comes part of the u-Boot distribution. Download u-boot, make and install the u-boot tools:
+
The bootloader used on the GuruPlug is [http://www.denx.de/wiki/U-Boot U-Boot]. U-Boot has a special image format called uImage. It includes parameters such as descriptions, the machine/architecture type, compression type, load address, checksums etc. To make these images, you need to have a mkimage tool that comes part of the U-Boot distribution. Download U-Boot, make and install the U-Boot tools:
  
 
<PRE>
 
<PRE>
Line 18: Line 18:
 
tar -xjf u-boot-latest.tar.bz2
 
tar -xjf u-boot-latest.tar.bz2
 
cd into u-boot directory
 
cd into u-boot directory
make tools
+
make tools-only
 
sudo install tools/mkimage /usr/local/bin
 
sudo install tools/mkimage /usr/local/bin
 
</PRE>
 
</PRE>
Line 31: Line 31:
  
 
<PRE>
 
<PRE>
# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.13.7.tar.xz
+
# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.17.tar.xz
# tar -xJf linux-3.13.7.tar.xz
+
# tar -xJf linux-3.18.17.tar.xz
# cd linux-3.13.7
+
# cd linux-3.18.17
 
</PRE>
 
</PRE>
  
Line 67: Line 67:
  
 
<PRE>
 
<PRE>
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
+
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=/home/cpeacock/export/rootfs-f12 modules_install
+
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=/home/cpeacock/export/rootfs-f12 modules_install
 
</PRE>
 
</PRE>
  
 
== Testing ==
 
== Testing ==
  
 +
To support your newer Linux Kernel with Device Tree Support, you must have an up-to-date u-Boot bootloader with Device Tree Support installed on your GuruPlug.
 +
 +
Please see [[GuruPlug_Upgrading_uBoot|Upgrading uBoot with Device Tree Support for the GuruPlug Server Plus]]
 +
 
=== TFTP Server ===
 
=== TFTP Server ===
  
Line 82: Line 86:
  
 
<PRE>
 
<PRE>
ln -s /path to linux/arch/arm/boot/uImage uImage-GuruPlug
+
# ln -s /path to linux/arch/arm/boot/uImage uImage-GuruPlug
ln -s /path to linux/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dtb uImage-GuruPlug.dtb
+
# ln -s /path to linux/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dtb uImage-GuruPlug.dtb
 
</PRE>
 
</PRE>
  
=== u-boot tftpboot ===
+
=== U-Boot tftpboot ===
  
 
To test your kernel, bring up a serial console to the GuruPlug. First we will need to configure the IP addresses. The ipaddr variable contains the IP address for the GuruPlug, while the serverip variable is the address of the TFTP server containing the kernel image.
 
To test your kernel, bring up a serial console to the GuruPlug. First we will need to configure the IP addresses. The ipaddr variable contains the IP address for the GuruPlug, while the serverip variable is the address of the TFTP server containing the kernel image.
Line 97: Line 101:
 
These variables can be saved to non-volatile memory to speed up development.
 
These variables can be saved to non-volatile memory to speed up development.
  
Next load the kernel image and device tree binary into memory:
+
Next load the kernel image and Device Tree BLOB into memory:
 
<PRE>
 
<PRE>
 
tftpboot 0x800000 uImage-GuruPlug.dtb
 
tftpboot 0x800000 uImage-GuruPlug.dtb
 
tftpboot 0x810000 uImage-GuruPlug
 
tftpboot 0x810000 uImage-GuruPlug
setenv bootcmd console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs
 
 
</PRE>
 
</PRE>
  
And boot from the memory location:
+
You will also require a root filesystem to do any serious testing. One option is to use the filesystem already in place (i.e. UBIFS on mtd2) as I have done below. However, it is unlikely to have your new kernel modules installed.
 +
 
 
<PRE>
 
<PRE>
bootm 0x810000 - 0x800000
+
setenv bootargs console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs
 
</PRE>
 
</PRE>
  
You may also require a root filesystem for debugging. One option is to use the filesystem already in place (i.e. UBIFS on mtd2). The preferred option is to export a root NFS filesystem. This has the added advantage as you can compile userland binaries on your development box, install them to the NFS export and have instant access to them on your target system.
+
The preferred option is to export a root NFS filesystem with your newly installed kernel modules installed. This has the added advantage as you can compile userland binaries on your development box, install them to the NFS export and have instant access to them on your target system.
  
== Common Issues ==
+
<PRE>
 +
setenv bootargs console=ttyS0,115200 root=/dev/nfs rw nfsroot=192.168.0.251:/home/cpeacock/export/rootfs ip=192.168.0.250:::::eth0
 +
</PRE>
  
=== Mainline Kernels 3.2 and later don't boot ===
+
Finally, you can boot the kernel from the memory:
 +
 
 +
<PRE>
 +
bootm 0x810000 - 0x800000
 +
</PRE>
  
If you are having trouble booting kernels 3.2 and later, then it is possible you have hit an issue with older versions of u-boot. Typically, the booting process will freeze just after the decompression of the kernel similar to below :
+
Hopefully you should yield results similar to the following:
  
 
<PRE>
 
<PRE>
Marvell>> bootm 0x800000
+
## Booting kernel from Legacy Image at 00810000 ...
## Booting kernel from Legacy Image at 00800000 ...
+
   Image Name:  Linux-3.13.7
   Image Name:  Linux-3.2.6
+
 
   Image Type:  ARM Linux Kernel Image (uncompressed)
 
   Image Type:  ARM Linux Kernel Image (uncompressed)
   Data Size:    2819096 Bytes = 2.7 MB
+
   Data Size:    3645136 Bytes = 3.5 MiB
 
   Load Address: 00008000
 
   Load Address: 00008000
 
   Entry Point:  00008000
 
   Entry Point:  00008000
 
   Verifying Checksum ... OK
 
   Verifying Checksum ... OK
 +
## Flattened Device Tree blob at 00800000
 +
  Booting using the fdt blob at 0x800000
 
   Loading Kernel Image ... OK
 
   Loading Kernel Image ... OK
OK
+
  Loading Device Tree to 0fffa000, end 0ffff21b ... OK
  
 
Starting kernel ...
 
Starting kernel ...
  
 
Uncompressing Linux... done, booting the kernel.
 
Uncompressing Linux... done, booting the kernel.
 +
Booting Linux on physical CPU 0x0
 +
Linux version 3.13.7 (cpeacock@max.beyondlogic.org) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) ) #4 PREEMPT Wed Mar 26 02:31:41 PDT 2014
 +
CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=00053977
 
</PRE>
 
</PRE>
  
To address this issue, in your .config file disable or comment out :
+
== Saving Kernel to Flash ==
 +
 
 +
Once your new Linux kernel has been thoroughly tested, you may want to permanently save it to flash.
 +
 
 +
To flash the kernel:
  
 
<PRE>
 
<PRE>
# CONFIG_ARM_PATCH_PHYS_VIRT
+
tftp 0x6400000 uImage-GuruPlug.dtb
 +
tftp 0x6410000 uImage-GuruPlug
 +
nand erase 0x100000 0x400000
 +
nand write.e 0x6400000 0x100000 0x400000
 
</PRE>
 
</PRE>
  
and add :
+
I've allocated the first 64Kbytes (0x10000) of the kernel space to the Flattened Device Tree blob.
 +
 
 +
The default environment variables on the GuruPlug is scripted to load a non-device tree kernel, i.e. bootm 0x6400000.
 +
 
 +
You may need to update the environment variables to load the new flattened device tree kernel.
  
 
<PRE>
 
<PRE>
CONFIG_EMBEDDED=y
+
setenv bootcmd '${x_bootcmd_kernel}; setenv bootargs ${x_bootargs} ${x_bootargs_root}; bootm 0x6410000 - 0x6400000;'
CONFIG_PHYS_OFFSET=0x0
+
saveenv
 
</PRE>
 
</PRE>
  
The fix is courtesy of the following links :
+
Your final environment variables should look something like:
  
[http://www.newit.co.uk/forum/index.php/topic,3049.msg8689.html#msg8689 Booting kernels 3.2 and later]
+
<PRE>
 +
Marvell>> printenv
 +
baudrate=115200
 +
bootcmd=${x_bootcmd_kernel}; setenv bootargs ${x_bootargs} ${x_bootargs_root}; bootm 0x6410000 - 0x6400000;
 +
bootdelay=3
 +
eth1addr=00:50:43:01:83:5f
 +
ethact=egiga0
 +
ethaddr=00:50:43:01:83:5e
 +
ipaddr=192.168.0.250
 +
serverip=192.168.0.251
 +
stderr=serial
 +
stdin=serial
 +
stdout=serial
 +
x_bootargs=console=ttyS0,115200
 +
x_bootargs_root=ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs
 +
x_bootcmd_ethernet=ping 192.168.2.1
 +
x_bootcmd_kernel=nand read.e 0x6400000 0x100000 0x400000
 +
x_bootcmd_usb=usb start
  
[http://lists.denx.de/pipermail/u-boot/2012-February/117020.html U-Boot PATCH v4 arm, arm-kirkwood: disable L2 cache before linux boot]
+
Environment size: 530/131068 bytes
 +
</PRE>

Latest revision as of 12:42, 4 July 2015

Prerequisites

ARM Cross Compiler

To compile the Linux kernel for the GuruPlug, you must first have an ARM cross compiler installed. I use gcc-4.7-arm-linux-gnueabi-base that comes with Ubuntu 13.04. To install the compiler run:

sudo apt-get install gcc-arm-linux-gnueabi

U-Boot mkimage

The bootloader used on the GuruPlug is U-Boot. U-Boot has a special image format called uImage. It includes parameters such as descriptions, the machine/architecture type, compression type, load address, checksums etc. To make these images, you need to have a mkimage tool that comes part of the U-Boot distribution. Download U-Boot, make and install the U-Boot tools:

wget ftp://ftp.denx.de/pub/u-boot/u-boot-latest.tar.bz2
tar -xjf u-boot-latest.tar.bz2
cd into u-boot directory
make tools-only
sudo install tools/mkimage /usr/local/bin

rootfs

After the kernel modules have been built, you will want to install them to your root filesystem. To speed up development, it is also a good idea to test the kernel via TFTP with a root NFS filesystem prior to committing the image to flash. Fedora has a pre-built ARM port which is ideal for this task. It can be downloaded from http://ftp.linux.org.uk/pub/linux/arm/fedora/rootfs/rootfs-f12.tar.bz2

Note: The default root password for the Fedora ARM root filesystem is "fedoraarm"

Compiling the GuruPlug Kernel

# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.17.tar.xz
# tar -xJf linux-3.18.17.tar.xz
# cd linux-3.18.17

Make and run the configuration menu:

# make ARCH=arm kirkwood_defconfig
# make ARCH=arm menuconfig

Customise your kernel. I enable the following:

Device Drivers --> Graphics Support --> Support for Frame Buffer Devices --> DisplayLink USB Framebuffer Support. 
Device Drivers --> Graphics Support --> Console display driver support --> Framebuffer Console support + Map the console to the primary display device
Device Drivers --> Memory Technology Devices (MTD) --> Enable UBI - Unsorted Block Images
File Systems --> Miscellaneous Filesystems --> UBIFS file system support
File Systems --> Miscellaneous Filesystems --> LZO compression support
File Systems --> Miscellaneous Filesystems --> ZLIB compression support

Networking support -> Networking options -->The IPv6 protocol

Device Drivers -> Network device support -> Turn off Wireless LAN

Once you have finished configuring your kernel, save the config. Then build it:

# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage dtbs -j4

Now build the modules and install them to a suitable path:

# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=/home/cpeacock/export/rootfs-f12 modules_install

Testing

To support your newer Linux Kernel with Device Tree Support, you must have an up-to-date u-Boot bootloader with Device Tree Support installed on your GuruPlug.

Please see Upgrading uBoot with Device Tree Support for the GuruPlug Server Plus

TFTP Server

Rather than flashing your newly created kernel to find out it doesn't work or it is not quite configured correctly, a better way to load the kernel into RAM and boot it from there. u-boot allows kernel images to be loaded via TFTP.

To speed up development, I create an 'export' directory. A TFTP server is then configured to use this directory as the TFTP root.

From the export directory, add symbolic links to the kernel images. This way, you can recompile the kernel and the new image is instantly available without having to move it.

# ln -s /path to linux/arch/arm/boot/uImage uImage-GuruPlug
# ln -s /path to linux/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dtb uImage-GuruPlug.dtb

U-Boot tftpboot

To test your kernel, bring up a serial console to the GuruPlug. First we will need to configure the IP addresses. The ipaddr variable contains the IP address for the GuruPlug, while the serverip variable is the address of the TFTP server containing the kernel image.

setenv ipaddr 192.168.0.250
setenv serverip 192.168.0.251

These variables can be saved to non-volatile memory to speed up development.

Next load the kernel image and Device Tree BLOB into memory:

tftpboot 0x800000 uImage-GuruPlug.dtb
tftpboot 0x810000 uImage-GuruPlug

You will also require a root filesystem to do any serious testing. One option is to use the filesystem already in place (i.e. UBIFS on mtd2) as I have done below. However, it is unlikely to have your new kernel modules installed.

setenv bootargs console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs

The preferred option is to export a root NFS filesystem with your newly installed kernel modules installed. This has the added advantage as you can compile userland binaries on your development box, install them to the NFS export and have instant access to them on your target system.

setenv bootargs console=ttyS0,115200 root=/dev/nfs rw nfsroot=192.168.0.251:/home/cpeacock/export/rootfs ip=192.168.0.250:::::eth0

Finally, you can boot the kernel from the memory:

bootm 0x810000 - 0x800000

Hopefully you should yield results similar to the following:

## Booting kernel from Legacy Image at 00810000 ...
   Image Name:   Linux-3.13.7
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    3645136 Bytes = 3.5 MiB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 00800000
   Booting using the fdt blob at 0x800000
   Loading Kernel Image ... OK
   Loading Device Tree to 0fffa000, end 0ffff21b ... OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0x0
Linux version 3.13.7 (cpeacock@max.beyondlogic.org) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) ) #4 PREEMPT Wed Mar 26 02:31:41 PDT 2014
CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=00053977

Saving Kernel to Flash

Once your new Linux kernel has been thoroughly tested, you may want to permanently save it to flash.

To flash the kernel:

tftp 0x6400000 uImage-GuruPlug.dtb
tftp 0x6410000 uImage-GuruPlug
nand erase 0x100000 0x400000
nand write.e 0x6400000 0x100000 0x400000

I've allocated the first 64Kbytes (0x10000) of the kernel space to the Flattened Device Tree blob.

The default environment variables on the GuruPlug is scripted to load a non-device tree kernel, i.e. bootm 0x6400000.

You may need to update the environment variables to load the new flattened device tree kernel.

setenv bootcmd '${x_bootcmd_kernel}; setenv bootargs ${x_bootargs} ${x_bootargs_root}; bootm 0x6410000 - 0x6400000;'
saveenv

Your final environment variables should look something like:

Marvell>> printenv
baudrate=115200
bootcmd=${x_bootcmd_kernel}; setenv bootargs ${x_bootargs} ${x_bootargs_root}; bootm 0x6410000 - 0x6400000;
bootdelay=3
eth1addr=00:50:43:01:83:5f
ethact=egiga0
ethaddr=00:50:43:01:83:5e
ipaddr=192.168.0.250
serverip=192.168.0.251
stderr=serial
stdin=serial
stdout=serial
x_bootargs=console=ttyS0,115200
x_bootargs_root=ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs
x_bootcmd_ethernet=ping 192.168.2.1
x_bootcmd_kernel=nand read.e 0x6400000 0x100000 0x400000
x_bootcmd_usb=usb start

Environment size: 530/131068 bytes