Porting Linux To ARM
Porting Linux To ARM
Arivendu Bhardwaj
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.
184
Porting Embedded Linux on ARM core
Device drivers
Operating System
Peripheral Peripheral
Processor (ARM)
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
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].
This section describes the setting up of Kernel sources, the required tool chains,
environment set up and the kernel compilation.
186
Porting Embedded Linux on ARM core
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
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
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
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)
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’).
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
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.
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.
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]
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 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
About Author
193