You are on page 1of 10

Arivendu Bhardwaj

Porting Embedded Linux on ARM Core

Arivendu Bhardwaj

Abstract : In the realm of embedded technologies ARM (Advanced RISC


Machine) is very popular. According to Wikipedia around 70% of all 32 bit
embedded CPU’s are based on ARM architecture. Its usage is growing in cell
phones, PDA’s, GPS devices and RFID systems. The Embedded modules,
based on ARM, can become very complex machines since these are meant to
support varied tasks such as memory management, process management and
peripheral interfaces. For seamless integration of these functional modules an
OS has to be ported on these ARM based CPUs .Traditionally this OS porting
is often the specialized work of third party vendors having expertise in this
domain. For every new CPU architecture, the OS has to be customized,
compiled and burnt into the core .With the coming of age of Linux as an
embedded OS all this has changed quite significantly. Being in Open Source
domain, Linux kernel can be freely downloaded and compiled for any system
architecture and this includes ARM based systems also. This enables the
developers to port the OS themselves. This paper describes the details of
porting of embedded Linux on ARM core. The Kernel boot sequences, where
the platform dependent handles are required and the working of board’s Boot
Loader are described in detail. Firmware to Kernel transition, early Kernel Init,
IRQ Setup, Core Subsystem initialization and final board Initialization are also
described.

Key Words: ARM, Operating System, Linux, Kernel.

1. Introduction
In recent years, embedded Linux has been receiving a lot of attention as a viable, low cost
and robust implementation platform for high performance embedded systems based on
popular microcontrollers. Thus Linux was the natural choice, when we decided to develop
a UHF RFID reader based on ARM7TDMI based AT91SAM7S256 module. This paper
brings out our experience in this development work.
From a High level Design perspective, an embedded system generally consists of the
following functional blocks (Fig.1):
 The Processor (in the present context it’s ARM).
 The Embedded Operating System (OS) running on the processor, present
context targets Linux.
 The peripherals around the processor, e.g. UART, SPI, MMU, Timers etc.
 The drivers for the peripherals that support the specific Operating system.
 Cross development tools-specific to the hardware as well as the Operating
System-consisting of compiler, debugger, emulator/simulator etc.

Proceedings of ASCNT – 2009, CDAC, Noida, India, pp. 184 –193

184
Porting Embedded Linux on ARM core

Device drivers
Operating System

Peripheral Peripheral

Processor (ARM)

Fig.1. Organization of an Embedded Module

Though the Embedded OS is absent in many low end embedded modules which don’t
support any or much of peripherals and I/O drivers. It’s very much required in high end
systems that have to support a multitude of peripherals and functional tasks. An embedded
OS is often a specialised and customised version of a general purpose OS like Windows
XP, Linux etc. Whereas the general purpose operating systems are non-deterministic in
nature and have a large code footprint (greater than 500 MB). An embedded OS on the
other hand are very efficient and compact in size (around 10 MB). They excludes the
additional modules of a general purpose OS which are not required in a task specific
embedded system. These embedded OS also often support deterministic and Real Time
behaviour where the OS has to render the services in a known and expected time frame.
The mathematical modelling of these service times doesn’t have any random components
which can induce randomly missed deadlines in its services. Non Real Time embedded OS
also provide similar kernel services.
The embedded modules incorporating ARM processors need to support a family of
peripherals and system modules, e.g. the AT91SAM7S series has 32 peripherals, including:
 AIC (Advanced Interrupt Controller).
 PIO (Parallel Input Output port).
 ADC (Analog to Digital Convertor).
 SPI (Serial Peripheral Interface).
 TWI (Two Wire Interface).
 2xUSART(Universal Synchronous Asynchronous Receiver Transmitter).
In order to support them, all these modules have to be configured at start up time. Doing
this at system level requires writing of start up code – often in ARM assembly targeting
each of these modules. This task of writing the start up code is quite complex and time
consuming and often leads to buggy code and malfunctioning peripherals. Moreover, if a
peripheral is added or changed in the system a complete start up code has to be re-written
from scratch. Only after this start up code is up and running can the application software
be developed for the module.
If there is an embedded OS running on the processor (ARM) this start up code can be done
away with as then that will be handled by the OS itself. The peripherals have just to be
provided with the required parameters as is done in a general purpose OS and there is no
need to individually program these peripherals. Even for a new peripheral the task
simplifies just to configure it. Starting with ARM9 and above cores, which incorporate a
memory management unit (MMU), the Linux kernel, which always had modular support
for memory management, is very much suited for ARM core family.

185
Arivendu Bhardwaj

The remaining sections of this paper are organized as follows:


Section 2 describes Embedded Linux and the utility tools available for development.
Section 3 explains the Linux kernel compilation process. Section 4 explains the Boot
loader details and its configuration. The files involved in kernel customization are dealt
with in Section 5. Section 6 deals with the system initialization process. Section 7
describes the importance of this development work within the overall developmental
framework of our project.

2. Embedded LINUX

Embedded Linux uses the same kernel (the core) as used by the desktop version and there
is no need for a special kernel for embedded applications. In fact the official kernel
release [1] can be used to build an embedded system. The kernel used in an embedded
system differs from its desktop version by its build configuration. Many third party vendors
provide kernels that are optimised and patched to support tools such as kernel debugging.
An embedded Linux system has this customised kernel together with the development
framework, specific to the hardware for which it has to be ported. This framework
includes cross-compilers, debuggers, boot image builders etc. This framework has to reside
on the development host system. Embedded Linux also support special libraries,
executables and configuration files to be used on the target system. With Linux maturing as
an embedded operating system, now the developers can themselves port it on to a processor
including ARM since the source code of the Linux kernel is freely available. Also Linux
is robust, flexible, has a large developer community and large number of vendors
supporting it. These are the major reasons for choosing Linux as an embedded OS. Device
drivers too are available for Linux and being in open source domain there is no dearth of
cross development tools specific to Linux and ARM.
A major online repository of Linux kernel, kernel patches and cross development tools etc.
for ARM platform can be located at [2].

3. The LINUX Kernel

This section describes the setting up of Kernel sources, the required tool chains,
environment set up and the kernel compilation.

3.1 Kernel source tree:


On the onset we require a kernel source tree with ARM patches. Linux follows a versioning
system as,Kernel version x.y.z, where:
 x: the major revision number
 y: the minor revision number.
 z: the patch level of the kernel
The ARM kernel tree carries a suffix to the version number i.e. vrsN or rmkN, where N
refers to the patch release number. This refers to the ARM kernel patch that needs to be
applied to the mainline kernel. e.g. 2.4.20 vrs2 np1 kernel is obtained by patching the
mainline 2.4.20 kernel with 2.4.20 vrs2 patch and 2.4.20 vrs2 np1 patch.
The patches are hierarchical. So they have to be applied in correct order. The patch files
with more extensions depend on the ones with less extension e.g. vrs2 np1 patch depends
on vrs2 patch, hence vrs2 patch has to be applied before vrs2 np1 patch.

186
Porting Embedded Linux on ARM core

3.2 Cross development tool chain


The cross development tool chains based on gcc-2.95.3 and gcc-3.0 are available as free
downloads [3]. The tool chain needs to be ‘untared’ (tar xvjf/tar xvzf) in /usr/local/arm
directory and the same has to be appended to the PATH environment variable.
The files specific to ARM are in:
 linux/arch/arm: the code.
 linux/include/asm-arm: the header files
Linux/arch/arm further contains the following directories, among others:
 kernel: core kernel code.
 mm: memory management code.
 lib: ARM specific internal library functions.
 nwfpe and fastfpe: floating point implementations
 boot: has the final compiled kernel.
 tools: scripts for auto generating files.
 def-configs: default configuration files.

3.3 Machine registration


The kernel tree identifies each device by a unique machine ID. We need to get this ID from
[4] and if the device is new, it has to be first registered there in order to get its unique ID.
This registration gives a unique numerical identifier for the device, a configuration variable
viz. CONFIG_MACH_$MACHINE and provides for runtime machine checking. This file,
containing the ID has to be placed at linux/arch/arm /tools/mach-types.
The script linux/arch/arm/tools/gen-mach-types uses this file to generate linux/include
/asm-arch/mach-types.h, which in turn sets the various macros, to be used by the source.

3.4 Configuration &Compilation


For configuring and cross compiling the kernel, the sequence given in Fig.2 has to be
followed.

“ARCH” and “CROSS_COMPILE” variables in the top level Makefile have to be


edited with:
ARCH = arm
CROSS_COMPILE = <path_to_cross_compile_toolchain>

A new default ‘config’ file (named <machinename>) has to be added in


linux/arch/arm/def-configs. Any old “.config” file should be deleted.

On executing
# make <machinename>_config (for2.6.xx kernel)
And
# make <machinename>_config
# make oldconfig (for 2.4.xx kernel)
The file <machinename> is copied from linux/arch/arm/
def-configs/ to linux/.config.
To compile, execute:
# make clean
# make dep (optional for 2.6.xx kernel)
# make zImage (generates a compressed image)
# make modules
Fig.2. The kernel configuration & compilation sequence
187
Arivendu Bhardwaj

The compressed kernel image is compiled as arch/arm/boot/zImage [5].

4. The Boot Loader


The ARM Linux needs a small amount of machine dependent code to initialize the system.
This code i.e. the bootloader, runs before the main kernel, and without it the system cannot
boot. Its equivalent to the BIOS for an X86 system.
The minimum functionality required from the bootloader are:
 Initialize the memory system.
 Initialize at least one serial console
 Obtain the ARM Linux machine type.
 Place the kernel image at the correct memory address.
 Load the Initrd (Initial RAM disk)
 Set up the boot parameters
 Jump to the kernel with specific register values.

Following changes have to be made to the “configuration” files of the boot loader:
a) In order to pass the physical memory layout to the kernel, bootloader uses the ATAG
parameters [6].

Fig.3, [6] depicts the ATAG structure as organized in the system memory.
ATAG_CORE
Base address
Increasing
ATAG_MEM address

ATAG_NONE

Fig.3. The ATAG structure

b) The boot loader passes the relevant ‘console=’ option to the kernel, specifying the
port, and serial format options. These options are detailed in
Linux/Documentation/kernel-parameters.txt.
c) The boot loader has to have the correct machine ID, either through hard code, or
through an algorithm. It’s the same ID that is generated by the machine registration
process.
d) The compressed kernel image (zImage files) can be either loaded from the flash or the
RAM. If RAM is used the image can be placed anywhere, the recommended place is
32KB (0x8000) into RAM. TABLE I [7], lists the important fields of the zImage
header.
Table1. Useful Fields In zImage Head Code
Offset into zImage Value Description
0x24 0x016F2818 Magic number (identifies the
ARM Linux zImage)
0x28 start address Starting address of the zImage
0x2C end address End address of the zImage

188
Porting Embedded Linux on ARM core

e) The boot loader places the Initrd image, into the memory at a set location. It uses the
following parameters for this:
ATAG INITRD2:specifies the location of the compressed ramdisk image.
struct atag_initrd2
{
U32 start; /* physical start address */
U32 size; /* size of compressed ramdisk image in bytes */
};
ATAG RAMDISK:ensures that the ramdiskis large enoughfor the decompressed Initrd
image.
struct atag_ramdisk
{
U32 flags; /* bit 0 = load, bit 1 = prompt */
U32 size; /* decompressed ramdisk size in _kilo_ bytes */
U32 start; /* starting block of floppy-based RAM disk image */
};
f) The tagged list passed by the bootloader to the kernel has to conform to the following
constraints:
 The list has to be placed in RAM, where it can’t be overwritten. The recommended
place is, start of RAM + 0x100.
 It must not extend past 0x4000 boundary, as after that kernel’s TLB is created.
 It has to be word (32 bit) aligned.
g) The boot loader calls the kernel image by jumping directly to the first instruction of
the kernel image. For both flash or RAM based, kernel compressed image, following
settings apply:
 Processor registers
o r0 = 0
o r1 = machine ID
o r2 = address of the tagged list
 Processor mode
o Disabled IRQs and FIQs.
o Processor has to be in supervisor mode (SVC).
In the present context, the GPL universal bootloader, U-Boot is referred [8].

5. Kernel Customisation

The following kernel files have to be edited for the ARM platform

5.1 Entry Level Files

arch/arm/Makefile
It should have the proper macros to detect the machine name, e.g. CONFIG_ARCH_xxx;
here ‘xxx’ refers to the specific machine names.

arch/arm/boot/Makefile

189
Arivendu Bhardwaj

This should list the start address from where the kernel image has to be decompressed, the
targeted environment variable is, ‘ZTEXTADDR’. It’s the same physical address to where
ARM Linux is placed in the bootloader code. Usually it’s 32KB inside the RAM.

include/asm/arch/uncompress.h
This is used to output the kernel decompression messages to the UART. It provides
following two functions to accomplish this:
1. arch_decomp_setup() : to setup the UART.
2. putstr() : to output a string to UART, it appends every ‘\n’ with ‘\r’

arch/arm/kernel/debug-armv.s
or
arch/arm/kernel/debug.s
This file refers to assembly level debugging, for ARM 32 bit mode. The following
(assembly) functions implemented here communicate to a serial port, independent of the
kernel.
addruart rx: to obtain the address of the serial port in ‘rx’
senduart rd,rx: write the character at ‘rd’ to ‘rx’ (the serial port)
busyuart rd, rx : the wait function (transmit buffer empty)
waituartrd,rx: wait for handshake signal (clear to send)

5.2 Processor (CPU) Files

arch/arm/mm/proc-<CPUTYPE>
The file contains the table of ‘cpu_mask’ and ‘cpu_val’ supported by the kernel. the
‘cpuid’ of the target machine is compared against this table.
If (cupid & cpu_mask) = = cpu_val, only then the kernel will run on the target cpu(as
specified by the ‘cpuid’).

include/asm-arm/ directory files


Once the ‘cpuid’ id correctly detected, the set up for the specific CPU is called. The various
functions and routines are coded in this directory. These functions include CPU init(),
idle(), tlbflush() and functions to synchronise both instruction and data cache.
arch/arm/mach-<machinename>/arch.c
It includes the macros used for machine setup, i.e. MACHINE_START and
fixup_<machinename>

MACHINE_START(<machinename>, "<machinename>")
MAINTAINER("<vendor name>.")
BOOT_MEM(<offset>,<peripheral_base_addr_phy>,
<peripheral_base_virtual>)
VIDEO(<start_addr>, <end_addr>)
FIXUP(fixup_<machinename>)
MAPIO(<machinename>_map_io)
INITIRQ(genarch_init_irq)
MACHINE_END

fixup_<machinename> is used for boot time updation of entries. [9]

190
Porting Embedded Linux on ARM core

6. System Initialisation

For Core Subsystem initialization of ARM platform the following files have to be
edited/customised.

6.1 IO Mapping
include/asm/arch/hardware.h
This file has to be edited according to the memory map and IO map of the hardware
architecture. The physical addresses (_START) are mapped on to the virtual addresses
(_BASE).
include/asm/arch/io.h
This lists the following macros:
 IO_SPACE_LIMIT(): the upper bound for IO mappings.
 arch_getw(<address>): to receive the ‘word’ from IO ‘<address>’.
 arch_putw(<data>,<address>): send the ‘word’ (data) to ‘<address>’.
All these macros are hardware specific.

6.2 IRQs for ARM

include/asm/arch/irq.h
It lists the direct mapping of the ‘fixup_irq’ to a literal. The base addresses of the various
IRQs have to be mentioned here, this is done in conformity to the memory map of the
ARM architecture.
include/asm/arch/irqs.h
This file defines the IRQ numbers, as used by the ARM architecture. These are the integer
values as assigned to the various ARM IRQs.

6.3 Timer Files

include/asm/arch/time.h
The timer interrupt handlers and macros are to be defined here, these are called after IRQs
are initialized. Major ones are:
 <machinename>_gettimeoffset:
Returns number of microseconds since last timer tick. In absence of a user defined function
the default handler from arch/arm/kernel/time.c is used.
 do_profile(<registers>): Does the kernel profiling, based on the given register
values.
 define CLOCK_TICK_RATE : Defines the time period of the hardware clock. [10]

6.4 Low Level Board Initialisation

Subsequent to the core subsystem initialization, a low level Board intialization routine has
to be executed.
The execution pointer has to be made to jump into this low level initialization routine. This
routine basically has a single function (which may be nested) e.g. lowlevelinit(). This is
very board specific and includes the <board_name>.h file.
Here the configuration and setup is done for:
 Master clock, can be main oscillator, PLL or slow clock.

191
Arivendu Bhardwaj

 The Power management controller (PMC).


 Advanced Interrupt Controller (AIC).
 Peripherals e.g. SPI, I2C, user mode UART etc.

7. Importance of the Development Work

The present work is an offshoot of the project titled “Design & Development of UHF RFID
reader”- under the aegis of the National RFID Program- which involves the firmware
microcontroller using ARM core. The firmware for the reader is already complex, and
needs a majority of time and development effort. By porting Linux on the ARM based
firmware controller, the peripheral configuration and synchronization tasks, which
presently is being done through system programming, and is more often than not
cumbersome, can be handled by the OS and the reader application shall run via this OS
layer.
This will not only save a lot of development time- which can then be utilized for the
application development- but will also result in a much more elegant, efficient and
modular architecture for the firmware. Moreover, as the present project/product will
mature, there shall be a need for added functionality, efficiency and additional peripherals.
This scaling up of the product can again be done much more elegantly and efficiently if we
have embedded Linux ported on to the ARM processor. Further more, it can always be
utilized as a firmware platform for the embedded modules for future projects.

8. Conclusion

The paper discussed a generic environment build of Linux for ARM core family. This
generic build has a limited functionality, as it just enables the kernel to boot and send
debug messages through the configured serial port. For a full fledged embedded module
this is quit elementary without the support for various peripherals through device drivers
which are paramount to the module. Linux kernel though monolithic has an excellent
modular approach which enables the driver modules to be attached and detached at run
time itself. This very much suits the embedded environment which are always constrained
for system memory. The open source GPL community is again a boon in terms of drivers
for new devices and also to fix issues which would otherwise cramp the development for
new platform ports.

Acknowledgement

This paper is the result of research efforts for the development of a UHF RFID reader,
under the National RFID program, sponsored and funded by the Department of Information
Technology, Ministry of communication and IT. The author expresses his gratitude to the
Department of IT and CDAC Management for giving the opportunity to work on the
project. The author also acknowledges Dr. George Varkey, Exec. Director CDAC NOIDA,
for his valuable guidance in completing the paper, Dr. P.R Gupta, Head School of IT,
CDAC NOIDA for her timely feedbacks and Sh. Sourish Behera, Project Manager, CDAC
NOIDA for his support during the project.

192
Porting Embedded Linux on ARM core

References

[1] http://www.kernel.org [last accessed on 24/12/08]


[2] http://www.arm.linux.org.uk [last accessed on 05/01/09]
[3] http://ftp.arm.linux.org.uk/pub/armlinux/toolchain/ [last accessed on 05/01/09]
[4] http://www.arm.linux.org.uk/developer/machines/[last accesed on 05/01/09]
[5] RusselKing“KernelCompilation”,http://www.arm.linux.org.uk/docs/,[last accessed on
06/01/09]
[6] RusselKing,“BootingARMLinux”,http://www.arm.linux.org.uk/developer/booting.ph
p, [lastaccessedon 15/01/09]
[7] Vincent Sanders, “Booting ARM Linux”, rev.1.10, June
2004.http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html [last
accessed on 15/01/09]
[8] http://sourceforge.net/projects/u-boot/ [last accessed on 20/12/08]
[9] Wooking and Tak-Shing, “Porting the Linux kernel to a new ARM Platform”, Aleph
One, vol. 4, summer 2002.
[10] Deepak Saxena, “porting Linux to a new ARM platform”, proceedings of “Linux
Banglore”, 2004.

About Author

Mr. Arivendu Bhardwaj received his Bachelor’s degree in Electronics


and Communication, from Kurukshetra University, Kurukshetra, and
P.G. Diploma in Embedded Systems and VLSI Design, from CDAC
NOIDA. He joined CDAC NOIDA in 2005, and is presently working
here as a Project Engineer, in Embedded Systems Lab. He has worked
on system programming for 8/16 bit microcontrollers, GSM/GPRS
engine, IP Set top Box and Linux internals. He is presently working in
the UHF RFID domain, involving single chip RFID Radio and ARM
firmware controller. His areas of interest include ARM architecture,
Linux kernel internals and inter chip communication protocols.

193

You might also like