Booting Linux
Introduction 3
About boot loader 3
Known components of Hardware block 4
[ARM926ejs core] 4
[Cache] 4
[MMU/TLB] 4
Linux kernel 5
Basic understanding of kernel internal 5
Specific patches added in kernel 6
Specific adaptions and patches for MCS8140 6
Compiling and using Linux kernel 6
Debugging kernel 8
JTAG- 8
Porting Linux step by step 8
Step 1 Machine registration 8
Step 2 Firmware to kernel transition 8
Step 3 Early kernel init 9
Step 4 Mapping I/O devices 10
Step 5 IRQ setup 10
Step 6 system timer tick 10
Step 7 board level initialization 11
MCS8140 specific peripherals 12
Root file system 15
Creating a JFFS2 file system 15
/bin and /sbin 16
About busybox 16
/etc 16
About /init.d/rcS 17
/dev 17
/proc 17
/tmp 17
/var 17
/lib 17
/mnt 17
/modules 17
/usr 17
/sys 17
Introduction
This document contains basic information about what are steps involved in building Linux for MCS8140, this board uses internal boot loader called I-boot and external boot loader called U-boot.
Building embedded Linux system consists of three parts, the bootloader, the Linux kernel, and the graphical user interface (or GUI). Attempt is made here to present understanding of linux kernel.
About boot loader
The typical bootloader performs the following types of functions:
Initialize CPU speed
Initialize memory, which includes enabling memory banks, initializing memory configuration registers, and so on
Initialize serial port (if present on the target).
Enable instruction/data caches.
Set up stack pointer.
Set up parameter area and construct parameter structures and tags (this is an important step, as boot parameters are used by the kernel in identifying root device, page size, memory size and more).
Perform POST (Power On Self Test) to identify the devices present and to report any problems.
Provide support for suspend/resume for power management.
Jump to start of kernel.
Known components of Hardware block
[Brief about hardware components involved in; need to have understanding of processor core, cache, MMU/TLB, memory map ]
[ARM926ejs core]
[Cache]
[MMU/TLB]
Linux kernel
The Linux kernel we are using for MCS8140 is linux-2.6.15. This kernel has so many features in built; we are using the following kernel features for MCS8140.
1) Kernel module support added.
2) Enabled ARM926 processor support and thumb instruction set support.
3) MMU support enabled.
4) PCI host support and hot plug enabled.
5) IPV4 TCP/IP stack enabled
6) IEEE80211 wireless support enabled.
7) Incorporated the flash device driver for supporting flash memory.
8) Enabled char, block devices support.
9) Ramdisk support enabled.
10) Enabled SCSI support.
11) PROC file system support.
12) SATA support enabled.
13) Enabled network device support.
14) Generic serial console (8250) support enabled.
15) Enabled sound support in kernel.
16) USB EHCI, OHCI support.
17) USB dev,sys file system.
18) Enabled ext2,ext3, minix, VFAT, FAT,MSDOS,NTFS,RAMFS file systems.
19) Enabled JFFS2, NFS, SMB file system support.
The features added to kernel which are specific to MCS8140 are: (we can enable the options in kernel in menuconfig by adding the options in Kconfig files in their respective modules.)
1) Added on board Ethernet driver to the kernel.
2) Added List processor and TCP segmentation offloading support to Ethernet driver.
3) Added board specific serial driver.
4) Added board specific sound driver. (I2S codec)
5) Added USBIP application module.
Basic understanding of kernel internal
The kernel layout is divided into architecture-specific and architecture-independent parts. The architecture-specific part of the kernel executes first and sets up hardware registers, configures the memory map, performs architecture-specific initialization, and then transfers control to the architecture-independent part of the kernel. It is during this second phase that the rest of the system is initialized. The directory arch/ under the kernel tree consists of different subdirectories, each for a different architecture (MIPS, ARM, i386, SPARC, PPC, and so on). Each of these subdirectories includes kernel/ and mm/ subdirectories, which contain architecture-specific code to do things like initialize memory, set up IRQs, enable cache, set up kernel page tables, and so on. These functions are called first once the kernel is loaded and given control, then the rest of the system is initialized.
The kernel can be compiled either as vmlinux, Image, or zImage depending on the available system resources and the functionality of the bootloader. The main difference between vmlinux and zImage is that vmlinux is the real (uncompressed) executable, while zImage is a self-extracting compressed file containing more or less the same information.
Specific patches added in kernel
The wireless drivers which are not available directly in 2.6.15 kernel are downloaded and added to our CVS tree.
These include Broadcom driver, Ralink drivers. (Available in drivers/net/wireless folder)
Specific adaptions and patches for MCS8140
UART, Timer, Interrupt Controller are must for Linux (these will come into basic Linux kernel porting section).
PCI Host driver
USB Host driver
EHCI,OHCI drivers.
MAC Driver (Includes LP & TSO & Cipher)
Audio Drivers.
Compiling and using Linux kernel
The kernel executable consists of many object files linked together. The object files have many sections such as text, data, init data, bass, and so forth. These object files are linked and loaded by a file known as a linker script. The function of the linker script is to map the sections of the input object files into an output file; in other words, it links all the input object files into a single executable whose sections are loaded at specified addresses. vmlinux.lds is the kernel linker script present in the arch/<target>/ directory, and it is responsible for linking the various sections of the kernel and loading them at a particular offset in memory.
Parameter passing and kernel boot up
stext(from lds file) is the kernel entry point, which means that the code under this section is the first to execute when the kernel boots up. It is usually written in assembly, and is normally present under the arch/<target>/ kernel directory. The code sets up the kernel page directory, creates identity kernel mapping, identifies architecture and processor, and branches to start_kernel (the main routine whereby the system is initialized).
start_kernel calls setup_arch as the first step where the architecture-specific setup is done. This includes initializing hardware registers, identifying the root device and the amount of DRAM and flash available in the system, specifying the number of pages available in the system, the filesystem size, and so on. All this information is passed in parameter form from the bootloader to the kernel.
There are two ways to pass parameters from bootloader to kernel: parameter_structure and a tag list. Of these, param structure is deprecated as it imposes restrictions by specifying that each and every parameter has to be at a particular offset within param_struct in memory. Recent kernels expect parameters to be passed as a tag list and will convert parameters to a tagged format. param_struct is defined in include/asm/setup.h. Some of its important fields are:
struct param_struct {
unsigned long page_size; /* 0: Size of the page */
unsigned long nr_pages; /* 4: Number of pages in the system */
unsigned long ramdisk /* 8: ramdisk size */
unsigned long rootdev; /* 16: Number representing the root device */
unsigned long initrd_start; /* 64: starting address of initial ramdisk */
/* This can be either in flash/dram */
unsigned long initrd_size; /* 68: size of initial ramdisk */
}
Note that the numbers represent the offset within the param structure where the fields are to be defined. This means that if the bootloader places the parameter structure at address 0xc0000100, then the rootdev parameter is placed at 0xc0000100 + 16, initrd_start is placed at 0xc0000100 + 64, and so on -- otherwise, the kernel will encounter difficulties in interpreting the correct parameters.
In a tagged list, each tag consists of a tag_header that identifies the parameter passed, followed by values for the parameter. The general format for a tag in the tag list could be as follows:
The kernel identifies each tag by the <ATAG_TAGNAME> header.
#define <aTAG_TAGNAME> <Some Magic number>
struct <tag_tagname> {
u32 <tag_param>;
u32 <tag_param>;
};
/* Example tag for passing memory information */
#define ATAG_MEM 0x54410002 /* Magic number */
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
The setup_arch also needs to perform any memory mappings for flash banks, system registers, and other specific devices. Once the architecture-specific setup is done, control returns to the start_kernel function where the rest of the system is initialized. These additional initialization tasks include:
Setting up traps
Initializing interrupts
Initializing timers
Initializing console
Calling mem_init, which calculates the number of pages in various zones, high memory, and so on
Initializing the slab allocator and creating slab caches for VFS, buffer cache, etc.
Setting up various filesystems like proc, ext2, JFFS2
Creating kernel_thread, which execs the init command in the filesystem and displays the lign prompt. If no init program is present in /bin, /sbin, or /etc, the kernel will execute the shell present in /bin of the filesystem.
Debugging kernel
JTAG-
Porting Linux step by step
Below steps provides brief explanation about porting linux to ARM; these steps are very general.
Step 1 Machine registration
Register the machine type. In arch/arm/tools/mach-types
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
scp ARCH_SCP SCP 900
This provides a unique numerical identifier for your machine, also provides configuration variable for your machine as CONFIG_MACH_$MACHINE.
Provides runtime machine-check (machine_is_xxx).
Step 2 Firmware to kernel transition
Requires boot loader to
● Initialize all memory controller and system RAM
● Initialize a single serial port for early boot messages
● Disable MMU
● Disable all caches
● Provide kernel parameter ATAG list
● Required registers:
– r0 = 0
– r1 = machine number
r2 = &(ATAG list)
We are using U-boot.
ATAG list is a data structure for providing machine details to kernel.
Usually located in first 16KB of RAM, most common is @RAM base + 0x0100.
ATAG list is defined in include/asm-arm/setup.h.
ATAG list consists of
ATAG_CORE- start of parameter list.
ATAG_MEM- memory size and location one per memory blocks.
ATAG_NONE- end of parameter list.
Directory file structure which need to be taken care while modifying,
● arch/arm/
– mm
● Cache/TLB/page fault/DMA handling
– kernel
● core kernel setup, APIs, and syscall handling
– lib
● low-level helper functions (mostly ASM)
– common
● code shared across various machine types
– arch-$MACHINE
● Machine-type specific code (arch-ixp425, -pxa, -omap, etc)
– configs/$PLATFORM_defconfig
● Default configuration for $PLATFORM (lubbock, ipaq, etc)
● include/asm-arm/arch-$MACHINE (include/asm/arch)
– Machine-specific headers
Step 3 Early kernel init
At this stage kernel starts decompression, calling arch_decomp_setup(), during this stage it initializes serial port(if any), to see the messages.
Need to detect the CPU before starts initialization,
Kernel contains table of CPUs it supports in
arch/arm/mm/proc-$CPUTYPE
include/asm-arm/procinfo.h
First thing kernel does is check CPUID with table of CPUs
– Table contains a mask and expected value
If (cpuid & cpu_mask) == cpu_val we are OK
Otherwise we can't run on this CPU
– If OK, call CPU's _setup function.
If CPU is detected OK
Check for the machine type
Each platform has a machine descriptor structure: like
MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
MAINTAINER("MontaVista Software, Inc.")
BOOT_MEM(PHYS_OFFSET,
IXP4XX_PERIPHERAL_BASE_PHYS,
IXP4XX_PERIPHERAL_BASE_VIRT)
MAPIO(ixdp425_map_io)
INITIRQ(ixp4xx_init_irq)
.timer = &ixp4xx_timer,
BOOT_PARAMS(0x0100)
INIT_MACHINE(ixdp425_init)
MACHINE_END
Machine name/number from can be obtained from arch/arm/tool/mach-types.
Step 4 Mapping I/O devices
Certain devices need to be mapped before VM is fully up and running.
Like interrupt controller
Timer tick
Also certain devices need large virtual memory area
Static mapping allows usage of 1MB sections.
ioremap() uses only 4K pages
Call mdesc->map_io()
Call create_mapping() with static I/O mappings.
ARM-Linux Memory Map
Step 5 IRQ setup
IRQ are defined in defined in include/asm-arm/arch/irqs.h; with macro NR_IRQS
IRQ numbering is upto developer.
First level IRQ decoding is done in
include/asm/arch-$MACHINE/entry-macro.S
get_irqnr_and_base irqnr, irqstat, base, tmp
Step 6 system timer tick
This is initialized after IRQ.
Load timer with LATCH,
● ((CLOCK_TICK_RATE + HZ/2) / HZ)
● CLOCK_TICK_RATE is HW clock freq.
Request timer interrupt.
Set SA_INTERRUPT
Timer ticks every (1/HZ)s
For getting timer interrupt, call first timer_tick() function.
gettimeoffset() function returns no of microseconds since last timer tick.
Step 7 board level initialization
Board_init() function is called; which adds platform devices such as flash, I2C etc. This is very board specific.
MCS8140 specific peripherals
[List out peripherals and write brief about what are file changes done in kernel source tree to support these peripherals]
Directory | Files changed | Purpose |
Target related changes | ||
Arch/arm/mach-scp | Added new dir |
|
| irq.c | Interrupt management on MCS8140 (clear_irq, mask_irq, unmask_irq) ,do_level_irq, pci , usb routines. |
arch.c | Arch type and name mentioning, ,Configuring size and start of SDRAM | |
pci.c | PCI bus registration, memory, irq mappings, configuration space reading routines. | |
Arch/arm/boot/compressed | /head-scp.S | - mov r7, #MACH_TYPE_SCP |
Arch/arm/boot/bootp | /init.S | Taking the param_struct out of "tag list" , "param_struct". |
include/asm-arm/arch-scp | Added new dir |
|
|
dma.h | DMA hardware details e.g DMA channels, Max. DMA addr.( No changes) |
hardware.h | Hardware mapping and base addr for all blocks e.g. BASE addr, offsets for PCI, USB, MAC etc.. | |
io.h | Macros to perform various read/write operations | |
irqs.h | IRQ's numbers. memory mapping , some definitions for IRQs. | |
keyboard.h | Minor change - File not required | |
memory.h | defines phys_to_virt and vice-versa | |
pch.h | packet cache manipulation functions ( not required) | |
param.h | reserved for future use | |
serial_reg.h | Definitions for serial port usage | |
system.h | Routines for cpu soft reset and cpu idle. | |
time.h | System timer initialization, routines for timer offset and it's interrupt. | |
uncompress.h | serial console putc and puts funtions | |
timex.h | clock tick rate | |
vmalloc.h | virtual memory allocation , start, offset, end definitions. | |
Arch/arm/kernel | /entry-armv.S | deals preempt changes |
| /fiq.c | __asm_volatile changes for fiq. |
Arch/arm/boot | /Makefile | Defines memory map symbols related to MCS8140 board and exports them Defines "arch/arm/boot/bootp/rdisk.bin.gz" as INITRD |
Arch/arm/boot/compressed | /head.S | Starting file to load and relocate the kernel. Enabled the D-Cache to have fast Uncompression of linux image on bootup. |
Driver file changes | ||
drivers/char | /tty_io.c | Initialization of serial console. |
drivers/serial | /serial_scp.c | serial console code. |
drivers/net | /Space.c | Ethernet probe added. |
include/linux | /skbuff.h | Chiefly added SKB debug messages apart from some minor target specifics. |
net/core | /skbuff.c | Target specific enhacements related to packet cache |
Init | /main.c | Console initilization delayed - Seems like not necessary. |
Config and Makefile changes | ||
Arch/arm/mach-scp | /Makefile | Simple makefile for new C files in this directory. |
drivers/net
| /Config.in | "tristate ' SCP FIQ network support' CONFIG_SCP_FIQ_ETHER" |
/Makefile | FIQ modules added. | |
drivers/serial
| /Config.in | CONFIG_SERIAL_SCP |
/Makefile | serial_scp.o modules added. | |
Arch/arm | /config.in | Config file for adding SCP Architecture. |
Arch/arm/boot/compressed | /Makefile | Config file for adding head_scp.o module. |
| Makefile | - Added info regarding the ARCH type, CC and path to MODLIB sym.link for asm-arm -> asm. |
Kernel | /ksyms.c | Preempt_schedule exported ifdef CONFIG_PREEMPT |
Arch/arm/kernel | /Makefile | - Add fiq.o module support if CONFIG_SCP_FIQ_ETHER defined |
Arch/arm/tools | /mach-types | ARCH_SCP 900 added. |
arch/arm | /Makefile | changed to hard float and ifeq ($(CONFIG_ARCH_SCP),y) MACHINE = scp. sym.link for arch-scp -> arch & proc-armv -> proc . copied below line, machine-$(CONFIG_ARCH_SCP) := scp |
Arch/arm/boot/bootp | /rdisk.bin.gz | - compressed bin file which is defined as INITRD |
Arch/arm | /defconfig | Default kernel config file |
arch/arm/def-configs
| /scp_modules | Selects what components to be built as modules. |
/scp_builtin | Selects what components to be made part of the kernel | |
Net | /Config.in | Selects the Driver SKB pool , PCH, Net profiling ,if CONFIG_ARCH_SCP is there. |
drivers/mtd/maps/ | Scp.c | Partitioning of flash for bootloader, environment variables, kernel and file system. |
MAC, LP ,TSO driver | ||
drivers/net/arm | /mcs8140 | New directory for ethernet driver. |
Root file system
We are using Journaling Flash File System, version 2 (JFFS2) in MCS8140.
Creating a JFFS2 file system
Basic steps for creating JFFS2 file
A JFFS2 file system (basically a Ram disk using JFFS2) is created under Linux with the mkfs.jffs2 command as follows
mkdir jffsfile
cd jffsfile
/* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries that are needed for the filesystem here */
/*Type the following command under jffsfile directory to create the JFFS2 Image */
./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image
The -e option specifies the erase sector size of the flash (typically 64 kilobytes). The -p option is used to pad the remaining space in the image with zeroes. The -o option is used for the output file, which is usually the JFFS2 filesystem image -- in this case, jffs.image.
Before creating root file system we need to compile the kernel and make kernel image.
Steps in compiling kernel
make menuconfig
make zImage
make modules
Copy .ko files to respective directory; these directory will be copy of directory file structure on target board.
run command create_flash_image kernel [./kernel source tree]; this will generate kernel image as scp_zimage.
run command create_flash_image jffs2 [./target directory structure]; this will generate jffs2 file system with name flashdisk_jffs2.
A JFFS2 file system (basically a Ram disk using JFFS2) is created under Linux with the mkfs.jffs2 command as follows
mkdir jffsfile
cd jffsfile
/* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries that are needed for the filesystem here */
/*Type the following command under jffsfile directory to create the JFFS2 Image */
./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image
The -e option specifies the erase sector size of the flash (typically 64 kilobytes). The -p option is used to pad the remaining space in the image with zeroes. The -o option is used for the output file, which is usually the JFFS2 filesystem image -- in this case, jffs.image.
/bin and /sbin
The /bin directory contains essential user command binaries and /sbin directory contains essential system administration binaries.
About busybox
BusyBox is a single executable implementation of many standard Linux utilities. BusyBox contains simple utilities, such as cat and echo, as well as larger, more complex tools, such as grep, find, mount, and telnet (albeit, with fewer options than the traditional version); some refer to BusyBox as the Swiss Army knife of utilities. Busybox is a key component of MCS8140, as it gives extremely small footprint (A multi-call binary can perform the functions of many different applications.) for MCS8140 it is 971KB, compaired to standard linux utilites size as 3.4MB.
The easiest way for BusyBox to perform the function of one of the applications that it can emulate is by creating and naming a symbolic link and connecting it to the BusyBox binary. You then type the name of the symbolic link, which executes BusyBox. BusyBox uses symbolic links to make one executable look like many. For each of the utilities contained within BusyBox, a symbolic link is created so that BusyBox is invoked. BusyBox then invokes the internal utility as defined by argv[0].
Currently defined functions in busybox v1.1.3 are
[, [[, addgroup, adduser, ash, awk, basename, bunzip2, busybox,
bzcat, cat, chgrp, chmod, chown, chroot, clear, cp, cut, date,
dd, delgroup, deluser, df, dirname, dmesg, du, echo, egrep, env,
expr, false, fdisk, fgrep, find, free, freeramdisk, ftpget, ftpput,
getty, grep, gunzip, gzip, halt, head, hostname, id, ifconfig,
init, insmod, kill, killall, klogd, linuxrc, ln, logger, login,
ls, lsmod, mesg, mkdir, mkfs.minix, mknod, modprobe, more, mount,
mv, netstat, nslookup, passwd, ping, poweroff, printf, ps, pwd,
reboot, reset, rm, rmdir, rmmod, route, sed, sh, sleep, sort,
start-stop-daemon, su, sulogin, sync, syslogd, tail, tar, tee,
telnet, telnetd, test, tftp, time, top, touch, tr, umount, uname,
uniq, unzip, uptime, usleep, vi, vlock, wc, which, who, whoami,
zcat
These all functions which are present in /bin and /sbin are symbolic link to busybox bin.
/etc
This directory contains system configuration files, including startup files.
About /init.d/rcS
This startup script present in /etc directory creates ramdisk of 42MB, this is being used for storing temporary messages. Actually /tmp -> rdisk0/tmp means /tmp directory is a link to rdisk0/tmp and /var is link to rdisk0/var. After creating ramdisk and /tmp and /var folders this script file starts syslogd and klogd daemons.
/dev
This directory contains devices and other special files.
/proc
This directory contains virtual file system for kernel and process information. This is useful for mounting virtual file system.
/tmp
It contains temporary files.
/var
It contains variable data stored by daemons and utilities.
/lib
It contains essential libraries, such as C library and kernel modules.
/mnt
It contains mount point for temporarily mounted file system.
/modules
It contains specific modules related to hardware block developed.
/usr
This is secondary hierarchy containing most applications and documents useful to most users.
/sys
Comments