The following kernel compilation guide was written for beginners and experts alike and will assist in:
- Compiling Custom TS Kernel
- Appendix I - Compiling Custom TS Kernel
- Appendix II - A Kernel Development Explanation
This document is time sensitive. That is, it's not to be used verbatim too far past the date written. Updates are applied to images and files/locations sometimes change. The principles generally stay the same, so keep this in the back of your mind while working through this guide.
BACKUP YOUR FILES AND IMAGES!
The following is a step-by-step guide to compiling a custom TS-Kernel specifically for the TS-7800. These steps have been verified and will work if they are followed in the exact, step-by-step order. This was written with beginners in mind, but may still be a bit too advanced for some. Remember to backup file and images so you may revert back to them if something goes wrong.
- Must be logged in as root on a Linux PC separate from the SBC
- These packages need to be installed for kernel compiling:
yum install ncurses-devel ncursesDebian/Ubuntu:
sudo apt-get install libncurses5-dev libncursesw5-dev
- TS-7800 SBC with JP1 = ON
- USB SD Card Reader
- Development PC with Linux installed
- The Cross Toolchain (ts7800-crosstool-linux-gnueabi-2005q3-2.tar.gz)
- The kernel Source(linux-2.6.21-ts-src-oct102008.tar.gz)
- ts7800_defconfig file for Kernel Options (Included in the kernel Source)
01.) Download the cross compile toolchain (EABI)from Technologic Systems: * wget ftp://ftp.embeddedarm.com/ts-arm-sbc/ts-7800-linux/cross-toolchains/ts7800-crosstool-linux-gnueabi-2005q3-2.tar.gz 02.) Extract to current working directory and remove old tar.gz file: * tar xvf ts7800-crosstool-linux-gnueabi-2005q3-2.tar.gz && rm ts7800-crosstool-linux-gnueabi-2005q3-2.tar.gz 03.) Obtain the TS-7800 kernel source tree * wget ftp://ftp.embeddedarm.com/ts-arm-sbc/ts-7800-linux/sources/linux-2.6.21-ts-src-oct102008.tar.gz 04.) Extract the TS-7800 kernel source tree (this is silent) * mkdir linux-2.6.21-ts && gzip -dc linux-2.6.21-ts-src-oct102008.tar.gz | tar xf - -C linux-2.6.21-ts/ 05.) Move into the newly extracted directory * cd linux-2.6.21-ts 06.) Edit the Makefile at the kernel root dir to point to the appropriate cross-compiler path. In our case, with the toolchain decompressed into the same directory as the kernel, we'll change line 186 of the Makefile to read: * CROSS_COMPILE ?= ../arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- 07.) Edit the scripts/mod/sumversion.c to include a definition to the PATH_MAX variable and set it to 1024. * #define PATH_MAX 1024 08.) Type "make ts7800_defconfig" to make the kernel with the options that Technologic Systems uses for the TS-7800 (More options can be found by listing the contents of arch/arm/configs) 09.) Type "make menuconfig" and edit the boot command line and other options of interest (optional) * For Example, to include CIFS support, use the arrow and Enter keys to navigate to Filesystems -> Network File Systems -> CIFS Support. Press "y" to include CIFS support into the kernel (alternatively, you could modularize the feature with "m" so you can enable or disable the module on demand which will also enable you to simply copy/paste the cifs.ko into the correct path in the kernel instead of copying the entire kernel (outlined below in appendix)). Keep hitting "exit" until you're prompted to save changes, choose "yes". 10.) Type "make" to compile the kernel 11.) The new kernel will be at "arch/arm/boot" in a compressed format called zImage (the uncompressed version is simply called Image, but it is REQUIRED that it be < 3.1MB (3145728 bytes in size). 12.) Copy the binary zImage to the second partition (in most cases, this is mounted as /dev/sdb2). This will erase any data which is on the MiniSD card now, so a backup is advised. * TO BACKUP: dd if=/dev/sdb2 of=../zImageBak * TO COPY zImage: dd if=arch/arm/boot/zImage of=/dev/sdb2 13.) At this point, insert the SD card in the TS-7800 and try to boot. If the image is working correctly, and you'd like to be able to use the TS-7800 independently of the SD card, you will need to copy the kernel to on-board flash. On the TS-7800, issue the following commands within the fastboot/initrd environment * createmtdboot 14.) Test by placing JP1 to the OFF position. You should have ">> Booting from onboard flash..." and the system should boot as expected.
In order to compile a separate kernel module and come out with a .ko file for inclusion in the already existing kernel, these are the steps to take following step 09 and ending at step 10 above. Note: Steps after step 02 are unverified/untested. They represent an accurate procedure which one would go through.
01.) Open menuconfig and modularize the kernel feature using "M". For example, to modularize cifs.ko, one would use the arrow and Enter keys to navigate to Filesystems -> Network File Systems -> CIFS Support. Press "M" to modularize CIFS support into the kernel then keep hitting "exit" until you're prompted to save changes, choose "yes". * make menuconfig 02.) Compile the kernel with the modules and copy the modules to the Linux PC * make && make modules && make modules_install 03.) Retrieve the module which was copied to the Linux PC with a command like cp so that it can be installed into the kernel on the SD card. * mkdir /mnt/SD4 * mount /dev/sdb4 /mnt/SD4 * cp /lib/modules/126.96.36.199/kernel/fs/cifs/cifs.ko /mnt/SD4 04.) Install the module into the kernel by copy and pasting from partition 4 of the card to partition 2 on the SBC. * cp -r /dev/tssdcardb4/cifs.ko /dev/tssdcardb2/lib/modules/188.8.131.52/kernel/fs/cifs/cifs.ko 05.) Finally, in order to use the new module, you must enable it. This can be included in a startup script such as linuxrc. * depmod * modprobe cifs.ko
When you compile source code there are always lots of options for toolchains (soft float vs hard float...) but the two major categories customers really need to know about are version of gcc and version of glibc. The version of gcc is important when compiling the kernel because the kernel is literally millions of lines of code, so a lot of corner cases are encountered in the kernel. As gcc releases new versions, they sometimes change the way they handle corner cases. For example, in one version they may call a certain corner case a warning and let the corner case go by, but in another version they might call it an error and stop compiling. So you need to make sure you have the version of gcc that is compatible with your particular kernel or you may get an error where another version would have given you a warning. For the 7800 use "arm-none-linux-gnueabi-gcc" as the toolchain. The version of glibc is important for people compiling user space applications. libc is the C library where all the standard C functions are implemented. In order to make things more efficient from a code size standpoint, Technologic Systems put one copy of the libc libraries in user space and let everyone share this one copy as opposed to giving everyone their own copy of the libc library. This is called dynamic linking. Static linking is where each binary has it's own copy of all the libraries it needs. When you compile a program you have to link against a version of the C libraries so the compiler can verify functions like printf() really do exist and you are passing the right arguments and lots of other details the compiler needs to know. If you link against a version of glibc when you compile it is a really good idea to ensure you have that same version of glibc running on the board. In theory glibc is backwards compatible so if you link against an older version you should be able to run using a newer version, but this isn't always the case. In embedded systems where stability is one of your major concerns taking risks is not a good idea. For really large projects like php or apache it's usually a good idea to take a look at what version of gcc is recommended also, although for the most part this is not an issue for user space programs because the probability of them having code for one of the corner cases gcc may have changed is much lower.
EABI vs OABI is an issue when you are doing things with floating point. Some CPUs have have floating point units(FPU) and some don't. If an FPU is present the hardware can do the math on floating point arithmetic(like an ALU) rather than software. Debian Linux has recently switched from OABI to EABI. An ABI specifies how binaries pass data to each other (basically what registers to use). EABI changed the way floating point parameters are passed, the reason they did this is like 80% of ARM CPUs don't have a floating point. OABI assumes a floating point unit was present, this was what Debian used by default so when a binary that was compiled for OABI tried to pass a floating point parameter to another binary it would try to pass the parameter in a floating point register. Well if no FPU is present then there are no floating point registers so as a result the CPU would issue an exception saying there is no such register. The Linux kernel would catch this exception with the idea that if there is no FPU then the kernel needs to perform the operation. This is very inefficient. EABI on the other hand supports both hardware with an FPU and hardware that doesn't have an FPU. The details are difficult, but basically if no FPU is present then the operation is performed by a library in software(libc). This is much more efficient than passing to a register that doesn't exist then to the kernel then back to user space. Now the problem is when binaries are compiled the toolchain that is used is EABI or OABI in the case of ARM. Since we use Debian we don't actually compile any of the userspace binaries(except the custom stuff we write). It's all compiled by Debian maintainers, so it's a really big advantage for people who want to do floating point arithmetic to have a toolchain and Debian file system that is EABI. Video is a very popular application that mostly uses floating point arithmetic.