- Introduction
- Training and Workbench Setup
- The Kernel Source Code
- 6. Offical and Unofficial Kernel Sources
- 7. Why Are The Sources So Big?
- 8. Programming Religion
- 9. No C Library
- 10. Portability
- 11. Linux Internal API
- 12. Is It Free?
- 13. Advantages Of GPL Drivers
- 14. Advantages Of In-Tree Kernel Drivers
- 15. User Space Device Drivers
- 16. What’s In The Sources?
- 17. Browsing The Sources
- 18. LAB 1 : Getting Accustomed To Browsing The Sources
- 19. Configuring The Kernel
- 19.1. Kernel Configuration
- 19.2. Configuring Features As Modules
- 19.3. Kernel Option Types
- 19.4. Kernel Option Dependencies
- 19.5. Graphical Configuration Interface xconfig
- 19.6. Graphical Configuration Interface gconfig
- 19.7. Text Configuration Interface menuconfig
- 19.8. Text Configuration Interface nconfig
- 19.9. make oldconfig
- 19.10. Reverting To A Previous Configuration
- 20. Compiling The Kernel
- 21. Kernel Installation
- 22. Cross-Compiling The Kernel
- 23. LAB 2 : Setting Up The Beaglebone Black Board
- 23.1. Getting Comfortable With The Board
- 23.2. Downloading The Technical Documentation
- 23.3. Installing The Free Electrons Lab Data
- 23.4. Making A Bootable MicroSD Card
- 23.5. Reflashing The eMMC With The micro-SD Card
- 23.6. Setting Up Serial Communication With The Board
- 23.7. Setting Up Ethernet Communication With The Board
- 24. LAB 3 : Cross Compiling The Kernel And Booting It From The Workstation
- Linux Kernel Modules
This document is under active development!
If you find errors or omissions in this document, please don’t hesitate to send me a mail. |
This journal assumes you are comfortable with a linux environment as most of the published work here uses an Ubuntu distribution as the work station.
Introduction
This journal was started in order to document my exploration of embedded linux using a popular low-cost platform i.e. the BeagleBone Black. The end objective is to become well versed with embedded linux development on an ARM based embedded device.
1. About The Linux Kernel
I’m doing a (free) operating system (just a hobby, won’t be big and professional like gnu) for 386(486) AT clones. This has been brewing since April and is starting to get ready. I’d like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things).
The Linux kernel started off as a hobby project and by a Finnish national Linus Torvalds. It is today the OS powering the largest number of computers on the planet. It is used in phones, tablets, laptops, netbooks, routers, desktops, servers, supercomputers, embedded devices, consumer electronics, etc.
The development of the Linux kernel is carried out by an army of dynamic open source developers, the majority of which comprise of hobbyists. Significant contribution to the kernel is now coming from companies using the kernel. The development is still spearheaded by Linus who is employed by the Linux Foundation.
2. About BeagleBoard
BeagleBoard.org Foundation is a non-profit corporation which promotes open source software and open hardware. It was started by enthusiasts from TI with the aim of providing a powerful platform to design embedded solutions. The BeagleBone Black is their fourth board till date which offers a lot of possibilities in a small credit card size form factor.
3. About Free Electrons
Free Electrons is an engineering company consisting of embedded linux experts who support companies using Embedded Linux. They additionally conduct training workshops for companies on different topics such as Linux kernel and device driver development, Android system development, Yocto Project and OpenEmbedded development, etc. This journal uses the Free Electrons training material which they publish online to explore Embedded Linux with the BeagleBone Black board from TI.
Training and Workbench Setup
This section covers the setup software and hardware used in this journal. The sources of the training material and references are mentioned as well as details about how to procure the hardware.
4. Hardware
4.1. BeagleBone Black
The BeagleBone Black is the newest member in the BeagleBoard family. The board is designed to be a low sized small form factor board. The size of the board is comparable to the size of a credit card and it offers expansion headers to add headers called as capes similar to the Raspberry Pi.
The table below highlights the key onboard components of the board along with the connectors available on the board. The diagram of the table below is taken from the BeagleBone Black System Reference Manual.
5. Software
5.1. Ubuntu
To work with an embedded system you need a work station on which you can perform the various tasks that are required in the development life cycle. These tasks include:
-
Editing your build scripts and source code
-
Cross-compiling your source code for the embedded target
-
Transferring or accessing the cross-compiled application and libraries to or from the embedded target
-
Collecting debug information from the target
-
Communicating with the target remotely using its interfaces like serial, USB, network, etc..
In this document we use the popular Debian based Linux operating system, Ubuntu as our work station for all the tasks listed above. Ubuntu can be easily downloaded and installed on any PC or laptop.
Do not use a virtual machine runnning Ubuntu as your workstation
This document uses Ubuntu 14.04 running on a HP laptop. Use of a similar environment through a virtual machine runnning on VMWare or Oracle VirtualBox is not recommended. |
5.2. GIT
The source code management tool used by the Linux kernel community is GIT. To use GIT we need to install the packages required on our work station using the Advanced Packaging Tool(APT) using a command line terminal.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ sudo apt-get install git gitk git-email
Once the packages are successfully installed we will need to configure GIT with some basic information about our name and email address
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ git config --global user.name Conrad Gomes
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ git config --global user.email conrad.s.j.gomes@gmail.com
Further infomation about GIT can be obtained at:
http://git-scm.com/.
5.3. Free Electrons
Since we are going through the training material provided by Free Electrons
we’ll need to download their slides and lab data from their website link:
http://free-electrons.com/training/kernel/
As Free Electrons continues to improve on their training material, this journal will be based on the version available at the time of its writing:
The Kernel Source Code
This section covers details about the Linux Kernel source code. We will go through the source code, its structure and characteristics.
6. Offical and Unofficial Kernel Sources
The official source of the Linux Kernel is available at:
https://www.kernel.org/
The sources present in this website do not represent the entire spectrum of features and development that is taking place. Since the kernel is logically divided into sub-systems, each sub-system is maintained by a designated individual who has been involved with the sub-system and is trusted by Linus. So when the merge window opens these individuals who are termed as "maintainers" send pull requests to Linus to take in the patches from their repositories for merging with the mainline kernel tree. In some cases if the subsystem is large it may be divided into smaller subsystems which are managed by individuals designated as "sub-maintainers".
The official development repository for some sub-systems are given below:
-
MTD
Website: http://www.linux-mtd.infradead.org/index.html
GIT: git://git.infradead.org/linux-mtd.git -
MIPS
Website: http://www.linux-mips.org/wiki/Main_Page
GIT: git://git.linux-mips.org/pub/scm/ralf/linux.git -
USB
Website: http://www.linux-usb.org/
GIT: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/patches.git
6.1. Cloning the Linux Tree With GIT
Now that GIT is present in the workstation we can get the main development tree of the Linux kernel as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
And if you’re in a corporarte environment or if your firewall blocks out the network port for git you can use http instead as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ git clone http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
The whole process should take a while so you can go for a small coffee break and come back. Comparitively using git is recommended as it is faster than http
If you happen to have a copy of the Linux GIT repository all you have to do is pull in the latest changes
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cd ~/git/linux
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git checkout master
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git pull
Once you have the Linux GIT repository you can pull the latest changes by by running git pull.
6.2. Using Stable Releases
Typically when we are developing a project we reuse multiple projects to build our application on top of. Similarly since we will be learing about Embedded Linux we cannot use the tip of the tree as it is the latest but not the stablest version of the kernel.
With GIT we don’t have to clone the whole repository all over again. Instead we can add a reference to a remote tree to our existing clone and fetch all the commits which are unique in that repository. As the stable release is derived from the mainline tree we can add a remote to our repository as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git remote -v (1)
origin git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git (fetch)
origin git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git (push)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git remote add stable git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git remote -v
origin git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git (fetch)
origin git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git (push)
stable git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git (fetch) (3)
stable git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git (push)
1 | git remote -v lists the remotes. By default the git repository from which the repository was cloned will be the main remote |
2 | git remote add adds a new remote with the name stable |
3 | git remote -v lists the new added remote |
The last part is fetching the unique commits in the stable remote. This command should take a while.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git fetch stable
7. Why Are The Sources So Big?
One of the reasons why cloning the kernel sources takes so long is that the Linux Kernel source code is BIG. This is because the Kernel source code contains many subsystems, frameworks, drivers, network protocols and supports many different processor architectures.
7.1. Size Comparison of Different Kernel Source Directories
If we check the disk usage per directory in the Linux Kernel source code we get the distribution below. We’ll go through the type of source code in each of those directories in a later section.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ du -s ./*/ | sort -nr
3084600 ./drivers/
723496 ./net/
589520 ./fs/
275636 ./arch/
260960 ./sound/
84020 ./kernel/
52264 ./security/
38628 ./include/
36340 ./crypto/
28968 ./Documentation/
27616 ./lib/
25984 ./mm/
17768 ./block/
8920 ./firmware/
8440 ./tools/
4356 ./scripts/
3760 ./ipc/
3720 ./init/
2596 ./virt/
248 ./samples/
92 ./usr/
8. Programming Religion
The Linux Kernel is written primarily in C with a little assembly code too. The source code is written in a version of C supported by Gnu Compiler Collection or GCC. Therefore the Linux Kernel source can not be compiled with all C compilers.
The assembly code comprises of small sections of code and is basically the GCC’s "AT&T-style" syntax of target architecture which will run the kernel.
Even though the Linux Kernel has certain frameworks designed with Object Oriented Principles in mind it is not written in C. For further understanding on why C is still not used please see the following link: http://www.tux.org/lkml/#s15-3
And on a lighter note …
In fact, in Linux we did try C++ once already, back in 1992.
It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.
The fact is, C++ compilers are not trustworthy. They were even worse in 1992, but some fundamental facts haven’t changed:
the whole C++ exception handling thing is fundamentally broken. It’s especially broken for kernels.
any compiler or language that likes to hide things like memory allocations behind your back just isn’t a good choice for a kernel.
you can write object-oriented code (useful for filesystems etc) in C, without the crap that is C++.
In general, I’d say that anybody who designs his kernel modules for C is either (a) looking for problems (b) a C bigot that can’t see what he is writing is really just C anyway (c) was given an assignment in CS class to do so.
Feel free to make up (d).
19 Jan 2004
9. No C Library
The Linux Kernel is a single program which has its own routines to perform common functions. It does not use any user space library like stdlib, rather it has equivalent functions that enable it to achieve the same results.
In place of the standard C functions like printf(), memset(), malloc() there are functions like printk(), memset(),kmalloc() in the source code.
10. Portability
One of the Linux Kernel key features is portability and hardware support. It supports a wide variety of architectures and to achieve this the source code should be portable across architectures. The architecture specific code is all located in the arch/ directory. The remaining code in all the other directories has to be portable across all architectures.
To achieve portability there are hardware abstraction API for specific features:
-
Endianess
-
cpu_to_be32()
-
cpu_to_le32()
-
be32_to_cpu()
-
le32_to_cpu()
-
-
I/O Memory Access
-
Memory barriers
-
DMA API to flush and invalidate caches
Since the Linux Kernel is designed to run on any processor the use of floating point expressions is not allowed. As an example consider the most popular embedded architecture i.e. ARM, it does not have a floating point unit.
11. Linux Internal API
One of the main reasons for having drivers in-tree i.e. present along with the sources of the Linux Kernel is that the internal Linux API may be changed at any point in time and if a change is proposed and implemented the developer responsible for the API change will also have to take the ownership of changing all the modules and drivers which use the changed API. In the case of an out-of-tree driver the work will be owned by the driver owner and any time a change occurs the driver will not compile with the latest kernel source code.
Having said that the Linux Kernel external API i.e. kernel to userspace API like system calls, /proc, /sys does not change and is considered to protect the user space applications who depend on it.
12. Is It Free?
The Linux Kernel is licensed under GNU General Public License version 2. This license defines the Linux Kernel as Free Software as defined by the Free Software Foundation.
-
If you redistribute the software you have to do so under the same license irrespective of whether it is modified or unmodified.
-
If you make modifications to the Linux Kernel you have to release it under the same license.
-
You only have to do so when your device with the kernel start getting distributed
-
You only have to license it to your customers and not necessarily the whole world.
-
It is illegal to distribute a binary kernel with statically compiled proprietary drivers.
-
Proprietary drivers are frowned upon by the Linux Kernel community as it goes against the philosophy of the GPL license.
13. Advantages Of GPL Drivers
-
It is possible to reuse software from other GPL drivers to write a new GPL driver
-
A GPL driver has more contributors, testers, reviewers and maintainers thereby making it more robust.
-
Once the driver is accepted it is easily shipped and distributed by others who are using the Linux Kernel.
-
A pre-compiled driver will always have to catch up with the latest kernel devlopments leaving users of the driver at a loss as they can’t upgrade their kernel with ease in order to use the latest source with new features
-
Making a driver GPL compliant avoids any potential legal hastles
14. Advantages Of In-Tree Kernel Drivers
-
Acceptance of a driver into the mainline kernel is a step that must be done by developers who have developed a GPL compatible driver.
-
This allows the developer to release the ownership of maintaining the kernel driver to the community. This reduces the cost of maintainence.
-
The source of the kernel driver is easily accessible by anyone, as the kernel code is widely published.
15. User Space Device Drivers
It is possible to develop a user space device driver. There are several scenarios in which a user space device driver is developed:
-
The device driver does not depend on any of the frameworks exposed by the Linux Kernel.
-
The device driver is used by only one application and is not required by any other application.
-
The kernel provides a simple interface with which the user space device driver can control and read the hardware for which it is developed.
15.1. Examples Of User Space Device Drivers
Certain busses have interfaces exposed by the kernel which can be used to develop a user space device driver if the hardware is connected to that bus:
-
USB with libusb, http://www.libusb.org/
-
SPI wiht spidev, Documentation/spi/spidev
-
I2C with i2cdev, Documentation/i2c/dev-interface
-
Memory-mapped devices with UIO, including interrupt handling, http://free-electrons.com/kerneldoc/latest/DocBook/uio-howto/
On certain SOCs the vendor also provides a user space device driver along with a kernel driver which has access to other processors in the SOC which are running a firmware for highly specialized applications.
15.2. The Good And The Bad Of User Space Device Drivers
The Good
-
The driver can be written in any programming language or script.
-
The driver can be kept proprietary.
-
The driver runs in user space as an application or daemon.
-
The driver cannot bring down the kernel.
The Bad
-
Handling interrupts from the hardware is non-trivial resulting in some sort of polling mechanism.
-
The interrupt latency is larger when compared to a kernel device driver.
16. What’s In The Sources?
We’ll briefly go through each of the sources in the Linux Source Code and try to get an understanding of the overall structure of the source tree. Each directory is a placeholder for certain code, scripts and files which serve to make up the Linux Kernel project.
- arch/<ARCH>
-
Architecture specific code. All code that has anything to do with the processor the kernel is running on is present in this directory
-
arch/<ARCH>/mach-<machine>, machine/board specific code
-
arch/<ARCH>/include/asm, architecture-specific headers
-
arch/<ARCH>boot/dts, Device Tree source files for certain architecture
-
- block/
-
Code relate to block device drivers for hard disk drives and others
- COPYING
-
License of the Linux Kernel.
- CREDITS
-
Who Did what?
- crypto/
-
Cryptographic libraries
- Documentation/
-
Documentation for all things about the Linux Kernel
- drivers/
-
Device drivers except for sound which has its own directory below
- firmware/
-
Legacy: firmware images extracted from old drivers
- fs/
-
Source code for various filesystems (ext2/ubifs/etc..)
- include/
-
Kernel headers
- include/linux/
-
Linux Kernel core headers
- include/uapi/
-
User space API headers
- init/
-
Code related to the kernel initaliazation. Includes the main.c
- ipc/
-
Code responsible for allowing inter process communication
- Kbuild
-
Part of the build system
- Kconfig
-
Top level description file for configuration parameters
- kernel/
-
The core of the Linux Kernel
- lib/
-
Useful library routines (crc32…)
- MAINTAINERS
-
Maintainers of different subsystems of the kernel
- Makefile
-
Top level makefile
- mm/
-
Memory management code
- net/
-
Network support code
- README
-
Overview and building instructions. Read once atleast.
- REPORTING-BUGS
-
Procedure to report bugs with the Linux Kernel
- samples/
-
Sample code of usage of frameworks and kernel code
- scripts/
-
Useful scripts for internal or external use
- security/
-
Support for security features like SELinux
- sound/
-
Sound support code and drivers
- tools/
-
Code for various user space tools
- usr/
-
Code to generate an initramfs cpio archive file
- virt/
-
Virtualization support (KVM)
17. Browsing The Sources
One of the most common tasks required by any developer is the ability to browse a project and search for:
-
A specific symbol such as a function name or variable name
-
The calling function of a function
-
The function definition using a function call point
-
An include file in the project from its declaration in source code
-
A pattern of text
17.1. Cscope
One such tool is Cscope which allows us to browse the Linux source code with ease from editors like vim, emacs and also independently using only cscope.
17.2. LXR
This is a generic indexing tool and code browser which is available as a web service. It supports both C and C++ and it makes it easy to search for declarations, definitions and symbols. A good examples of LXR with the Linux Kernel in action is through the Free Electrons LXR Site and further information abouit LXR can be obtained from its sourceforge page.
18. LAB 1 : Getting Accustomed To Browsing The Sources
This is a hands on session taken from the Free Electrons labs with the following objectives
|
18.1. Creating A Branch To A Particular Stable Kernel Version
In order to get the list of branches on our stable remote tree we have to enter the Linux Kernel source tree and use the git branch command as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cd ~/git/linux
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git branch -a
* master (1)
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/stable/linux-2.6.11.y (2)
remotes/stable/linux-2.6.12.y
.
.
remotes/stable/linux-3.9.y
remotes/stable/master
1 | Our source code is currently pointing to the master branch |
2 | Remote stable branch remotes/stable/linux-2.6.11.y |
We will be working with the 3.13 stable branch and so we will use the remote branch remotes/stable/linux-3.13.y from the list of branches displayed.
Before we do anything let us check the version of our master branch using the top level Makefile in the source code. Using vim or your favourite editor or head examine the first few lines of the Makefile
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ head Makefile
VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
EXTRAVERSION = -rc4
NAME = Diseased Newt
.
.
We can see the version of our master branch is at 3.18.0 -rc4 and the name of the release is "Diseased Newt". Now let us create a local branch starting from the stable remote branch of 3.13.y. The following command uses git checkout to checkout the stable remote branch stable/linux-3.13.y as a local branch with the name 3.13.y.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git checkout -b 3.13.y stable/linux-3.13.y (1)
Checking out files: 100% (27044/27044), done.
Branch 3.13.y set up to track remote branch linux-3.13.y from stable.
Switched to a new branch '3.13.y' (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git branch -a (3)
* 3.13.y (4)
master
remotes/origin/HEAD -> origin/master
remotes/origin/master
.
.
1 | Command to checkout the stable remote branch as a local branch |
2 | The switch to the new branch takes place successfully |
3 | We list all the branches again |
4 | The git repository now points to the 3.13.y local branch |
Once again let us examine the first few lines of the top level Makefile. We can now see the version is at 3.13.11 and the name of the release is "One Giant Leap for Frogkind". So we have successfully managed to create a branch pointing to a stable release of the Linux Kernel source code.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ head Makefile
VERSION = 3
PATCHLEVEL = 13
SUBLEVEL = 11
EXTRAVERSION =
NAME = One Giant Leap for Frogkind
.
.
18.2. Searching Tools
There are several tools that can be used to browse the kernel code and search. We will demonstrate the commands used with examples taken from the labs.
18.2.1. Using Find
The find utility can be used to search for a specific file name. The only catch being the name or pattern of the file needs to be known. For instance say you want to locate the logo of Linux in the source code.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ find . -name "*.gif" -o -name "*.jpg" -o -name "*.png" -type f
./Documentation/logo.gif
We use popular file formats to locate pictures in the source code and coincidentally there is one file in the Documentation directory with the name logo.gif.
18.2.2. Using Git-Grep
The git-grep command can be used to search within a git project. For instance if we want to search for the name of the maintainer of MVNETA network driver we would use it as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git grep MVNETA (1)
MAINTAINERS:MARVELL MVNETA ETHERNET DRIVER (2)
arch/arm/configs/mvebu_defconfig:CONFIG_MVNETA=y
drivers/net/ethernet/marvell/Kconfig: This driver is used by the MV643XX_ETH and MVNETA drivers.
drivers/net/ethernet/marvell/Kconfig:config MVNETA
.
.
.
1 | We search for MVNETA with git grep |
2 | We get the maintainers as MARVELL for MVNETA ETHERNET DRIVER |
To get line numbers for the references of the regex being searched we have to set the environment for git. This can be done locally (--local) specific to the git project or globally(--global) for all git projects on the workstation.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git config --local grep.lineNumber true (1)
1 | Enabling line numbers in the search in my local linux git clone |
It is possible to search in a specific branch of the project with git-grep. For instance let us try to find the platform_device_register function in all header files in the linux project in the branch remotes/stable/linux-3.7.y
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git grep -e platform_device_register remotes/stable/linux-3.7.y -- '*.h' (1)
remotes/stable/linux-3.7.y:arch/arm/mach-ux500/devices-common.h:99: return platform_device_register_full(&pdevinfo);
remotes/stable/linux-3.7.y:arch/arm/mach-ux500/devices-common.h:123: return platform_device_register_full(&pdevinfo);
remotes/stable/linux-3.7.y:arch/arm/mach-ux500/devices-common.h:140: platform_device_register_full(&pdevinfo);
remotes/stable/linux-3.7.y:arch/arm/mach-ux500/devices-db8500.h:26: return platform_device_register_resndata(parent, "nmk-ske-keypad", -1,
remotes/stable/linux-3.7.y:arch/arm/plat-mxc/include/mach/devices-common.h:31: return platform_device_register_full(&pdevinfo);
remotes/stable/linux-3.7.y:include/linux/platform_device.h:43:extern int platform_device_register(struct platform_device *); (2)
remotes/stable/linux-3.7.y:include/linux/platform_device.h:69:extern struct platform_device *platform_device_register_full(
remotes/stable/linux-3.7.y:include/linux/platform_device.h:73: * platform_device_register_resndata - add a platform-level device with
remotes/stable/linux-3.7.y:include/linux/platform_device.h:86:static inline struct platform_device *platform_device_register_resndata(
remotes/stable/linux-3.7.y:include/linux/platform_device.h:102: return platform_device_register_full(&pdevinfo);
remotes/stable/linux-3.7.y:include/linux/platform_device.h:106: * platform_device_register_simple - add a platform-level device and its resources
remotes/stable/linux-3.7.y:include/linux/platform_device.h:127:static inline struct platform_device *platform_device_register_simple(
remotes/stable/linux-3.7.y:include/linux/platform_device.h:131: return platform_device_register_resndata(NULL, name, id,
remotes/stable/linux-3.7.y:include/linux/platform_device.h:136: * platform_device_register_data - add a platform-level device with platform-specific data
remotes/stable/linux-3.7.y:include/linux/platform_device.h:151:static inline struct platform_device *platform_device_register_data(
remotes/stable/linux-3.7.y:include/linux/platform_device.h:155: return platform_device_register_resndata(parent, name, id,
1 | Expression searches for platform_device_register declaration in remotes/stable/linux-3.7.y |
2 | The function is declared on line 43 in include/linux/platform_device.h in the branch linux-3.7.y |
If we compare it to one of the older stable branches of remotes/stable/linux-2.6.11.y we get fewer header files with reference to the function name.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/git/linux$ git grep -e platform_device_register remotes/stable/linux-2.6.11.y -- '*.h' (1)
remotes/stable/linux-2.6.11.y:include/asm-ppc/ppc_sys.h:54:/* Update all memory resources by paddr, call before platform_device_register */
remotes/stable/linux-2.6.11.y:include/asm-ppc/ppc_sys.h:58:/* Get platform_data pointer out of platform device, call before platform_device_register */
remotes/stable/linux-2.6.11.y:include/linux/device.h:380:extern int platform_device_register(struct platform_device *); (2)
remotes/stable/linux-2.6.11.y:include/linux/device.h:392:extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int);
1 | Expression searches for platform_device_register declaration in remotes/stable/linux-2.6.11.y |
2 | The function is declared on line 380 in include/linux/platform_device.h in the branch linux-2.6.11.y |
18.2.3. Using Linux Cross Reference
We can make use of an automated tool like Linux Cross Reference or LXR as well:
-
Identifier search: http://lxr.free-electrons.com/ident
-
Free text search: http://lxr.free-electrons.com/search
19. Configuring The Kernel
The kernel source code contains code to support many filesystems, device drivers, network protocols, architectures, etc. The source code can be configured to chose which features are required based on the type of applications that will be run in user space.
Additionally the kernel configuration will also support test code that may be run to validate device drivers in the system. For example the MTD system has several kernel modules which can be loaded to validate the implementation of the mtd device driver code for the flash storage in the system.
To support this type of configuration there are a series of Makefiles present in the kernel source code. However to start the configuraton and build we would only be required to work with the top level Makefile.
There are various targets defined in the top level Makefile which can control the configuration, build and installation of the Linux kernel.
To get a sense of the number of targets available we can run make help to see all the targets.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make help | head
Cleaning targets:
clean - Remove most generated files but keep the config and
enough build support to build external modules
mrproper - Remove all generated files + config + various backup files
distclean - mrproper + remove editor backup and patch files
Configuration targets:
config - Update current config utilising a line-oriented program
nconfig - Update current config utilising a ncurses menu based program
menuconfig - Update current config utilising a menu based program
.
.
.
19.1. Kernel Configuration
The process of configuring the Linux Kernel includes modifying the configuration file located at the root of the source code. This file is named .config. The dot at the beginning of the file name indicates that it is a hidden file.
The syntax of this file is in the form of simple key value pairs as shown in the example below:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ head .config (1)
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 3.12.0-rc7 Kernel Configuration
#
# CONFIG_64BIT is not set (2)
CONFIG_X86_32=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf32-i386"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
.
.
.
1 | Command to display the first lines of the .config file |
2 | # is used to comment out key values in the configuration file |
An important point to note is that because options have dependencies it is not advisable to edit the .config file by hand. Preferably use the available configuration interfaces.
- Graphical Interfaces
-
make xconfig OR make gconfig
- Text/Shell Interfaces
-
make menuconfig OR make nconfig
It doesn’t make any difference which is used and we can shift between either of the interfaces as they all edit the same .config file.
19.1.1. Kernel Configuration In The System
The configuration of a GNU/Linux distribution is usually present along with the kernel image in the /boot/ directory.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ uname -r (1)
3.13.0-45-generic (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ ls -l /boot/config-3.13.0-45-generic (3)
-rw-r--r-- 1 root root 169818 Jan 14 01:53 /boot/config-3.13.0-45-generic (4)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$
1 | uname -r is the command to get the kernel running on the system |
2 | The kernel running is 3.13.0-45-generic |
3 | Listing the configuration file of this kernel in /boot/ |
4 | The configuration file is config-3.13.0-45-generic |
19.2. Configuring Features As Modules
Upon configuring the kernel source and completion of the build we get a single image which represents the kernel and all the features it is configured for. However it is possible to configure some of the features such as device drivers, filesystems, driver tests, etc. as separate entities called kernel modules.
By configuring certain features as modules we are able to keep the size of the kernel to a minimum. Kernel modules can be loaded from user space to support certain applications on execution or on insertion of certain devices into the system buses like USB, PCI, etc..
Therefore in the configuration of certain features it is possible to select if the feature needs to be compiled as a kernel module. All kernel modules will have to be stored in a file system and will have to be loaded into the running kernel by some user space application or script.
An important point to note in choosing if a feature should be compiled as a module is the latency with which the feature needs to be activated from boot of the system. As the kernel module is stored in a filesystem, it will not be loadable until the filesystem is mounted in the kernel.
19.3. Kernel Option Types
When selecting different features and configuring the kernel we come across different types based on the information required to complete the configuration.
- bool
-
true or false to indicate presence or absence of the feature respectively.
- tristate
-
true or false similar to bool option types and also a third state i.e. module to indicate it is a kernel module.
- int
-
If an integer value is required in the configuration of the feature.
- hex
-
If a hexadecimal value is required in the configuration of the feature.
- string
-
If a string value is requried in the configuration of the feature.
19.4. Kernel Option Dependencies
There will be dependencies between different kernel objects. To describe the dependency there are two types:
- depends on dependencies
-
The option that is dependent on another remains invisible until the later is enabled.
- select dependencies
-
The option on selection automatically selects the object on which it depends on in the configuration.
19.5. Graphical Configuration Interface xconfig
The xconfig configuration utitlity which uses Qt is invoked when running make xconfig in the root directory. If we try to invoke it we get the following error:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cd ~/Git/linux
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make xconfig
CHECK qt (1)
* Unable to find the QT4 tool qmake. Trying to use QT3
*
* Unable to find any QT installation. Please make sure that
* the QT4 or QT3 development package is correctly installed and
* either qmake can be found or install pkg-config or set
* the QTDIR environment variable to the correct location. (2)
*
make[1]: *** No rule to make target `scripts/kconfig/.tmp_qtcheck', needed by `scripts/kconfig/qconf.o'. Stop.
make: *** [xconfig] Error 2
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$
1 | The target rule checks for qt |
2 | A nice description of what is probably wrong with our Ubuntu distribution |
Ok we need to install Qt in our system. The dependencies are libqt4-dev and g++. For older kernel sources the dependencies are libqt3-mt-dev.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ sudo apt-get install libqt4-dev g++ (1)
Reading package lists... Done
Building dependency tree
Reading state information... Done
.
.
.
Setting up libqtwebkit-dev (2.3.2-0ubuntu7) ...
Processing triggers for libc-bin (2.19-0ubuntu6.5) ...
1 | Installing the prerequisites |
Again we try running make xconfig and see the graphical interface as shown in the screen capture below:
It is possible to search for a particular feature using the search interface. This can be invoked with a CTRL + F keyboard combination.
19.6. Graphical Configuration Interface gconfig
Another graphical interface is the gconfig target.This GTK based configuration gives the following error when we invoke it:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make gconfig (1)
*
* Unable to find the GTK+ installation. Please make sure that
* the GTK+ 2.0 development package is correctly installed...
* You need gtk+-2.0, glib-2.0 and libglade-2.0. (2)
*
make[1]: *** No rule to make target `scripts/kconfig/.tmp_gtkcheck', needed by `scripts/kconfig/gconf.o'. Stop.
make: *** [gconfig] Error 2
1 | We invoke the target gconfig of the root directory makefile |
2 | A helpful message indicates a missing GTK+ installation in our Ubun |
In this case we have to install the debian package libglade2-dev
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ sudo apt-get install libglade2-dev
[sudo] password for conrad:
no talloc stackframe at ../source3/param/loadparm.c:4864, leaking memory
Reading package lists... Done
Building dependency tree
Reading state information... Done
.
.
.
19.7. Text Configuration Interface menuconfig
This configuration interface requires no graphical interface and only requires the libncurses-dev debian package to be installed. This interface is popular with other projects such as Linux Target Image Builder (LTIB), Busybox, OpenWrt, etc.. It works well enough for us to ignore the graphical interfaces. It is brought up using a make menuconfig command in the root directory.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make menuconfig
We get the following screen shot one the interface is invoked from the shell.
Searching with the menuconfig interface is done by hitting the '/' key similar to vim. Once the search page is displayed we can enter a key word for the search.
The results of the search are displayed as follows:
19.8. Text Configuration Interface nconfig
Another similar test based configuration interface is nconfig with the same dependency on libncurses_dev debian package. Again to invoke the interface we will have to use make nconfig.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make nconfig
We get the following screen shot once the interface is invoked from the shell.
19.9. make oldconfig
If we are upgrading to a newer release and use the .config file from an older release of the Linux kernel then we need to run make oldconfig. This will inform us of the configuration settings that are irrelevant in the newer release and if there are newer features or parameters then it will prompt us asking for appropriate values for these settings.
Another scenario in which make oldconfig may come in use is if we modify the .config file by hand.
19.10. Reverting To A Previous Configuration
If we mess up our configuration and build a kernel that is unusable then we can revert to the older configuration that the kernel was built. This is done by copyting the .config.old file which gets created if we use any of the configuration interfaces available. All the interfaces save a copy of the existing configuration file .config as a back up in .config.old
20. Compiling The Kernel
After configuring the kernel with one of the configuration interfaces we can proceed to build the kernel by issuing a make command in the root directory. If blessed with multiple CPU cores then the build can be speed up using a make -j 4 command which instructs make to run 4 jobs in parallel.
After the build the following will be generated:
- vmlinux
-
Raw and uncompressed image which can be used for debugging purposes. This image cannot be booted.
- arch/<ARCH>/boot/*Image
-
The final kernel image which can be booted e.g. bzImage for x86 and zImage for ARM. There may also be compressed images generated.
- arch/<ARCH>/boot/dts/*.dtb
-
Compiled Device Tree files for certain architectures. This will be loaded by the bootloader before the kernel image.
- kernel modules(*.ko)
-
This will be generated in the directory corresponding to the driver/feature for which module type of configuration option was selected.
21. Kernel Installation
A kernel compiled for the host machine on which it is built can be installed in the system by issuing a make install after the build is successful. To install the kernel image we would required root permissions.
The installation includes the following:
- /boot/vmlinuz-<version>
-
The compressed kernel image. This is copied from the arch/<ARCH>/boot directory.
- /boot/System.map-<version>
-
This file stores the kernel symbols along with their addresses and will be handy in the event of a Kernel panic
- /boot/config-<version>
-
This is the configuration file .config saved along with the compiled kernel
The installation may also reconfigured the bootloader to take the new kernel settings so that on the next boot the new kernel will be visible.
21.1. Kernel Module Installation
Along with the kernel the compiled modules will also have to be installed in the system. To achieve this there is a target modules_install which can be executed after executing the install target of the root makefile.
The kernel modules and related files are installed in the /lib/modules/<version>/ directory. If we explore this directory we will see the following:
- kernel/
-
This directory contains a directory structure similar to the kernel source code. The kernel modules will be saved in the same directory structure as the source from which they were built.
- modules.alias
-
Aliases for the modules for loading utilities. An example of the contents of this file is given below:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ head /lib/modules/3.13.0-45-generic/modules.alias
# Aliases extracted from modules themselves.
alias char-major-10-134 apm
alias aes-asm aes_i586
alias aes aes_i586
alias twofish-asm twofish_i586
alias twofish twofish_i586
alias salsa20-asm salsa20_i586
alias salsa20 salsa20_i586
alias serpent serpent_sse2_i586
alias aes aesni_intel
- modules.dep
-
Highlights the dependencies between modules. This will be used by modprobe to choose which kernel modules have to be loaded before loading a particular module. In the example below mce_inject.ko has no dependency and can be loaded without any issue. But twofish-i586.ko depends on twofish_common.ko which must be loaded first.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ head /lib/modules/3.13.0-45-generic/modules.dep
kernel/arch/x86/kernel/cpu/mcheck/mce-inject.ko:
kernel/arch/x86/kernel/msr.ko:
kernel/arch/x86/kernel/cpuid.ko:
kernel/arch/x86/kernel/apm.ko:
kernel/arch/x86/crypto/glue_helper.ko:
kernel/arch/x86/crypto/aes-i586.ko:
kernel/arch/x86/crypto/twofish-i586.ko: kernel/crypto/twofish_common.ko
kernel/arch/x86/crypto/salsa20-i586.ko:
kernel/arch/x86/crypto/serpent-sse2-i586.ko: kernel/crypto/xts.ko kernel/crypto/serpent_generic.ko kernel/crypto/lrw.ko kernel/crypto/gf128mul.ko kernel/arch/x86/crypto/glue_helper.ko kernel/crypto/ablk_helper.ko kernel/crypto/cryptd.ko
kernel/arch/x86/crypto/aesni-intel.ko: kernel/arch/x86/crypto/aes-i586.ko kernel/crypto/xts.ko kernel/crypto/lrw.ko kernel/crypto/gf128mul.ko kernel/crypto/ablk_helper.ko kernel/crypto/cryptd.ko
- modules.symbols
-
Describes the kernel module to which a symbol belongs. It can be useful during debugging of a Kernel panic. For example we can see that cfg80211_report_obss_beacon belongs to the cfg80211 kernel module.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ head /lib/modules/3.13.0-45-generic/modules.symbols
# Aliases for symbols, used by symbol_request().
alias symbol:cfg80211_report_obss_beacon cfg80211
alias symbol:drm_dp_link_train_channel_eq_delay drm_kms_helper
alias symbol:VBoxHost_RTThreadPreemptDisable vboxdrv
alias symbol:__twofish_setkey twofish_common
alias symbol:get_wd_exp_mode_sd bpctl_mod
alias symbol:hsi_register_controller hsi
alias symbol:mlx4_db_free mlx4_core
alias symbol:sdhci_remove_host sdhci
alias symbol:videobuf_dma_init_kernel videobuf_dma_sg
21.2. Cleaning Up
There are several targets that are used to clean up files that have been generated by the configuration and compilation of the Linux kernel source code.
- make clean
-
This will remove all the generated object code files to allow us to rebuilt the kernel.
- make mrproper
-
Remove all the generated files including the configuration file .config. It may be used if we are rebuilding the kernel source code for a different architecture.
- make distclean
-
This target is used to remove editor backup files. It is mainly used when generating patches.
22. Cross-Compiling The Kernel
When we work with embedded targets such as the Beagle Bone Black board we have to compile the kernel for the architecture of that board i.e. ARM. A kernel compiled on our x86 workstation will not execute on the Beagle Bone Black because it is compiled for an x86 architecture.
The process of compiling the kernel on our work station for another architecture is referred to as cross-compilation. The kernel can be compiled on the Beagle Bone Black if it has a toolchain installed on it. However as the processing power of embedded targets is much lower than that of PCs and servers it becomes more efficient to employ a cross-compilation toolchain for embedded development.
A cross-compiler can be recognized by its prefix which indicates the system for which it will compile the source code. For example mips-linux-gcc indicates that the cross-compiler will generate a binary that can be executed on a MIPS based architecture whereas a arm-linux-gnueabi-gcc indicates that the cross-compiler will generate a binary that can be executed on an ARM based architecture.
To specify the architecture for which the kernel source code is to be compiled we have to pass a variable ARCH to the top level makefile. This should map to any of the subdirectories in the arch/ directory of the kernel source code e.g. arm.
To specify the cross compilation toolchain we have to pass the CROSS_COMPILE variable which represents the prefix of the toolchain e.g. mips-linux- or arm-linux-gnueabi-.
22.1. Predefined Configuration Files
Many times when working with embedded boards we don’t set the configuration of a particular board from scratch. It is easier if there is a predefined configuration with which we can start from and there is in most cases. We get a list of predefined configurations from make help which allows us to set the .config to a particular configuration for a specific board.
For instance if we run make viper_defconfig it will overwrite the .config file with the file from arch/arm/configs/viper_defconfig. To get a list of default configurations we can either use make help or the find utility as shown below:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ find . -name *_defconfig |head
./arch/arc/configs/tb10x_defconfig
./arch/arc/configs/fpga_defconfig
./arch/arc/configs/fpga_noramfs_defconfig
./arch/arc/configs/nsimosci_defconfig
./arch/mn10300/configs/asb2364_defconfig
.
.
.
./arch/ia64/configs/sim_defconfig
./arch/ia64/configs/tiger_defconfig
./arch/xtensa/configs/iss_defconfig
./arch/xtensa/configs/s6105_defconfig
./arch/xtensa/configs/common_defconfig
Once we’ve loaded a default configuration which is basically a minimal configuration it’s time to tailor the configuration to our specifications. This will include running one of the configuration interfaces like make menuconfig. We see the settings of the default configuration in the interface.
22.2. Saving Our Default Configuration
We also have the ability to save our configuration once it is tailored, as a default configuration. This can be done by running the command make savedefconfig. Running this target causes make to save the .config file with a name defconfig. We can move the new defconfig file to the architecture configs directory with an appropriate name.
-
mv defconfig arch/<ARCH>/configs/my_favourite_config
Overall the choice of starting from a default minimal configuration lies with the developer. We can also start from scratch but be mindful about selection of the CPU selection and the correct device drivers.
22.3. Device Tree
Most embedded platforms have non-discoverable hardware which exists as part of the SOC. This hardware has to be described to the kernel in the form of code or a special hardware description language called Device Tree.
The Device Tree language is used only recently in certain architectures such as ARM, PowerPC, ARC, etc.. The Device Tree source file is compiled into a binary called Device Tree Blob by a compiler and passed to the kernel through the bootloader. Each board will have its own unique hardware and therefore will have a unique device tree source file.
The Device Tree files will be located in the /arch/<ARCH>/boot/dts/ folder. The bootloader has to have the capability to load the Device Tree Blob and the kernel image before starting execution of the kernel.
22.4. Steps To Build and Install A Kernel
-
Configure the kernel source code using make menuconfig
-
Build the kernel using make with <ARCH> and <CROSS_COMPILE> set if building for and embedded platform.
-
Copy the built image from arch/<ARCH>/boot/.
-
The image name will depend on the architecture e.g. bzImage, zImage, etc..
-
-
Install the kernel image. For an embedded platform do NOT run make install. It is better to simply copy the built kernel image.
-
The installation can be customized by editing the arch/<ARCH>/boot/install.sh script.
-
-
Install the modules. For an embedded platform do NOT run make modules_install without the INSTALL_MOD_PATH=<dir>/ variable. This ensures we don’t mess around with the system kernel modules.
22.5. Using U-Boot
A popular bootloader with embedded platforms is U-Boot. U-Boot works with a format of kernel image called uImage. This is generated from the zImage using a make uImage target execution for ARM. Newer versions of U-Boot also support booting of the ARM based kernel image zImage directly.
Some ARM platforms require the LOADADDR to be passed along with the make uImage target execution. The address associated with this variable represents the physical memory where the image is executed in.
U-Boot also has the ability to load the Device Tree Blob in memory and pass it to the kernel. The boot process follows the steps
-
Load the kernel zImage or uImage at address X
-
Load the <board>.dtb file at Y
-
Boot the kernel with bootz X -Y or bootm X - Y. The - indicates no initramfs.
22.6. Kernel Command Line
The kernel takes in a list of arguments which can affect its behavior at run time. These argument can be hardcoded during the configuration of the kernel source code by setting the CONFIG_CMDLINE option.
The command line argument can also be passed to the kernel at boot up using an environment variable like bootargs in the case of U-Boot.
There are several kernel arguments documented in Documentation/kernel-parameters.txt. We typically set:
-
root = for the root filesystem
-
console = for the destination of the kernel messages
23. LAB 2 : Setting Up The Beaglebone Black Board
This is a hands on session taken from the Free Electrons labs with the following objectives
|
23.1. Getting Comfortable With The Board
At this point we have to get familiar with our board. It is good to go through the features of the board given in section 4.0 of the BeagleBone Black System Reference Manual.
23.1.1. Connectors, LEDs and Switches
- 5V DC Power Connector
-
The main DC input which accepts 5V power. Suitable for more power hungry applications.
- Power Down Button Switch
-
Signals to the processor to initiate the power down sequence. It is used to power down the board.
- Boot Button Switch
-
Force the a boot from the micro-SD card by removing and reapplying power to the board.
- Reset Button Switch
-
Reset the processor.
- USB Client Connector
-
Mini USB port at the bottom of the board. It can be used to power the board and setup a network connection.
- 10/100 Ethernet Connector
-
The LAN interface.
- Debug Serial Header Connector
-
The header interface for the serial port.
- MicroSD Slot Connector
-
Slot at the bottom of the board to insert a micro-SD card.
- MicroHDMI Slot Connector
-
Slot at the bottom of the board to insert a micro-HDMI cable to interface to a display.
- USB Host Connector
-
This can be used to connect a USB device like keyboard, mouse, BT dongle, WiFi dongle, etc..
23.1.2. System Key Components
- Sitara Processor
-
ARM architecture OMAP System On Chip(SOC) from Texas Instruments. This is XAM3359AZCZ100 for revision A5A to A6A and XAM3359AZCZ100 for revision B and above. Only the A4 revision boards had the AM3352 processor.
- 512MB DDR3 RAM
-
Micron 512MB DDR3L or Kingston 512MB DDR3 Dual Data Rate RAM.
- TPS65217C PMIC
-
It is the power management IC which supplies the power rails to the different components on board.
- SMSC Ethernet PHY
-
The physical interface to the ethernet network.
- Micron eMMC
-
This was 2GB till revision B and changed to 4GB in revision C.
- HDMI Framer
-
Provides the HDMI control for and HDMI or DVI-D display with adaptor.
23.2. Downloading The Technical Documentation
Design is not possible without documentation, so we download the documents which will help us in the lab sessions. The following are needed:
Tht System Reference Manual describes the details about the design of the
board and is available on this site here
The latest document should be available at: https://github.com/CircuitCo/BeagleBone-Black/blob/master/BBB_SRM.pdf?raw=true.
The datasheet of the TI AM335x SoCs is useful to see the PIN assignments
later when we want to configure the pinmux settings and is available on this
site here
The original link is at the TI website at: http://www.ti.com/lit/ds/symlink/am3359.pdf
The last document is the Technical Reference Manual(TRM) of the TI AM335x SoCs.
At over 4000 pages it describes the internal IP design of the chip. It is available
here.
The same document can be retrieved from the TI website at :
http://www.ti.com/product/am3359
23.3. Installing The Free Electrons Lab Data
We will be using the lab data available from Free Electrons to setup our BeagleBone Black. First make sure the lab data is downloaded. The lab data which was available at the time of writing this journal is here.
We’ll have to uncompress the file with sudo permissions and change the permissions of the resulting folder. The prime reason being that the package contains system device node files for the NFS root filesystem:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo tar xvJf linux-kernel-labs.tar.xz (1)
[sudo] password for conrad:
no talloc stackframe at ../source3/param/loadparm.c:4864, leaking memory
linux-kernel-labs/
linux-kernel-labs/src/
linux-kernel-labs/src/patches/
.
.
.
linux-kernel-labs/modules/nfsroot/sbin/route
linux-kernel-labs/modules/nfsroot/sbin/runlevel
linux-kernel-labs/git/
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo chown -R conrad:conrad linux-kernel-labs (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ ls -l
total 7756
drwxrwxr-x 6 conrad conrad 4096 Mar 22 17:38 linux-kernel-labs (3)
-rw-rw-r-- 1 conrad conrad 7931316 Mar 22 18:57 linux-kernel-labs.tar.xz
-rw-rw-r-- 1 conrad conrad 87 Mar 22 18:55 Readme.txt
1 | Command to untar and decompress the package |
2 | Command to change the owner and group to the user name in this case conrad |
3 | Listing of the directory shows the owner and group has been set appropriately |
The xz extension of the package indicates that it requires XZ compression utility which if not available on your system can be upgraded as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo apt-get install xz-utils
23.4. Making A Bootable MicroSD Card
Now we deviate slightly from the Free Electrons lab slides and first prepare our board as per the instructions provided in the linux-kernel-labs/bootloader/beaglebone-black/README.txt file. The bootable micro-SD card will automatically format the on board eMMC device.
Take the micro-SD card and insert it into a micro-SD adapter/reader like the one shown in the image below:
This memory card reader/adapter should be inserted into the SD card slot available. If your system has a micro-SD card slot then please use that directly. On checking the kernel logs with dmesg we should be able to identify the card detected in the system. If a micro-SD card slot is available then the system should register it as a /dev/mmcblk0 whereas in this case with a memory card reader we see it as /dev/sdb. The following shows the kernel logs:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ dmesg
.
.
.
[127595.272118] usb 1-2: new high-speed USB device number 6 using ehci-pci
[127595.405640] usb 1-2: New USB device found, idVendor=058f, idProduct=6366
[127595.405650] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[127595.405658] usb 1-2: Product: Mass Storage Device
[127595.405665] usb 1-2: Manufacturer: Generic
[127595.405671] usb 1-2: SerialNumber: 058F63666433
[127595.406226] usb-storage 1-2:1.0: USB Mass Storage device detected
[127595.407830] scsi9 : usb-storage 1-2:1.0
[127596.532963] scsi 9:0:0:0: Direct-Access Multiple Card Reader 1.00 PQ: 0 ANSI: 0
[127596.533754] sd 9:0:0:0: Attached scsi generic sg1 type 0
[127598.192274] sd 9:0:0:0: [sdb] 7744512 512-byte logical blocks: (3.96 GB/3.69 GiB) (1)
[127598.193263] sd 9:0:0:0: [sdb] Write Protect is off
[127598.193269] sd 9:0:0:0: [sdb] Mode Sense: 03 00 00 00
[127598.194256] sd 9:0:0:0: [sdb] No Caching mode page found
[127598.194259] sd 9:0:0:0: [sdb] Assuming drive cache: write through
[127598.199023] sd 9:0:0:0: [sdb] No Caching mode page found
[127598.199028] sd 9:0:0:0: [sdb] Assuming drive cache: write through
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ ls -l /dev/sdb (2)
brw-rw---- 1 root disk 8, 16 Mar 22 21:09 /dev/sdb
1 | We see the device attached as sdb |
2 | The device node has been created successfully as /dev/sdb |
We will have to first partition the micro-SD card using the sfdisk utility which is part of the util-linux APT package. This tool helps us to list the partitions of a device, check the sizes of the partitions, check the partitions on a device and re-partition a device. We must be extra careful when we use such a tool as it could also cause damage to our workstation system if we select the wrong device file unintentionally.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ sudo sfdisk --in-order --Linux --unit M /dev/sdb << EOF (1)
> 1,48,0xE,*
> ,,,-
> EOF
Checking that no-one is using this disk right now ...
BLKRRPART: Device or resource busy (2)
This disk is currently in use - repartitioning is probably a bad idea.
Umount all file systems, and swapoff all swap partitions on this disk.
Use the --no-reread flag to suppress this check.
Use the --force flag to overrule all checks.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ mount (3)
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/cgroup type tmpfs (rw)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
none on /sys/fs/pstore type pstore (rw)
rpc_pipefs on /run/rpc_pipefs type rpc_pipefs (rw)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
nfsd on /proc/fs/nfsd type nfsd (rw)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,user=conrad)
/dev/sdb1 on /media/conrad/boot type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2) (4)
1 | The command to re-partition the /devsdb device with sfdisk. The options --in-order indicates that the partitions are in order in the input. --Linux tells sfdisk to ignore all warnings irrelevant for Linux. |
2 | The device is apparently busy. |
3 | We do a mount to check if it is mounted |
4 | We see that a partition is mounted in our Workstation at /media/conrad/boot |
If the micro-SD card is already partitioned and formated it may be auto mounted by our work station. We will have to un-mount all the partitions before we can proceed.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ sudo umount /media/conrad/boot (1)
[sudo] password for conrad:
no talloc stackframe at ../source3/param/loadparm.c:4864, leaking memory
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ mount (2)
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/cgroup type tmpfs (rw)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
none on /sys/fs/pstore type pstore (rw)
rpc_pipefs on /run/rpc_pipefs type rpc_pipefs (rw)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
nfsd on /proc/fs/nfsd type nfsd (rw)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,user=conrad)
1 | We have to unmount the /dev/sdb1 from the mount point i.e. /media/conrad/boot |
2 | We check to see if anything else is mounted again |
Again we attempt to repartition the micro-SD card
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ sudo sfdisk --in-order --Linux --unit M /dev/sdb << EOF
1,48,0xE,*
,,,-
EOF (1)
Checking that no-one is using this disk right now ... (2)
OK
Disk /dev/sdb: 1023 cylinders, 122 heads, 62 sectors/track
Old situation: (3)
Units = mebibytes of 1048576 bytes, blocks of 1024 bytes, counting from 0
Device Boot Start End MiB #blocks Id System
/dev/sdb1 * 1 48 48 49152 e W95 FAT16 (LBA)
/dev/sdb2 49 3780 3732 3821568 83 Linux
/dev/sdb3 0 - 0 0 0 Empty
/dev/sdb4 0 - 0 0 0 Empty
New situation: (4)
Units = mebibytes of 1048576 bytes, blocks of 1024 bytes, counting from 0
Device Boot Start End MiB #blocks Id System
/dev/sdb1 * 1 48 48 49152 e W95 FAT16 (LBA)
/dev/sdb2 49 3780 3732 3821568 83 Linux
/dev/sdb3 0 - 0 0 0 Empty
/dev/sdb4 0 - 0 0 0 Empty
Successfully wrote the new partition table
Re-reading the partition table ...
BLKRRPART: Device or resource busy
The command to re-read the partition table failed.
Run partprobe(8), kpartx(8) or reboot your system now,
before using mkfs
If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)
to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1
(See fdisk(8).)
1 | The sfdisk utility is invoked supplying the information about the partitions |
2 | sfdisk checking to see that no one is using the disk |
3 | The old partition map is displayed first. This will vary based on the history of the micro-SD card |
4 | The new partition map is displayed. The first partition is a W95 FAT16 one which is 48 MB. This is the first line of input to sfdisk. The remaining has been converted to a Linux partition. |
We will have to format the first partition of the disk using the mkfs.vfat partition.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ sudo mkfs.vfat -F 16 /dev/sdb1 -n boot (1)
[sudo] password for conrad:
no talloc stackframe at ../source3/param/loadparm.c:4864, leaking memory
mkfs.fat 3.0.26 (2014-03-07)
mkfs.fat: warning - lowercase labels might not work properly with DOS or Windows
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ echo $? (2)
0
1 | mkfs.vfat is run on the partition /dev/sdb1. The label of the partition is set to boot with the -n option and the -F option specifies the type of file allocation tables used (12, 16 or 32 bit). |
2 | Checks the return value of the command |
We now remove and re-insert the micro-SD card into the system to see if it gets detected and automatically mounted. It does and we see that Ubuntu opens up the directory located in /media/conrad/boot.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria$ mount (1)
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/cgroup type tmpfs (rw)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
none on /sys/fs/pstore type pstore (rw)
rpc_pipefs on /run/rpc_pipefs type rpc_pipefs (rw)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
nfsd on /proc/fs/nfsd type nfsd (rw)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,user=conrad)
/dev/sdb1 on /media/conrad/boot type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2) (2)
1 | We use mount to check explicitly what’s there in the system |
2 | Our partition has been mounted at /media/conrad/boot |
We will finally have to copy the files from the lab data folder to this partition and un mount the device.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs/bootloader/beaglebone-black$ cp am335x-boneblack.dtb MLO MBR u-boot.img MLO.final u-boot.img.final uEnv.txt uImage /media/conrad/boot/ (1)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs/bootloader/beaglebone-black$ umount /media/conrad/boot (2)
1 | Copying the necessary files from the Free Electrons lab data folder which we unpacked earlier |
2 | Unmounting the mounted partition |
We can now safely eject or remove the micro-SD card from the work station.
23.5. Reflashing The eMMC With The micro-SD Card
The bootable micro-SD card will now be used to reflash the eMMC device to get it ready for the lab session. The process is short but the steps maybe a bit confusing so follow the pictures to nail it down correctly.
23.5.1. Insert The micro-SD Card
This step is self-explanatory. The bootable micro-SD card has to be inserted into the micro-SD card slot on the BeagleBone Black board. The micro-SD card has 8 contacts with a golden hue which are at the bottom of the card. The picture below shows the top of the micro-SD card which is placed in the slot. All that is left is to press it into the slot until a click is felt.
23.5.2. Pressing The Boot Switch
After inserting the micro-SD card we have to press the boot switch which is located near the micro-SD card slot as shown in the picture below. Also note that the micro-SD card has been inserted properly into its slot.
23.5.3. Applying Power
The last step is to apply power i.e. either through the USB connector or power connector. Make sure your power supply is built for 5V 1A output before inserting it into the power supply connector. You can depress the boot switch after 1 second after applying power. On applying power the leds will start blinking. The entire reflashing process takes about 20 to 30 seconds. At the end of the process all 4 leds will be on as shown:
23.5.4. Troubleshooting
In case there is an issue with the process and the 4 leds do not light up after a minute then try again. If it still fails then go through the steps given in the lab data folder i.e. linux-kernel-labs/bootloader/beaglebone-black/README.txt. The procedure given here has been taken from that document. There’s a section on "Fixing issues (if any)" which might help.
23.6. Setting Up Serial Communication With The Board
The debug serial header connector has been descibed in the Getting Comfortable With The Board section and should be easy to locate with the labelled image in that section. It is a 1x6 header. Serial capability is provided by UART0 of the processor. It would be good to read the section on the debug serial header given in the Technical Reference Manual.
The only two signals available are TX and RX on the connector and the levels
on these signals is 3.3V. A FTDI USB to serial cable is recommended as this
serves to provide a serial port to PCs/Laptops making use of the available
USB port. The FTDI chip translates the USB data to serial and vice versa. There
are several provided in the elinux.org website link at:
http://elinux.org/Beagleboard:BeagleBone_Black_Serial.
23.6.1. Rhydolabz FTDI USB To Serial Breakout Board
In this journal a breakout board was purchased from
Rhydolabz. There are several boards available but
one without a 1x6 connector was chosen. All the signals of the FTDI can be
exposed by soldering a bergstrip pin-out for advanced users but for our use
case GND, RX and TX are provided with an easy to access 4 pin connector. The
board is also capable of outputing both 5V and 3.3V. This is controlled by
soldering the 3.3V leads at the back of the breakout board. The board can be
picked up from:
http://www.rhydolabz.com/index.php?main_page=product_info&cPath=80&products_id=1090
23.6.2. Connecting The Breakout Board
The FTDI breakout board comes with a Grove 4 pin Female jumper to 4 pin conversion cable. Each of the cables can be connected to female connectors to be slotted into the serial debug header pins. We need only the GND, RXD and TXD signals from the board. Before connecting the board signals make sure the 3.3V leads are shorted at the bottom of the board. The board from Rhydolabz comes with the 5V lead shorted and must be converted for the Beagle Bone Black.
-
Connect the GND cable of the FTDI breakout board to pin 1 of the serial header.
-
Next connect RXD of the FTDI breakout board to pin 5 which is the TX of the serial debug header.
-
Finally connect TXD of the board to pin 4 which is the RX of the serial debug header.
It is always good to understand the specifications of the connectors whenever interfacing electronic circuits. In this case we know that the BeagleBone Black takes 3.3V from the System Reference Manual. If a different cable is to be used check and see if its connector is compatible with the header. The figure below shows the setup where GND is the orange cable on the right, next RXD is the brown cable followed by the TXD which is the red cable.
Once the connections are in place between the BeagleBone Black serial debug header and the FTDI cable or breakout board then connect the USB cable to the breakout board. The picture shows that the board lights up.
The linux kernel running on the workstation should register the new USB device connected. We can probe the kernel logs to see if there is any activity using dmesg.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs$ dmesg
.
.
.
[60269.932101] usb 6-1: new full-speed USB device number 2 using uhci_hcd
[60270.125794] usb 6-1: New USB device found, idVendor=0403, idProduct=6001
[60270.125804] usb 6-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[60270.125812] usb 6-1: Product: FT232R USB UART
[60270.125819] usb 6-1: Manufacturer: FTDI
[60270.125825] usb 6-1: SerialNumber: A602I2CN
[60270.212583] usbcore: registered new interface driver usbserial
[60270.212599] usbcore: registered new interface driver usbserial_generic
[60270.212611] usbserial: USB Serial support registered for generic
[60270.230288] usbcore: registered new interface driver ftdi_sio
[60270.230305] usbserial: USB Serial support registered for FTDI USB Serial Device
[60270.230972] ftdi_sio 6-1:1.0: FTDI USB Serial Device converter detected
[60270.231033] usb 6-1: Detected FT232RL
[60270.231036] usb 6-1: Number of endpoints 2
[60270.231039] usb 6-1: Endpoint 1 MaxPacketSize 64
[60270.231041] usb 6-1: Endpoint 2 MaxPacketSize 64
[60270.231043] usb 6-1: Setting MaxPacketSize 64
[60270.233850] usb 6-1: FTDI USB Serial Device converter now attached to ttyUSB0 (1)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs$ ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Mar 25 22:28 /dev/ttyUSB0 (2)
1 | The device has been recognized as a tty device and is named ttyUSB0 |
2 | A device node /dev/ttyUSB0 is created in the root filesystem |
23.6.3. Accessing The Serial Port With Picocom
We can now access the serial port with a terminal application like picocom. This can be installed as follows:
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs$ sudo apt-get install picocom (1)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs$ sudo adduser $USER dialout (2)
1 | Installing picocom with apt-get |
2 | Adding $USER to the dialout group to use picocom without sudo. $USER is set to the username i.e conrad in the above case. |
We can now start picocom and connect it to the /dev/ttyUSB0 device which was created earlier. The baud rate is specified with the -b option. The default serial port settings for the board are:
-
Baud 115,200
-
Bits 8
-
Parity N
-
Stop Bits 1
-
Handshake None
After starting the picocom application we should be able to see the serial port is opened and the settings should be the default settings. If they are not then try to get the settings by providing options to picocom. Once we get the desired settings we can apply power to the connected BeagleBone Black. At this point we will boot up the board for the first time and should see the serial logs of the bootloader U-Boot. The boot process can be interrupted by hitting any key on the keyboard and allowing us to configure the U-Boot environment.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/techeuphoria/quests/beagleboneblacktux/free_electrons_linux_kernel$ picocom -b 115200 /dev/ttyUSB0 (1)
picocom v1.7
port is : /dev/ttyUSB0
flowcontrol : none
baudrate is : 115200
parity is : none
databits are : 8
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv
imap is :
omap is :
emap is : crcrlf,delbs,
Terminal ready (2)
U-Boot SPL 2013.10 (Nov 28 2013 - 06:36:11) (3)
reading args
spl: error reading image args, err - -1
reading u-boot.img
reading u-boot.img
U-Boot 2013.10 (Nov 28 2013 - 06:36:11)
I2C: ready
DRAM: 512 MiB
WARNING: Caches not enabled
MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
Using default environment
Net: <ethaddr> not set. Validating first E-fuse MAC
cpsw, usb_ether
Hit any key to stop autoboot: 0 (4)
U-Boot#
1 | We run the picocom application setting the baud rate to 115200 and choosing the device as /dev/ttyUSB0 |
2 | picocom shows that the terminal is ready after printing the serial port settings |
3 | On application of power to the BeagleBone Black this is the first print from U-Boot |
4 | We can interrupt U-boot before it tries to boot the kernel by hitting any key |
23.6.4. Setting Default Environment Variables For U-Boot
We need to make sure the version of the U-Boot running is 2013.10. We use the command version to get the information.
U-Boot# version (1)
U-Boot 2013.10 (Nov 28 2013 - 06:36:11) (2)
arm-linux-gnueabi-gcc (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
GNU ld (GNU Binutils for Ubuntu) 2.23.52.20130913
1 | version checks the version of U-Boot in the system |
2 | Our version has to be 2013.10 to save the U-Boot environment to the eMMC storage |
Finally we reset the settings of the U-Boot environment to its default values using the command env default -f -a as shown below. Finally saveenv is used to save the environment settings whenever we want to retain it across reboots.
U-Boot# env default -f -a (1)
## Resetting to default environment
U-Boot# saveenv (2)
Saving Environment to MMC... (3)
Writing to redundant MMC(1)... done
U-Boot#
1 | Resetting the environment variables to a default value |
2 | Saving the environment values |
3 | The environment values are saved to the eMMC device |
23.7. Setting Up Ethernet Communication With The Board
We will now need to setup the board in such a way so as to allow us to download files to its system memory using U-Boot. To do this we will use Trivial File Transfer Protocol (TFTP) through an ethernet cable. Our board will be the TFTP client and we will configure our Ubuntu work station to act as a TFTP server. TFTP can be installed as shown below using APT.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo apt-get install tftpd-hpa
Now we will connect an ethernet cable between our workstation and the BeagleBone Black ethernet connector. If the workstation does not have any more connections then we will have to use a USB ethernet adapter. In this case we have an unused connection so we will connect the cable as shown.
We next have to configure the network interface on the workstation side. Click on the network manager tasklet on the desktop and select Edit Connections.
Click on the Add button on the left and then Create.. an ethernet connection.
Edit the new ethernet connection by changing its name to BBB. Change the IPV4 settings by selecting the method as manual. And finally add the static address as 192.168.0.1 and netmask as 255.255.255.0. There’s no need to add a gateway but if the cursor is in the textbox enter 0.0.0.0. Save the settings and the interface is set up on the workstation.
Now that we have our workstation ethernet interface configured we can setup networking on U-Boot’s side. We can print the environment to check what the variables are set to by running printenv which will give out the values of all the variables in the U-Boot environment. In our case with the default environment values we see that the IP address and TFTP server IP is not set.
U-Boot#
U-Boot# printenv (1)
arch=arm
baudrate=115200
board=am335x
board_name=A335BNLT
board_rev=00A6
.
.
.
stderr=serial
stdin=serial
stdout=serial
usbnet_devaddr=90:59:af:49:c8:ef
vendor=ti
ver=U-Boot 2013.10 (Nov 28 2013 - 06:36:11)
Environment size: 3471/131067 bytes
U-Boot# printenv ipaddr (2)
## Error: "ipaddr" not defined
U-Boot# printenv serverip (3)
## Error: "serverip" not defined
1 | Print all the environment variables |
2 | Print value of the IP address |
3 | Print value of TFTP server IP |
We will set the server IP to the static IP we assigned to our ethernet interface on our workstation and IP address to a different value as follows:
U-Boot# setenv ipaddr 192.168.0.100 (1)
U-Boot# printenv ipaddr
ipaddr=192.168.0.100
U-Boot# setenv serverip 192.168.0.1 (2)
U-Boot# printenv serverip
serverip=192.168.0.1
U-Boot# saveenv (3)
Saving Environment to MMC...
Writing to MMC(1)... done
1 | Setting the IP address to 192.168.0.100 |
2 | Setting the server IP to the workstation ethernet interface IP |
3 | Saving the environment variables |
The next step is to test the connection by creating a file called testfile.txt in /var/lib/tftpboot/. We will attempt to download the file through the tftp command in U-Boot.
U-Boot# tftp 0x81000000 testfile.txt (1)
link up on port 0, speed 100, full duplex
Using cpsw device
TFTP from server 192.168.0.1; our IP address is 192.168.0.100
Filename 'testfile.txt'.
Load address: 0x81000000
Loading: T T T T T T T T
Abort (2)
1 | The tftp command takes a memory address in our BBB system and the file name as parameters. |
2 | We abort the command with CTRL-C after a while as nothing seems to be happening. |
This may happen if the tftp service has not been started properly. So we can restart the service using the following command on the workstation.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo service tftpd-hpa restart
tftpd-hpa stop/waiting
tftpd-hpa start/running, process 12562
Now when we try the tftp command again in the U-Boot command prompt we are able to successfully download the file.
U-Boot# tftp 0x81000000 testfile.txt
link up on port 0, speed 100, full duplex
Using cpsw device
TFTP from server 192.168.0.1; our IP address is 192.168.0.100
Filename 'testfile.txt'.
Load address: 0x81000000
Loading: #
6.8 KiB/s
done
Bytes transferred = 23 (17 hex) (1)
U-Boot# md 0x81000000 (2)
81000000: 67616542 6f42656c 4220656e 6b63616c BeagleBone Black
81000010: 61776120 fa0a2179 3477dfe5 36c5771d away!....w4.w.6
81000020: ddfddd53 acb6fdf7 bff3df47 8df4e90d S.......G.......
81000030: 51bbd157 4bbfd90f 5f723ff2 ae63b73f W..Q...K.?r_?.c.
81000040: e777dbbd ff1f5774 d43f27c9 bcefd75d ..w.tW...'?.]...
81000050: fdb7eff5 fd7ff7bd 6c7e5ebc df50576c .........^~llWP.
81000060: f6fdad24 e24de9dd fdaf3f3f 97cfffbe $.....M.??......
81000070: fec7fc3d fbed8ff7 bfdd7bbe 57df759c =........{...u.W
81000080: 7fbbd68d 3cb2b137 a71377cf 1754bdff ....7..<.w....T.
81000090: ef4cf775 bbee4a85 fe75553d f137bfec u.L..J..=Uu...7.
810000a0: f9997e33 f5f77735 df4cbffb dd7d4d49 3~..5w....L.IM}.
810000b0: f077f636 b5e5d555 5c7fb5f7 d7f69374 6.w.U......\t...
810000c0: f27f9d5f f1d4fd65 74a5db11 b5b6734d _...e......tMs..
810000d0: 77d75f6f 3ef5757e d327f1d7 91255fd7 o_.w~u.>..'.._%.
810000e0: f5c47f7f fe5d77fe 445ebfdd ed78dbbf .....w]...^D..x.
810000f0: 7fb36aff 4fffe7bf d7bd7f5f 9fdffe6d .j.....O_...m...
U-Boot#
1 | The file was successfully transferred this time. |
2 | We read the contents of the load address at 0x81000000 and see "BeagleBone Black away!" as expected. |
We have successfully setup U-Boot to download the kernel.
24. LAB 3 : Cross Compiling The Kernel And Booting It From The Workstation
This is a hands on session taken from the Free Electrons labs with the following objectives
|
24.1. Enabling Networking To Speed Up Embedded Development
In the previous lab we enabled network connectivity between the board and workstation by configuring the U-Boot environment appropriately. This enables us to build our binaries on the workstation and test it on the board without having to flash the board which saves time as well as prolongs the life of the eMMC device or micro-SD card. We will also enable a NFS type of root filesystem which will allow us to test cross-compiled modules on board.
24.2. Installing The Prerequisites
We will need to install a couple of packages before we can proceed with the lab.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs/src$ sudo apt-get install libqt4-dev g++ u-boot-tools (1)
.
.
.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs/src$ sudo apt-get install gcc-arm-linux-gnueabi (2)
.
.
.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training/linux-kernel-labs/src$ dpkg -L gcc-arm-linux-gnueabi (3)
/.
/usr
/usr/bin
/usr/share
/usr/share/doc
/usr/share/man
/usr/share/man/man1
/usr/bin/arm-linux-gnueabi-gcc
/usr/bin/arm-linux-gnueabi-gcov
/usr/share/doc/gcc-arm-linux-gnueabi
/usr/share/man/man1/arm-linux-gnueabi-gcov.1.gz
/usr/share/man/man1/arm-linux-gnueabi-gcc.1.gz
1 | libtqy4-dev, g++ are required for make xconfig. u-boot-tools are required for mkuimage |
2 | gcc-arm-linux-gnueabi is the cross compiler toolchain from Linaro |
3 | Path and name of the cross-compiler can be determined by examining the cross-compiler installed. |
24.3. Configuring The Kernel
We start with configuring the kernel source code with a default configuration. Since our board has a processor(AM335x) which belongs to the OMAP2 family we will use a default configuration file for that board i.e. omap2plus_defconfig.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ find arch/arm/configs/ -iname '*omap*'
arch/arm/configs/omap2plus_defconfig (1)
arch/arm/configs/omap1_defconfig
arch/arm/configs/da8xx_omapl_defconfig
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- omap2plus_defconfig (2)
#
# configuration written to .config
#
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$
1 | The default configuration for omap2 boards |
2 | Setting the default configuration to omap2dplus_defconfig |
Now configure the kernel to use a NFS root filesystem. This can be done with any of the configuration targets i.e. menuconfig, nconfig, gconfig or xconfig.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
scripts/kconfig/mconf Kconfig
.
.
To identify the configuration option for NFS root filesystem search for CONFIG_ROOT_NFS once the menuconfig screen appears.
We see that CONFIG_ROOT_NFS can be reached through "File systems" and "Network File Systems"
24.4. Cross-compiling The Kernel
Now it is time to cross-compile the kernel after we have configured it correctly. We will first do a clean on the source code to make sure we’re compiling fresh
24.4.1. Clean The Sources
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- clean
CLEAN .
CLEAN arch/arm/kernel
CLEAN drivers/eisa
CLEAN drivers/gpu/drm/radeon
CLEAN drivers/net/wan
CLEAN drivers/scsi/aic7xxx
CLEAN drivers/scsi
CLEAN drivers/tty/vt
CLEAN drivers/video/logo
CLEAN firmware
CLEAN kernel/debug/kdb
CLEAN kernel
CLEAN lib/raid6
CLEAN lib
CLEAN security/apparmor
CLEAN security/selinux
CLEAN usr
CLEAN arch/arm/boot/compressed
CLEAN arch/arm/boot/dts
CLEAN arch/arm/boot
CLEAN .tmp_versions
We compile the source code by invoking make with no target and by passing ARCH as arm and CROSS_COMPILE as arm-linux-gnueabi-. The compilation process may take a while.
24.4.2. Build zImage
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- (1)
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
HOSTCC scripts/basic/fixdep
make[1]: `include/generated/mach-types.h' is up to date.
CC kernel/bounds.s
.
.
.
CC sound/soc/omap/snd-soc-omap3pandora.mod.o
LD [M] sound/soc/omap/snd-soc-omap3pandora.ko
CC sound/soc/snd-soc-core.mod.o
LD [M] sound/soc/snd-soc-core.ko
CC sound/soundcore.mod.o
LD [M] sound/soundcore.ko
CC sound/usb/snd-usb-audio.mod.o
LD [M] sound/usb/snd-usb-audio.ko
CC sound/usb/snd-usbmidi-lib.mod.o
LD [M] sound/usb/snd-usbmidi-lib.ko
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ ls -l arch/arm/boot/
total 12828
drwxrwxr-x 2 conrad conrad 4096 Nov 12 23:07 bootp
drwxrwxr-x 2 conrad conrad 4096 Mar 30 21:28 compressed
drwxrwxr-x 4 conrad conrad 36864 Mar 30 21:28 dts
-rwxrwxr-x 1 conrad conrad 8843712 Mar 30 21:28 Image
-rw-rw-r-- 1 conrad conrad 1648 Oct 19 2013 install.sh
-rw-rw-r-- 1 conrad conrad 3148 Oct 19 2013 Makefile
-rwxrwxr-x 1 conrad conrad 4229384 Mar 30 21:28 zImage (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ file arch/arm/boot/zImage
arch/arm/boot/zImage: Linux kernel ARM boot executable zImage (little-endian) (3)
1 | The cross-compilation command in the kernel source directory |
2 | The zImage generated after cross-compilation |
3 | We check the type of file of zImage using the file command |
24.4.3. Build uImage
In order to boot the kernel image with U-Boot we need to convert it into a special format called uImage. The kernel Makefile has a target that can do this and which uses mkimage tool found in the u-boot-tools package. The file will contain the zImage kernel and information about load address of the kernel. The load address will vary based on the platform for the BeagleBone Black board it is 0x80008000.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make LOADADDR=0x80008000 uImage (1)
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
CHK kernel/config_data.h
Kernel: arch/arm/boot/Image is ready
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage
Image Name: Linux-3.13.11
Created: Tue Mar 31 21:50:14 2015
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4229384 Bytes = 4130.26 kB = 4.03 MB
Load Address: 80008000
Entry Point: 80008000
Image arch/arm/boot/uImage is ready (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$
1 | Invoking the uImage target with LOADADDR set to 0x80008000 |
2 | The image is located at arch/arm/boot/uImage |
24.4.4. Generate The Device Tree Binaries
We also need to generate the Device Tree Binaries (DTBs)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ make dtbs
24.4.5. Copy To TFTP Server Home Directory
Finally we can copy the uImage and the am335x-boneblack.dtb files to the TFTP server home directory i.e. /var/lib/tftpboot.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ cp arch/arm/boot/dts/am335x-boneblack.dtb /var/lib/tftpboot/.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/Git/linux$ cp arch/arm/boot/uImage /var/lib/tftpboot/.
24.5. Setting Up The NFS Server
We will now need to setup our workstation as a NFS server. This will require installation of the nfs-kernel-server package.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo apt-get install nfs-kernel-server
Once installed we need to edit the /etc/exports file to configure the server to allow a NFS client to connect to it and mount a directory. In this case we want to configure the NFS server in such a way so as to allow our BeagleBone Black platform to mount the root filesystem which is there in our workstation lab data directory.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ cat /etc/exports (1)
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/home/conrad/fe-kernel-training/linux-kernel-labs/modules/nfsroot 192.168.0.100(rw,no_root_squash,no_subtree_check) (2)
1 | After editing the file we cat its contents |
2 | The directory of nfsroot is exported to IP 192.168.0.100 which is our BBB IP |
Finally before we boot make sure to restart the NFS server as shown below. If there are any errors then the server will refuse to start and error logs will appear. The /etc/exports file must be revisited and the syntax of the line must be inspected and corrected. Fix the errors and ensure the NFS server restarts before proceeding.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo service nfs-kernel-server restart
* Stopping NFS kernel daemon [ OK ]
* Unexporting directories for NFS kernel daemon... [ OK ]
* Exporting directories for NFS kernel daemon... [ OK ]
* Starting NFS kernel daemon [ OK ]
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$
24.6. Boot The System
We will now proceed to boot the system. Make sure the BeagleBone Black is connected to the USB to serial connector correctly as was described in Lab2. Also make sure your etherned cable is connected between the board and your workstation. On powering up the board interrupt the boot sequence so that we have access to the U-Boot console.
24.6.1. Setting The bootargs
We will now change the bootargs environment variable to instruct it to boot the root filesystem from a NFS server and also we will pass the consoled that it is to use. These are standard kernel parameters which can change the way the kernel boots the system.
U-Boot 2013.10 (Nov 28 2013 - 06:36:11)
I2C: ready
DRAM: 512 MiB
WARNING: Caches not enabled
MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
Net: cpsw, usb_ether
Hit any key to stop autoboot: 0
U-Boot#
U-Boot# setenv bootargs root=/dev/nfs rw ip=192.168.0.100 console=ttyO0 nfsroot=192.168.0.1:/home/conrad/fe-kernel-training/linux-kernel-labs/modules/nfsroot (1)
U-Boot# printenv bootargs
bootargs=root=/dev/nfs rw ip=192.168.0.100 console=ttyO0 nfsroot=192.168.0.1:/home/conrad/fe-kernel-training/linux-kernel-labs/modules/nfsroot
U-Boot#
1 | We use setenv to fix the bootargs. |
24.6.2. Explanation Of The Bootargs
- root=/dev/nfs
-
We set the root filesystem device as /dev/nfs to indicate that NFS is to be used. rw::The root filesystem should be mounted with read and write capabilities
- ip=192.168.0.100
-
The IP of the BeagleBone Black board should be 192.168.0.100 before mounting the NFS root filesystem
- console=ttyO0
-
The console to be used is serial port 0. The character before the 0 is 'O' as in "OMAP".
- nfsroot=192.168.0.1:/home/conrad/fe-kernel-training/linux-kernel-labs/modules/nfsroot
-
The NFS root filesystem server IP and path of the directory. This is similar to the workstation settings. The IP is the workstation ethernet static IP and the path is the same as that in the /etc/exports.
24.6.3. Download The Kernel Image And Device Tree Binary
The first step is to download the uImage via tftp. Before downloading it is good to restart the TFTP server on the workstation.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ sudo service tftpd-hpa restart
tftpd-hpa stop/waiting
tftpd-hpa start/running, process 4204
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$
Next on the U-Boot console we can download the uImage as we learnt in the previous lab. We download it to address 0x81000000.
U-Boot# tftp 0x81000000 uImage (1)
link up on port 0, speed 100, full duplex
Using cpsw device
TFTP from server 192.168.0.1; our IP address is 192.168.0.100
Filename 'uImage'.
Load address: 0x81000000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#############################
1.3 MiB/s
done
Bytes transferred = 4229448 (408948 hex) (2)
1 | Command to download uImage |
2 | 4229448 bytes successfully transferred. |
Next we download the device tree binary for the BeagleBone Black board to address 0x82000000
U-Boot# tftp 0x82000000 am335x-boneblack.dtb (1)
link up on port 0, speed 100, full duplex
Using cpsw device
TFTP from server 192.168.0.1; our IP address is 192.168.0.100
Filename 'am335x-boneblack.dtb'.
Load address: 0x82000000
Loading: ##
485.4 KiB/s
done
Bytes transferred = 17911 (45f7 hex) (2)
U-Boot#
1 | Command to download am335x-boneblack.dtb |
2 | 17911 bytes successfully transferred. |
24.6.4. Boot The Kernel
Finally we can boot the kernel from the U-Boot prompt passing the address of the uImage and the address of the device tree binary. The complete log file is available here. The credentials for the login prompt are username as root and no password.
(1)
U-Boot# bootm 0x81000000 - 0x82000000
## Booting kernel from Legacy Image at 81000000 ...
Image Name: Linux-3.13.11
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4229384 Bytes = 4 MiB
Load Address: 80008000
Entry Point: 80008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 82000000
Booting using the fdt blob at 0x82000000
Loading Kernel Image ... OK
Using Device Tree in place at 82000000, end 820075f6
Starting kernel ...
.
.
(2)
[ 5.028652] libphy: 4a101000.mdio:00 - Link is Up - 100/Full
[ 5.068073] IP-Config: Guessing netmask 255.255.255.0
[ 5.073695] IP-Config: Complete:
[ 5.077074] device=eth0, hwaddr=90:59:af:49:c8:ef, ipaddr=192.168.0.100, mask=255.255.255.0, gw=255.255.255.255
[ 5.088130] host=192.168.0.100, domain=, nis-domain=(none)
[ 5.094313] bootserver=255.255.255.255, rootserver=192.168.0.1, rootpath=
[ 5.120355] VFS: Mounted root (nfs filesystem) on device 0:13.
[ 5.142936] devtmpfs: mounted
[ 5.146640] Freeing unused kernel memory: 384K (c0771000 - c07d1000)
Starting logging: OK
Initializing random number generator... [ 5.795678] random: dd urandom read with 56 bits of entropy available
done.
Starting network...
ip: RTNETLINK answers: File exists
Starting dropbear sshd: OK
Welcome to Buildroot
buildroot login: root
#
#
#
#
1 | Successfully starting the kernel |
2 | The NFS root filesystem has been successfully mounted giving us access to a root terminal. |
If at all the kernel fails to mount the NFS root filesystem take a look at the /var/log/syslog file.
24.6.5. Automating The Boot System
It is cumbersome to repeat the sequence of U-Boot commands at the console everytime we want to boot our system. We can automate the boot process by changing the bootcmd environment variable of U-Boot. Before doing so we can save the older value of bootcmd in another variable of our choice. Reset the board by pressing the "Reset" switch. Interrupt the U-Boot autoprompt sequence to gain access to the U-Boot terminal.
U-Boot# printenv bootcmd (1)
bootcmd=run findfdt; run mmcboot;setenv mmcdev 1; setenv bootpart 1:2; run mmcboot;run nandboot;
U-Boot#
U-Boot# setenv bootcmd_orig 'run findfdt; run mmcboot;setenv mmcdev 1; setenv bootpart 1:2; run mmcboot;run nandboot;' (2)
U-Boot# printenv bootcmd_orig
bootcmd_orig=run findfdt; run mmcboot;setenv mmcdev 1; setenv bootpart 1:2; run mmcboot;run nandboot;
U-Boot#
U-Boot# setenv bootcmd 'tftp 0x81000000 uImage; tftp 0x82000000 am335x-boneblack.dtb; bootm 0x81000000 - 0x82000000' (3)
U-Boot# printenv bootcmd
bootcmd=tftp 0x81000000 uImage; tftp 0x82000000 am335x-boneblack.dtb; bootm 0x81000000 - 0x82000000
U-Boot# saveenv (4)
Saving Environment to MMC...
Writing to MMC(1)... done
1 | Checking the value of bootcmd |
2 | Note the use of single quotes for the value of the command |
3 | Setting the new value of bootcmd |
4 | Saving the environment changes |
The bootcmd can be changed based on requirements. It can also be changed to boot the uImage from the eMMC flash if it is stored there. As a last step power cycle the board to check if the system boots up as was done previously. If there is an issue in the boot sequence then review the bootcmd carefully.
24.6.6. Halting The Sytem And Disconnecting Picocom
We have to remember that the BeagleBone Black is a development board which may not be as robust as other products. To be on the safer side it is good to shutdown the system correctly. To shutdown the system we can issue the halt command in the terminal.
buildroot login: root
#
#
# halt (1)
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system halt
[ 202.908940] reboot: System halted (2)
1 | On issuing halt wait for the system to shutdown |
2 | The last log received |
Finally picocom can be disengaged carefully by keying the "espace character" which by default is "C-a" and then by hitting "x".
Linux Kernel Modules
This section covers details about Linux Kernel modules. Some features of the kernel can be loaded as modules after it boots up. We will understand what a module is and when it is used. We will also write, compile and test our very own kernel module.
25. When Do We Use Kernel Modules
In the Configuring Features As Modules section we learnt about Kernel modules and how we can configure certain features of the kernel source code to be compiled as separate binaries that can be loaded into the kernel after it boots up. These modules can also exist independent of the kernel source code in another source path and can be compiled with the headers of the kernel so long as the API used in the module are compatible with the kernel source code.
We use kernel modules when:
-
We are interested in developing a feature of the kernel independently. This allows us to make changes to the module source code, load and test it without having to reboot the kernel. If the source code were a part of the kernel source code we would have to reboot the kernel everytime we wanted to test the code.
-
We want to minimize the size of the kernel image. In most cases if the system is a general purpose system then the drivers and features required by certain applications do not have to be present in the kernel from boot. They can be loaded on demand. In embedded systems the kernel is sometimes stored on a limited storage device like NAND flash on a partition. The size of the partition of the kernel will depend on the size of the kernel used for the applications of that system.
-
We want to minimize the boot time to improve system responsiveness after a reboot. If features that are not required immediately after boot are part of the kernel then their initialization will be add to the boot time. We can delay their initialization using kernel modules.
26. Determining Kernel Module Dependencies
Kernel modules cannot be loaded if the modules they depend on have not been loaded into the kernel. To check the module dependencies of a particular module, read the module information using modinfo. Apart from other useful information about the Kernel module modinfo will also give a list of dependencies in the depends field. We will check the module dependency for one of the kernel modules in our workstation as an example.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ modinfo mac80211 (1)
filename: /lib/modules/3.13.0-45-generic/kernel/net/mac80211/mac80211.ko
license: GPL
description: IEEE 802.11 subsystem
srcversion: 385697223F8285F67C93A06
depends: cfg80211 (2)
intree: Y
vermagic: 3.13.0-45-generic SMP mod_unload modversions 686
signer: Magrathea: Glacier signing key
sig_key: 36:89:BF:48:AF:50:2C:BA:FE:71:E5:C2:5D:6C:55:34:0B:7F:13:FF
sig_hashalgo: sha512
parm: max_nullfunc_tries:Maximum nullfunc tx tries before disconnecting (reason 4). (int)
parm: max_probe_tries:Maximum probe tries before disconnecting (reason 4). (int)
parm: beacon_loss_count:Number of beacon intervals before we decide beacon was lost. (int)
parm: probe_wait_ms:Maximum time(ms) to wait for probe response before disconnecting (reason 4). (int)
parm: ieee80211_default_rc_algo:Default rate control algorithm for mac80211 to use (charp)
1 | We use modinfo to check the information about mac80211 |
2 | We see the dependency is module cfg80211 |
The utility modinfo can be also given the full path file name of a kernel module if it is not loaded into the system
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ modinfo /lib/modules/3.13.0-45-generic/kernel/net/mac80211/mac80211.ko (1)
filename: /lib/modules/3.13.0-45-generic/kernel/net/mac80211/mac80211.ko
license: GPL
description: IEEE 802.11 subsystem
srcversion: 385697223F8285F67C93A06
depends: cfg80211
intree: Y
vermagic: 3.13.0-45-generic SMP mod_unload modversions 686
signer: Magrathea: Glacier signing key
sig_key: 36:89:BF:48:AF:50:2C:BA:FE:71:E5:C2:5D:6C:55:34:0B:7F:13:FF
sig_hashalgo: sha512
parm: max_nullfunc_tries:Maximum nullfunc tx tries before disconnecting (reason 4). (int)
parm: max_probe_tries:Maximum probe tries before disconnecting (reason 4). (int)
parm: beacon_loss_count:Number of beacon intervals before we decide beacon was lost. (int)
parm: probe_wait_ms:Maximum time(ms) to wait for probe response before disconnecting (reason 4). (int)
parm: ieee80211_default_rc_algo:Default rate control algorithm for mac80211 to use (charp)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$
1 | We give the full path file name of the kernel module |
The kernel module dependencies are described in the /lib/modules/<kernel-version>/modules.dep file which is generated when running the make modules_install command.
27. Inserting Kernel Modules
To insert a module into the kernel we have to use the insmod command. As a kernel module has the ability to affect the running kernel it requires administrative privileges in order to insert the module. The full path of the kernel module must be given e.g. sudo insmod <module_path>.ko
It may so happen that the kernel module may refuse to load and insmod will exit without giving sufficient details. In such a case we can inspect the kernel logs using dmesg to understand what is failing.
Another method of inserting the module is to use modprobe. With this method all dependent modules are also loaded into the kernel before loading the module required. To do this modprobe determines the dependency tree of the module and loads them in order. The dependent modules are searched in the /lib/modules/<version>/. Based on the module name the corresponding object file name is searched.
To list the modules which are inserted into the kernel we can use the lsmod utility. Another way is to cat the contents of /proc/modules.
28. Removing Kernel Modules
We can remove a module which has been inserted and is live as part of the kernel if no other process or kernel module is using it. To do this we have to use the rmmod utility with administrator privileges e.g. sudo rmmod <module name>.
Another way of removing the kernel module is with modprobe e.g. modprobe -r <module name>. This will attempt to remove the module and all the dependent modules which are no longer needed after removing the module.
29. Passing Parameters To Modules
A kernel module can take parameters before loading it so as to change its behavior during execution. The parameters of a kernel module can be determined with the modinfo utility.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~/fe-kernel-training$ modinfo mac80211 (1)
filename: /lib/modules/3.13.0-45-generic/kernel/net/mac80211/mac80211.ko
license: GPL
description: IEEE 802.11 subsystem
srcversion: 385697223F8285F67C93A06
depends: cfg80211
intree: Y
vermagic: 3.13.0-45-generic SMP mod_unload modversions 686
signer: Magrathea: Glacier signing key
sig_key: 36:89:BF:48:AF:50:2C:BA:FE:71:E5:C2:5D:6C:55:34:0B:7F:13:FF
sig_hashalgo: sha512
parm: max_nullfunc_tries:Maximum nullfunc tx tries before disconnecting (reason 4). (int) (2)
parm: max_probe_tries:Maximum probe tries before disconnecting (reason 4). (int) (3)
parm: beacon_loss_count:Number of beacon intervals before we decide beacon was lost. (int) (4)
parm: probe_wait_ms:Maximum time(ms) to wait for probe response before disconnecting (reason 4). (int) (5)
parm: ieee80211_default_rc_algo:Default rate control algorithm for mac80211 to use (charp) (6)
1 | We use modinfo to check the information about mac80211 |
2 | Parameter max_nullfunc_tries indicated with the parm field. |
3 | Parameter max_probe_tries indicated with the parm field. |
4 | Parameter beacon_loss_count indicated with the parm field. |
5 | Parameter probe_wait_ms indicated with the parm field. |
6 | Parameter ieee80211_default_rc_algo indicated with the parm field. |
There are several ways of passing parameters to the kernel module:
-
Through insmod:
sudo insmod ./snd-intel8x0m index=-2 -
Through modprobe by setting parameters in /etc/modprobe.conf or any file in /etc/modprobe.d/ as follows:
options snd-intel8x0m index=-2 -
Through the kernel command line, when the driver is built as part of the kernel:
snd-intel8x0m index=-2-
snd-intel8x0m is the kernel module name
-
index is the parameter
-
-2 is the value
-
To check the current values of modules already loaded in the kernel check the /sys/module/<name>/parameters directory. Each file in it represents a parameter and its content is the value of that parameter for the running module.
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ ls /sys/module/snd/parameters/
cards_limit debug major slots (1)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cat /sys/module/snd/parameters/cards_limit
1 (2)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cat /sys/module/snd/parameters/debug
1 (3)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cat /sys/module/snd/parameters/major
116 (4)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$ cat /sys/module/snd/parameters/slots
(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null) (5)
conrad@conrad-HP-Pavilion-dm3-Notebook-PC:~$
1 | Listing the parameters cards_limit, debug, major, slots |
2 | Checking the values passed to the parameter card_limit |
3 | Checking the values passed to the parameter debug |
4 | Checking the values passed to the parameter major |
5 | Checking the values passed to the parameter slots |
30. Developing Kernel Modules
We will first take a look at a sample source code of a Linux kernel module.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
(1)
static int __init sample_module_init(void) (2)
{
pr_alert("Wassup!\n");
return 0;
}
static void __exit sample_module_exit(void) (4)
{
pr_alert("Cya Later!\n");
}
module_init(sample_module_init); (3)
module_exit(sample_module_exit); (5)
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Sample Module");
MODULE_AUTHOR("Newbie");
1 | Only headers specific to the Linux kernel, no access to the standard C library |
2 | Defining an initialization function, returns an int to indicate the status of the initialization when insmod is used to load the module. |
3 | The macro module_init is used to register the initialization function for the module. |
4 | Defining a cleanup function for the module. |
5 | The macro module_exit is used to register the cleanup function for the module. |
6 | Metadata for the module defining the license type, description and the author. |
The source code is in C but it has some special symbols which are not
used in user space application programming:
- __init
-
This indicates that the module initializaiton function sample_module_init can be removed after initialization. The function is called only once when the module starts up and thereafter is not used. This optimizes the memory usage of the kernel.
- __exit
-
This indicates that the function is discarded if the module is compiled statically into the kernel or if module unloading is disabled. Its primary use is for loadable kernel modules.
It should be noted that the name of the initialization and cleanup functions can be anything however the module name is often used to form the functions (<modulename>_init()/<modulename_exit()).
30.1. Symbols Exported To Modules
A kernel module can use functions and variables defined in other parts of the Linux
kernel source code so long as they are exported. There are two macros
that are used to export the symbol names that can be used by other modules:
- EXPORT_SYMBOL(symbolname)
-
Exports a function or variable to all modules
- EXPORT_SYMBOL_GPL(symbolname)
-
Exports a function or variable to only GPL modules
The diagram illustrates the difference between exporting a symbol with EXPORT_SYMBOL versus EXPORT_SYMBOL_GPL. Symbols exported by EXPORT_SYMBOL_GPL(func3, func4) can be used by only GPL modules whereas symbols exported by EXPORT_SYMBOL can be used by both GPL and Non-GPL modules. A module gets it’s license from the MODULE_LICENSE macro added in it’s source code along with the other metadata.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init sample_module_init(void)
.
.
.
MODULE_LICENSE("GPL"); (1)
MODULE_DESCRIPTION("Sample Module");
MODULE_AUTHOR("Newbie");
1 | Module license is GPL |
The kernel can only use symbols defined in its source code. It cannot use symbols exported by modules even if they are GPL licensed modules. Symbols exported with EXPORT_SYMBOL_GPL can be used only by GPL licensed modules. Symbols exported with EXPORT_SYMBOL can be used by GPL and Non-GPL licensed modules
30.2. About Module Licenses
The MODULE_LICENSE macro is used to define the license of the module. It is used to restrict the functions that a module can use if it is not a GPL licensed module. GPL licensed modules have access to all exported symbols whereas Non-GPL licensed modules can only access symbols exported with EXPORT_SYMBOL.
Another use for module licenses is to identify issues comming from proprietary modules. Typically kernel developers do not fix issues coming from proprietary modules or drivers which cause kernel crashes and OOPSes.
#ifndef __LICENSE_H
#define __LICENSE_H
static inline int license_is_gpl_compatible(const char *license)
{
return (strcmp(license, "GPL") == 0
|| strcmp(license, "GPL v2") == 0
|| strcmp(license, "GPL and additional rights") == 0
|| strcmp(license, "Dual BSD/GPL") == 0
|| strcmp(license, "Dual MIT/GPL") == 0
|| strcmp(license, "Dual MPL/GPL") == 0);
}
#endif
GPL compatible licenses are defined in the include/linux/license.h file as shown above. These include GPL, GPL v2, GPL and additional rights, Dual BSD/GPL, Dual MIT/GPL or Dual MPL/GPL. All other licenses are considered as proprietary.
30.3. Compiling Modules Out Of Tree
The source code is maintained separately outside the kernel source code. It is easier to modify the source code, however adapting the module source code to changes in the kernel API means that the maintainer has the onus of keeping it upto date with the changing kernel. One disadvantage is that the module cannot be built statically with the kernel. The following snippet shows the Makefile that can be used to build an out of tree kernel module/driver.
ifneq ($(KERNELRELEASE),)
obj-m := wassup.o
else
KDIR := /path/to/kernel/sources
all:
$(MAKE) -C $(KDIR) M=$$PWD (1)
endif
1 | Rule for the target all |
When compiled out of tree the Makefile does not have KERNELRELEASE defined and therefore KDIR is set to the path to either:
-
Full kernel directory
-
Kernel Headers Directory
The kernel Makefile gets invoked as KDIR is set and the rule for the target all will change to the KDIR first and call the corresponding Makefile in that path. Additionally $PWD is passed as an argument value in M to the kernel Makefile. The double $$ is required to pass $PWD as the value to M.
The kernel Makefile knows that it has to compile a module and because there is a value for M it can locate where the module Makefile is present. This time the kernel Makefile calls the module Makefile and the value of KERNELRELEASE is defined. The kernel uses the definition of obj-m to identify the module to be compiled which in our case is wassup.o. In this way the module Makefile given above is invoked twice, the first time from the module directory and second time by the kernel Makefile.
The kernel directory pointed to by KDIR in the module makefile must be configured as there will be differences between different configurations of the kernel. The module compiled against a specific version will only load in that version and configuration of the kernel. If there is a mismatch then insmod/modprobe will crib with an output "Invalid module format".
30.4. Compiling Modules Inside Of The Kernel Tree
The source code is integrated inside the kernel source code. It can be integrated with the configuration and compilation process of the kernel. The module can be built statically with the kernel source code.
To add a new driver or module to the kernel source tree we have to place the source file in the appropriate source directory. For example we’ll take a look at the USB serial navman driver. The source code for the driver/module should be present in a single file. If the driver is really big then it should have its own directory. The source file for the navman driver is in drivers/usb/serial/navman.c
To configure the kernel to include a module or driver we need to add information in the drivers/usb/serial/Kconfig file in the same directory. The snippet below shows that the navman driver has a kernel option type of tristate which means it can be enabled, disabled or configured as a module.
.
.
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
help
To compile this driver as a module, choose M here: the
module will be called navman.
.
.
Next we take a look at the drivers/usb/serial/Makefile which has a line based on the drivers/usb/serial/Kconfig setting. The name of the configuration field CONFIG_USB_SERIAL_NAVMAN is derived from the KConfig settings. The value of CONFIG_USB_SERIAL_NAVMAN will be based on the configuration applied upon invoking make menuconfig. After configuring the kernel and enabling th module/driver we can build it by running make.
.
.
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
.
.
Further information about the Kernel build process and incorporating
newer files to the source can be obtained at:
Documentation/kbuild