Benefits of browsing the Linux source code

September 20th, 2010 by admin 1 comment »

Going through the Linux source code is like picking the technical nuances of Linux first hand. Without an iota of doubt Linux within it has all the concepts and skills that a system programmer needs, I figured this out the hard way. Programming excellence can be achieved through ripping the source apart and diagnosing it. Let me list you some direct benefits ushered by source code reading

First hand information
You can read from books, get information from the Internet or by other means but nothing like knowing it first hand by exploring the Linux source code. This rich treasure of GNU/C code has got everything that you are looking for. This information leaves absolutely no space for any doubts as this is the final original source of information and there are zero alternates to this. As you comprehend these pieces of code it’s like going through the minds of the people who have actually written it. And this experience and the kind of learning involved will never be found anywhere.

Improve your conceptual clarity
As you follow the flow of the code, the concepts get unfolded and the maze starts to show you the way. Personally I go through this process whenever I’m tied in two minds on a particular OS concept. It cuts down the need for looking for other sources; however this needs some real experience. If you do this exercise regularly then I’m sure cracking or understanding any technical concept, even though it is not related to an OS becomes a piece of cake for you

Efficient code writing style and skill
Just look and appreciate the style and standards followed by this open source marvel that has stood the time and taken the brunt of real time performance and emerged as the best open project ever. The coding standards are so defined and stable that all these varied pieces of code contributions from all over the world has never brought this thing down. So one thing that you undoubtedly get is the skill to code like a top class pro.

Rock solid confidence
This requires serious mention, when I first started off with the initial versions of the Linux kernel the best thing that I got was a truck load of confidence. This single benefit was the sole reason for all my success as a programmer and as a trainer. Lack of confidence can even hinder the growth of a technically sound individual. So get that confidence right now with some useful source code reading

Increased adaptability to change
If you digest the design and frameworks on which these operating systems are build and if you go back to the previous versions of Linux and track down the progression you will no doubt heighten your clarity and grip on the subject. You will also become most adaptable to future changes and you can even predict technological changes, which may often become real. So this skill will equip you with the flexibility and adaptability to changes

Final word
I for sure know that this is a small list of benefits that source code browsing can bring to you. If you have done this before then I request you to add on to this list of benefit through your valuable feedback

Best time to learn Linux kernel programming as jobs gather steam

September 8th, 2010 by admin No comments »

-By Raghu Bharadwaj

“Linux device driver developer required, Chennai, apply now”
“Linux system programming professionals, Pune, apply now”
“Senior software engineer-Linux, Bangalore, apply now”

These are the kind of mails that are more visible in my inbox these days. Yes, days are back where you have requirements touching full steam. However this time it’s great news for system developers for obvious reasons.

New age consumer gadgets like smart phones, tablets, and other hand held devices are sweeping the consumer markets thus creating huge demand for professionals like you with the skills to develop software for these devices. For instance Android which runs on Linux is in huge demand and companies like Qualcomm, Sasken, Samsung , LGSoft, Sony among others, are looking for Linux experts who can seamlessly work on Android with a bit of training.

Recently most of my students were offered plum jobs with these companies, needless to say, most of them have received multiple job offers and are busy picking the right ones. I also received the below mentioned feedback from one of my student (Krishna Asthana) which is worth mentioning here

“I have mentioned the skills acquired at Veda in my resume, I may have appeared in 10+ interviews fetching in 7 offers and frankly speaking 90% of the companies were anxious to find out from where I did the course”

Most questions in these interviews were based on Linux OS internals and related concepts. To be precise there were questions ranging from Kernel space concepts, memory issues, driver development process and other project based issues. Bottom line is that these companies are seriously looking for programmers who command good knowledge on the Linux OS, in and out.

Key job gaining skills which most companies are looking for: Linux kernel Programming, Linux Drivers, Embedded Linux, Gnu c programming.

So if you are interested to make a decent career as a system programmer then believe me this is the best time to start. So pull up and start picking highly rewarding jobs now.

Benefits of learning an Online Linux Device Drivers course

August 30th, 2010 by admin No comments »

Though there are many reasons for participants to go for an online course when it comes to a high intensity courses like Linux Device Drivers, these were surveyed to be the major reasons for choosing it.

Learning System Programming should be slow and steady

By no stretch system programming is an easy and fast pill to swallow; it takes pure intention and good clean learning to seal things for you. As against normal application software learning where it is mostly restricted to functionality based learning, system programming like Linux Device Drivers involves deep understanding and analysis of issues like the Linux kernel and its subsystem. As an online course doesn’t mandate you to learn things daily, you can take it slowly and easily as you comprehend it. This makes learning Linux Device Drivers easier and more complete

More work involved

Conventional classroom based learning hammers you with daily doses of information and mostly leaves no room for putting theory to practice, this seriously dampens the learning and leaves the information indigested. As online learning can be taken at your own pace you get ample space to put theory to practice and move on once you mastered the topic.

Learn only when you are really prepared to

There are certain times when you really feel like getting to things and deal with it with maximum focus and force. Learning is no different; it’s these short spans of energy bursts which get you the best. As most online trainings are accessible 24×7 they empower you with using these times of peak interest to best use unlike conventional time bound training programs.

Redo portions which need double attention

Irrespective of how attentive you are during training sessions, some core sessions need that extra bit of attention or double the attention to grab the topic, sometimes you need to redo the topic all over again to get the complete picture. This is where an online course is truly unparalleled with its openness unlike classroom based training which can never be repeated

Manage learning easily against tight work schedules

As working professionals you may already be fighting time and even if you commit for a fixed time to learn you may often fail to keep up as scheduled. This on a continued basis may let your interest and focus deviate from learning. An online course helps you here with the freedom of time schedules and lets you learn only when you find the right time to do so.

Online courses may also bring you other benefits apart from the above mentioned. Final word is that it’s always better to go for an online course for a core training program like Linux Device Drivers

Embedded Linux Boot- Code Walkthrough

July 31st, 2010 by admin No comments »

By K.V.Mohan Reddy & Raghu Bharadwaj

This will be a series of articles Documenting Embedded Linux Boot sequence. This is part one.

Embedded Linux on Arm:
———————————-

We will walk through boot up code  for AT91RM9200 system-on-chip, built around the ARM920T ARM Thumb processor. Kwickbyte builds an embedded board called kb9202 based on AT91RM9200.

Before you start reading this you need to read AT91RM9200 data sheet (specification). You can download the data sheet with the following link.

www.keil.com/dd/docs/datashts/atmel/at91rm9200_ds.pdf

You also need to read ARM Architecture Reference Manual for better understanding the boot process. You can download it with the following link.

http://www.lysator.liu.se/~kjell-e/embedded/ARM-ARM.pdf

Components in Linux Boot Process:
———————————————–

Linux boot process involes the following components.

Bootloader
Kernel Image
Root Filesystem

Before we see how the above components work, the following is the call flow of Linux Kernel boot process for arm architecture. This gives a big picture on whole Linux boot process. We use U-boot bootloader.

ARM Linux Boot Process: Big Picture
U-boot:

_start (cpu/arm920t/start.S)

start_code (cpu/arm920t/start.S)

start_armboot (lib_arm/board.c)

board_init (board/kb9202/kb9202.c)

timer_init (cpu/arm920t/at91/timer.c)

serial_init (drivers/serial/at91rm9200_usart.c)

main_loop (lib_arm/board.c)

Now u-boot is up and running and is in u-boot prompt and ready to accept commands. Assume that kernel image is loaded into RAM and issued bootm command.

do_bootm (common/cmd_bootm.c)

bootm_start (common/cmd_bootm.c)

bootm_load_os (common/cmd_bootm.c)

do_bootm_linux (lib_arm/bootm.c)

stext (linux/arch/arm/kernel/head.S)

Control is given to linux.

Linux Kernel:

—————-

stext (arch/arm/kernel/head.S:78)

__lookup_processor_type (arch/arm/kernel/head-common.S:160)

__lookup_machine_type (arch/arm/kernel/head-common.S:211)

__create_page_tables (arch/arm/kernel/head.S:219)

__arm920_setup (arch/arm/mm/proc-arm920.S:389)

__enable_mmu (arch/arm/kernel/head.S:160)

__turn_mmu_on (arch/arm/kernel/head.S:205)

__switch_data (arch/arm/kernel/head-common.S:20)

start_kernel (init/main.c:529)

start_kernel (init/main.c:529)

tick_init(kernel/time/tick-common.c:413)

setup_arch (arch/arm/kernel/setup.c:666)

setup_machine (arch/arm/kernel/setup.c:369)

lookup_machine_type ( )

setup_command_line (init/main.c:408)

build_all_zonelists (mm/page_alloc.c:3031)

parse_args (kernel/params.c:129)

mm_init (init/main.c:516)

mem_init (arch/arm/mm/init.c:528)

kmem_cache_init (mm/slab.c, mm/slob.c, mm/slub.c)

sched_init (kernel/sched.c)

init_IRQ (arch/arm/kernel/irq.c)

init_timers (kernel/timer.c:1713)

hrtimers_init (kernel/hrtimer.c:1741)

softirq_init (kernel/softirq.c:674)

console_init (drivers/char/tty_io.c:3084)

vfs_caches_init (fs/dcache.c:2352)

mnt_init (fs/namespace.c:2308)

init_rootfs ()

init_mount_tree (fs/namespace.c:2285)

do_kern_mount (fs/namespace.c:1053)

set_fs_pwd(fs/fs_struct.c:29)

set_fs_root(fs/fs_struct.c:12)

bdev_cache_init (fs/block_dev.c:465)

chrdev_init (fs/char_dev.c:566)

signals_init (kernel/signal.c:2737)

rest_init (init/main.c:425)

kernel_thread (431, arch/arm/kernel/process.c:388)

kernel_thread() creates a kernel thread and control is given to kernel_init().

kernel_init (431, init/main.c:856)

do_basic_setup (888, init/main.c:787)

init_workqueues (789, kernel/workqueue.c:1204)

driver_init (793, drivers/base/init.c:20)

do_initcalls (796, init/main.c:769) /* Calls all subsytems init functions */

prepare_namespace (906, init/do_mounts.c:366)

initrd_load (399, init/do_mounts_initrd.c:107)

rd_load_image (117, init/do_mounts_rd.c:158) /* if initrd is given */

identify_ramdisk_image (179, init/do_mounts_rd.c:53)

handle_initrd (119, init/do_mounts_initrd.c:37) /*if rd_load_image is success */

mount_block_root (45, init/do_mounts.c:233)

do_mount_root (247, init/do_mounts.:218)

mount_root (417, init/do_mounts.c:334) /* if initrd not given */

mount_block_root (359, init/do_mounts.c:233)

do_mount_root (247, init/do_mounts.c:218)

init_post (915, init/main.c:816)

run_init_process (847, init/main.c:807)

kernel_execve (810, arch/arm/kernel/sys_arm.c:81)

|

User Space |

————- |

init() /*userspace /sbin/init */

Bootloader:

A bootloader is a small program which will load the kernel image into RAM and boots up the kernel image. This is also called bootstrap as it brings(pulls) up system by loading an operating system. Bootloader starts before any other software starts and initializes the processor and makes cpu ready to execute a program like an operating system. Most processors have a default address from which the first bytes of code are fetched upon power is applied or board is reset. Hardware designers use this information to store the bootloader code at that address in ROM or flash. Since it should initialize the cpu and should run a program which is located at architecture specific address bootloaders are highly processor specific and board specific. Every embedded board comes with a bootstrap to download the kernel image or standalone application into the board and start executing the kernel image or application. Bootloader will be executed when power is applied to a processor board. Basically it will have some minimal features to load the image and boot it up.

It is also possible to control the system using a hardware debug interface such as JTAG. This interface may be used to write the boot loader program into bootable non-volatile memory (e.g. flash) by instructing the processor core to perform the necessary actions to program non-volatile memory. Generally done for first time to download the basic bootloader and for some recovery process. JTAG is a standard and popular interface provided by many board vendors. Some micro controllers provide special hardware interfaces which can’t be used to take arbitrary control of a system or directly run code, but instead they allow the insertion of boot code into bootable non-volatile memory (like flash memory) via simple protocols. Then at the manufacturing phase, such interfaces are used to inject boot code (and possibly other code) into non-volatile memory. After system reset, the micro controller begins to execute code programmed into its non-volatile memory, just like usual processors are using ROMs for booting. In many cases such interfaces are implemented by hardwired logic. In other cases such interfaces could be created by software running in integrated on-chip boot ROM from GPIO pins.

There are some other third party bootloaders available which provide rich set of features and easy user interface. You can download these third party bootloaders into board and can make them default bootloaders for your board. Generally bootloaders provided by board vendors are replaced with these third party bootloader. There are a quite few third party boolader available and some of them are open source (or free bootloaders) and some are commercial. Some of them are Das U-Boot, Red boot, GRUB (for desktops), LILO , Loadlin, , bootsect-loader, SYSLINUX, EtherBoot, ELILO.

We will take U-boot boot loader as our boot loader. U-boot is the widely used boot loader in embedded systems. We will explain code from the u-boot-2010.03 source. You can download U-boot from the following site.

http://www.denx.de/wiki/U-Boot

How U-boot is built:

Based on the configuration of U-boot, all the assembly files (.S) and C files (.c) are compiled using cross compiler which is built for a particular architecture and object files(.o) will be generated. All these object files are linked by linker and an executable file will be created. An object file or executable file is a collection of sections like .text, .data, .bss etc. Object files and executable files have a file format like elf. All the sections of the object files will be arranged in the executable file based on a script called linker script. This script tells where all the sections are to be loaded in the memory when it runs. Understanding this script is very important to know how boot loader and kernel are composed and how different sections of boot loader or kernel are loaded in the memory.

Generally, when a program is run (executed) a loader reads executable file and loads different sections of the executable file in the specified memory location and starts executing the start function(entry point) specified in the linker script. But, if you want to run(load) a boot loader there will not be any loader to load(basically to understand the file format) different sections of executable file into the memory. Then you need to use a tool called objcopy which will take all sections from the executable file and create a binary file which doesn’t have any file format. This binary file can be loaded into the memory and executed or can be written in to the ROM at a particular address (specific to the architecture) which will be executed by cpu when power is applied to the board. You can find good tutorial on linker script in the following location.

http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/gnu-linker/scripts.html

Assume that based on the U-boot configuration all files are compiled and object files are created. U-boot makefile uses the following linker script (specific to architecture) to build an executable file.
File: cpu/arm920t/u-boot.lds

32 OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)

33 OUTPUT_ARCH(arm)

34 ENTRY(_start)

35 SECTIONS

36 {

37 . = 0×00000000;

38

39 . = ALIGN(4);

40 .text :

41 {

42 cpu/arm920t/start.o (.text)

43 *(.text)

44 }

4546 . = ALIGN(4);

47 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

48

49 . = ALIGN(4);

50 .data : { *(.data) }

51

52 . = ALIGN(4);

53 .got : { *(.got) }

54

55 . = .;

56 __u_boot_cmd_start = .;

57 .u_boot_cmd : { *(.u_boot_cmd) }

58 __u_boot_cmd_end = .;

59

60 . = ALIGN(4);

61 __bss_start = .;

62 .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }

63 _end = .;

64 }

OUTPUT_FORMAT in line #32 specify the file format of the executable file. Here the executable file format is elf32 and endianness is little endian. OUTPUT_ARCH in line # 33 specify the architecture on which this code runs. ENTRY in line #34 specifies the start function(entry point) of u-boot program. Here the entry point is _start.

SECTIONS in line #35 defines how different sections are mapped in the executable file. Loader uses the addresses specified in this section to load different section of the program into the memory.

‘.’ in the line #37 specifies the start address where the following sections should be loaded. In this case start address is 0×00000000. After this in line #39 the memory is aligned by 4 bytes and the .text section follows in the line #40.

40 .text :

41 {

42 cpu/arm920t/start.o (.text)

43 *(.text)

44 }

At the ‘.’ position (0×00000000) the code in the cpu/arm920t/start.o is mapped and follows the code that is there in .text sections of all other object (.o) files. cpu/arm920t/start.o contains the _start() function(in assembly language) which is entry point of this program.

Now the ‘.’ will be at 0×00000000 + sizeof (.text). Again memory is aligned by 4 bytes and .rodata section follows in line #47.

. = ALIGN(4);

47 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

.rodata sections from all objects files are mapped at this address. Follows the .data and .git sections.

49 . = ALIGN(4);

50 .data : { *(.data) }

51

52 . = ALIGN(4);

53 .got : { *(.got) }

Each U-boot command is an object of type ‘cmd_tbl_t’ which contains command name, help string and function pointer to be executed when this command is run. All these command objects are placed in the memory sequentially. Each of this command object is built into an U-boot defined section called .u_boot_cmd in the object file. These all .u_boot_cmd sections are placed in the memory after the above sections(.data and .git).

. = .;

56 __u_boot_cmd_start = .;

57 .u_boot_cmd : { *(.u_boot_cmd) }

58 __u_boot_cmd_end = .;

__u_boot_cmd_start contains the start of the commands objects and __u_boot_cmd_end contains the end of the command objects.

And next follows the .bss (uninitialized global variables) sections.

60 . = ALIGN(4);

61 __bss_start = .;

62 .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }

63 _end = .;

__bss_start points to the .bss start address and _end contains the end of the all sections.

Using this linker script linker will generate an executable file called u-boot. Objcopy tool is used to generate a binary file from the u-boot executable file.

u-boot.bin: u-boot

$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
U-boot binary file will be copied to the board RAM or written in the flash disk. At91rm9200 board comes with a boot programer, A tiny program called atmel bootstrap that can be used to download the image into flash or RAM and start execute or to reset a corrupted board. U-boot will be copied to flash disk or internal RAM( if it is less size) and will be downloaded to RAM and will be executed when the board power is applied to the board. For this board(at91rm9200) the code is always downloaded from device address 0×0000_0000 to the address 0×0000_0000 of the SRAM after remap. That ’s why we have given the start address of the .text section as 0×00000000. If you want to load the code any where in the RAM and want to execute U-boot you need to build you code as position independent code(PIC). Then the instructions addresses will be offset into to PC(cpu register) value. So the downloaded code must be position-independent or linked at address 0×0000_0000. For our explanation purpose assume that U-boot code is linked at 0×00000000 and the Boot program downloaded U-boot from the data flash(Check AT91RM9200 spec for downloading process)) and call entry point into the U-boot.

In the Linux boot process Part 2 we will see U-boot execution.

Linux for space constrained small embedded devices

June 1st, 2010 by admin No comments »

By Raghu Bharadwaj

A considerable segment of embedded systems are often found in mass-market products and are therefore subjected to hard economic constraints. The basic nature of these systems mandates further constraints on physical size and power consumption. These in turn give rise to resource constraints on the computing platform level, e.g., constraints on computing speed, memory size, and communication bandwidth etc.  In spite of the rapid development of computer hardware these constraints are true due to the economic overheads. In most cases it is not economically justified to use a processor with more capacity due to the overall product’s cost limits.

Now coming to the software that goes into these space crunched hardware?

 A recent survey conducted on small embedded device manufacturers revealed the following facts.

Most of these vendors avoided using embedded operating systems and the response was a straightforward, “we don’t need one.” More than half of these vendors mentioned a simple lack of need as the sole reason for skipping the operating-system. It’s easy to think of many products that might not need an OS so this response isn’t surprising. Out of those about 30% said an OS will strain their system’s processor and/or memory. Some said an OS was too expensive and the remaining felt that operating systems are too complicated. However the need for an embedded OS was felt considering the fast changing demands of the consumers, who are looking for multi-purpose small embedded devices, which mandates the use of an OS

 

Now the question, what is the most economical and easy OS solution?

This brings up Linux as a viable option. Let’s explore the reasons behind this choice and most importantly understand how it can be used on these space constrained devices?

  • Linux is open source kernel backed by a strong community of developers; members of the community provide bug fixes, enhancements, and even support old devices long after the manufacture has ceased support.

 

  • Linux offers a large library of functionality that can be leveraged to accelerate development. Linux is easy to customize and port even on to MMU less processors. With Linux community’s commitment to support embedded systems and various embedded hardware vendors contributing development tools and support .Linux is the best bet to migrate from hardware specific code to richer software.

 

Linux kernel is massive collection of sources targeting various architectures and platforms. Linux kernel currently contains around 9.2 million lines of code with a 10% increase every year. With the current versioning pattern new stable kernel is available every 3 to 4 months. Linux Currently supports

25 different architectures, 60 Filesystems , 20 net protocols(L2), 50+ ATA Drivers, 300+ pci Drivers, 200+ Ethernet Drivers

“Linux supports more individual types of devices overall than any other kernel”

                        -Greg KH 

Default vanilla kernel configuration includes full network support, support for wide variety of input devices, and does not offer fixed boot time (can afford the time delays related to device discovery).

So with all these code buried within Linux, how can we fit it into these small devices?

  • Disabling unrequired Device drivers and file systems like Ext2, Ext3 (not required on mass storage less embedded devices)

 

  • Disabling unrequired network protocols and other network services like Net filters, packet forwarding etc…

  

  • Disabling symmetric multi-processor support when not running on dual CPU boards. This reduces the kernel image size and also results in better performance on uniprocessor machines

  

  • Removing support for other CPU variants for the architecture we have selected would help    us reduce kernel image size by stripping out unrequired start up code.

 

  • Disable support for Dynamic configuration of kernel parameters through sysctl’s.

 

  • Reduce the kernel log buffer to 4k (default 16k).

 

  • Support for hotplug events / user space notifications are often not required in Embedded systems kernel so choosing to disable them would help reduce kernel image size

 

  • Enable CONFIG_EMBEDDED which enables a group option to further trim down the kernel. Notable options enabled are the ability to select a different allocator and a selection to optimize for size (CONFIG_CC_OPTIMIZE_FOR_SIZE).

 

  • Current kernels are by default set to SLAB allocator which is more efficient on the large memory desktop machines. So enable SLOB allocator which perfectly suits smaller, resource limited devices.

 

  • Modules under Linux allow kernel code to be dynamically installed or removed. However, to accomplish this, each module is loaded onto a fresh page. This has two consequences. On architectures that support large memory pages, modules do not share the large page typically used by the primary kernel code. Consequences of this is another page table entry is needed and page table caches may get thrashed more which may be a  potential performance impact. A second consequence is if a module is the page size plus one byte, the total memory consumed is 2 entire pages. This is almost 50% waste. Or in another case if the module is small, a full page has to be allocated. If the page size is 4K and the module is only 1K, this is a 300% waste. If many such modules are loaded, there can be considerable waste of memory

 

  • Consider UClinux when there are no stringent MMU requirements

 

  • Other issues apart from normal selections include appropriate tagging of disposable code. Custom drivers or even existing drivers should have the initialization code tagged appropriately so memory occupied by them can be freed. This can be done by the use of the GCC   __init attribute.

 

  • Developers also need to be aware of performance constraints with XIP(Execute in place) NOR flashes on some custom hardware. XIP allows the kernel to run form the same place that it is stored. This requires the flash to appear as linear memory. On custom hardware (such as certain ARM based systems) the bus for interfacing to NOR flash may be smaller than the native size of the processors for ex: 16bit NOR memory interface requiring two access cycles to load a native size piece of data, 32bits wide. This would result in massive performance bottleneck. In addition, XIP prevents the use of compressed kernel images.

  

These are some of the performance and space tuning options available on Linux. In the next part we will discuss about the application tuning options.

www.techveda.org

info@techveda.org