My Tech notes
Subscribe

Unix Documentation

Free Online Unix Training Materials

Lists many links to free Unix training materials.

Pointers and Arrays Materials

Pointers and Arrays materials Explained for C beginners

C FAQ and General Questions C Interview Questions

Powered By

Free XML Skins for Blogger

Powered by Blogger

Friday, July 11, 2008


Porting Linux


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

Kernel linking and loading

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

  1. make menuconfig

  2. make zImage

  3. make modules

  4. Copy .ko files to respective directory; these directory will be copy of directory file structure on target board.

  5. run command create_flash_image kernel [./kernel source tree]; this will generate kernel image as scp_zimage.

  6. run command create_flash_image jffs2 [./target directory structure]; this will generate jffs2 file system with name flashdisk_jffs2.

  7. create_flash_image is a script 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.

/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





No comments:

Post a Comment