| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • Stop wasting time looking for files and revisions. Connect your Gmail, DriveDropbox, and Slack accounts and in less than 2 minutes, Dokkio will automatically organize all your file attachments. Learn more and claim your free account.

View
 

linux

Page history last edited by PBworks 14 years, 2 months ago

Linux on ARMputer

 

EE-692 -- R&D PROJECT

 

 

  • Acknowledgement

 

I would like to thank Prof. D.K.Sharma for his invaluable time that he has so generously given to me in past 4 months. I am thankful to Ashrut Ambastha for this support and mentorship throughout the project. I am grateful to Mr. Dave Anders for his constant help and always pointing to the correct sources. Dave has been microsoft free since 1997 and can be reached at : http://www.elinux.org/wiki/prpplague

 

-- Aneesh Nainani

aneeshnainani@gmail.com

 

  • Hardware Info

 

The motivation behind this project is to boot linux on a ARM board.

 

The hardware config is as follows -

- We are using a ARM720T based Sharp SoC LH79520

- 16Mb of SDRAM (Sharp - MT48LC2M32)

- 4Mb Flash (LHF00L15) ( not CFI complaint )

 

 

All of this was developed by Ashrut Ambastha (IIT-Bombay), if you have doubts regarding the hardware config or want to make a ARM development board yourself you can get in touch with him on elecashrut@yahoo.com.

 

Though i have mentioned the hardware for the sake of completeness, my job to put in the simplest of words is to boot linux on a LH79520 based board with 16M of RAM ( the FLASH being non-CFI complaint nor uses a standard INTEL command set, hence is of no good exceot to store the boot loader). I would be most happy to see a bash prompt on the minicom window. A output like given below will mark the termination of the project.

 

$ cat /proc/meminfo

total: used: free: shared: buffers:

cached:

Mem: 6897664 4481024 2416640 0 77824

2781184

Swap: 0 0 0

MemTotal: 6736 kB

MemFree: 2360 kB

MemShared: 0 kB

Buffers: 76 kB

Cached: 2716 kB

SwapCached: 0 kB

Active: 580 kB

Inactive: 2640 kB

HighTotal: 0 kB

HighFree: 0 kB

LowTotal: 6736 kB

LowFree: 2360 kB

SwapTotal: 0 kB

SwapFree: 0 kB

$ df -h

Filesystem Size Used Available

Use% Mounted on

/dev/root.old 1.9M 1.4M 509.0k

73% /

$

 

  • Introduction - Embedded Linux Fundamentals

 

The fundamental requirement for a GNU/Linux system is a kernel and a filing system for it to execute things from.

 

The kernel is an autonomous piece of code that doesn't need any other files or libraries to get started, although without a root filing system it will simply stop after initialising the system as it no files to operate on.

 

The filing system can be loaded from a range of different hardware devices (hard disk, RAM, ROM, CD and NFS mount) and must be in a format that the kernel understands. For embedded systems it is often a RAMdisk. The kernel and RAMdisk both need to be loaded to correct places in memory and the kernel executed. This can be done in various ways, typically by loading over a serial connection or from local flash RAM.

 

In order to be able to load anything from anywhere some kind of bootloader must be present on the target hardware which knows how to load files and execute them. This can be installed in a physical fashion by inserting a pre-programmed ROM/EEPROM or flash chip, but is more usually installed using a JTAG port, which allows instructions to be executed from an external input, and thus an initial program loaded.

 

There are many peculiarities involved with booting linux on an embedded system as compared to a PC such as cross compiling, debugging etc which will be taken as they incurre in the following section.

 

The wisdom that we are presently using is :

 

 

  1. Load Bootloader to the flash using JTAG (using Jflash-linux)
  2. Bootloader (apex) receives the RAMdisk over serial port (using Xmodem protocol ) stores in the RAM
  3. Bootloader receives Kernel image over the serial port and stores it in the RAM
  4. boot linux with both Kernel image and RAMdisk present in the RAM

 

  • Jflash-linux

 

Getting the target side of the bootloader installed is normally done with the Jflash utility (both Windows and Linux versions exist). This drives the JTAG interface through the parallel port of the host PC. The Linux version is called JFlash-linux.

 

Note that this program is different for each target as it depends on knowing the exact hardware of the target.

 

The included source code was slightly modified for LH79520 by Dave Anders (dav123_aml@yahoo.com). It was then modified to support the flash chip we are using by yours truly.

 

On Linux, this should be compiled with:

 

gcc -O2 -s -o Jflash-linux Jflash.cpp

 

There's a warning about 'gets' being dangerous. If someone could tell me (Dave) what _should_ be used, I'll get rid of it. Dont play around much with the JTAG functions as some linux developers quote "JTAG is a real brain-damaged protocol (it was designed by a committee, need we say more?)".

 

The executable can only be used by root. Please be sure their arent any application ( check _minicom_ in particular) using your parallel port to avoid conflicts.

 

  • The Bootloader

 

Bootloaders are highly system-specific. The two choices we had for a bootloader for LH79520 were Blob and Apex.

 

Blob is the Boot Loader OBject. Blob started its life as a boot loader for the famous LART, but a patch is available for lh79520. Its able to boot a Linux kernel stored in flash or RAM and provide that kernel with a RAMdisk (again from flash or RAM). The limitation with blob is when downloading the RAMdisk it tries to burn it directly to the flash, since out flash is not supported by the standard CFI / INTEL flash drivers blob isnt able to write to it. Hence we root for APEX which stores the RAMdisk / Kernel received from serial port in RAM.

 

APEX superceeds Blob . It was written to support specifically the Sharp LH series of SystemOnChip processors though it has been ported to a few other ARM targets.

 

The source code is archived here: ftp://ftp.buici.com/pub/apex.

 

Some of its feature which appear nice are :

  1. Easy to configure. There is a single configuration file and it uses the linux-2.6 Kconfig infrastructure.
  2. Supported targets: LH79520, LH79524, LH7A400, LH7A404, IXP42x (e.g. Linksys NSLU2), S3C2410.
  3. Small footprint. A limited feature version can be as small as 16KB.
  4. And lastly but most importantly stores the received Kernel/RAMdisk in RAM.

 

If the apex installation is sucessful on the Hyperterm ( Baud Rate = 115200 ) you will see something like

 

APEX Boot Loader 1.2.11 -- Copyright (c) 2004,2005 Marc Singer

APEX comes with ABSOLUTELY NO WARRANTY. It is free software and you

are welcome to redistribute it under certain circumstances.

For details, refer to the file COPYING in the program source.

apex => mem:0x20200000+0x8998 (35224 bytes)

env => nor:128k+64k

Use the 'help .' command to get a list of help topics.

apex>

Please do a help on the apex prompt for xreceive, dump, boot etc commands to get familiar with APEX.

 

  • ARM Toolchain

 

To compile APEX, and also the Kernel later we need a ARM toolchain. The toolchain actually consists of a number of components. The main one is the compiler itself gcc, which can be native to the host or a cross-compiler. This is supported by binutils, a set of tools for manipulating binaries ( e.g linking, objdump etc ) . These components are all you need for compiling the kernel, but almost anything else you compile also needs the C-library (uClibc for embedded ).

 

As you will realise if you think about it for a moment, cross compiling the compiler etc is not a easy task. If you have a long weekend coming up and got nothing better to do "The GNU Toolchain for ARM targets HOWTO" by Wookey et. al tell step by step how to do so.

 

Or for a easier way out you can download the crosstool : ftp://ftp.buici.com/pub/arm/crosstool which will make your job easier.

 

If you are wiser you will just download a precompiled toolchain and start using it right away.

 

In case you are planning to compile a Linux-2.6 kernel make sure you have gcc version 3.3 or better , and binutils 2.16 or better.

 

  • The Kernel

 

One can choose from a variety of linux kernel (considering that Linus releases a new one every now and then ) to choose from. Patches for LH79520 are available for both linux 2.4 and 2.6. A tested 2.4 patch by Lineo Sharp can be found in the mARMalade distribution ( downloadable from www.earthlcd.com ), linux 2.6 patches can be downloaded from : ftp://ftp.buici.com/pub/arm/.

 

Despite applying the patch the kernel on building will bail out some errors ( mostly variable UNDEFINED etc) that can be easily fixed looking at the code. BTW, the Kconfig based build for linux 2.6 is much better.

 

To cross-compile the linux for ARM in the top level Makefile change :

 

ARCH =

with

ARCH = arm

and

CROSS_COMPILE=

to

CROSS_COMPILE=

eg.

CROSS_COMPILE=arm-linux-

 

Do a 'make meuconfig' to conveniently configure the kenrel and drivers you need,

followed by 'make dep', and finally 'make Image' to build the kernel (arch/arm/boot/Image). A compressed image can be built by doing a 'make zImage' instead of 'make Image'.

 

BEFORE compiling make sure to add the cross compiler to $PATH.

 

Kernel Configuration

 

Since we are working on a system with a very limited RAM (16M) its better to choose a Kernel with minimum possible config. That is -

 

- No loadable module support

- Disable most Drivers except just the Serial Ones.

- Stuff like SATA / MTD drivers / Parallel port etc can also be done away with

- File system support - ext2

 

RAMDISK and initrd support

 

Make sure this option is selected in the Kernel Config. Also since the RAM size is limited one can change this the default no of RAMdisks from 16 ( only in linux 2.6 ) and the deafault RAMdisk size from 4096K to 2048K.

 

Default Kernel Command Line

 

Must be "root=/dev/ram0 mem=8M"

 

Verbose Kernel Debugging

 

Though it adds to the kernel size, its worth including specially in the initial development stage.

 

  • RAMdisk

 

The RAMdisk is a very useful kernel facility that lets you load the files you need on the system into RAM along with the kernel. It take the form of a compressed filesystem. The kernel automatically allocates RAM for it and uncompresses it, then mounts it as the root filing system.

 

Again, there are many variations possible on this theme, but the conventional setup is to format the RAMdisk as ext2, the normal Linux disk filesystem. For this to work you need to specify the correct kernel options: RAMdisk support (CONFIG_BLK_DEV_RAM, CONFIG_BLK_DEV_RAM_SIZE, CONFIG_BLK_DEV_INITRD) and support for the filesystem used (normally ext2 - CONFIG_EXT2_FS).

 

There are many RAMdisk available for popular configs, we could not find "the one" that satisfies our needs, so made one ourselves.

 

To check an existing RAMdisk

 

Suppose you downloaded a RAMdisk image from the net (ramdisk.gz) and want to check if its a vaild image and what all it contains. You need to gunzip it and loop-mount it as a filesytem. Your kernel need loop support for this to work, but a desktop kernel will nromally have this (it's really useful).

 

gunzip ramdisk . gz

mount -o loop ramdisk /mnt/ramdisk

 

Now you can see the contents by browsing /mnt/ramdisk like any other filesystem. You can even add files by copying them in if there is space left in the RAMdisk. The kernel needs to have support for the filesystem used in the RAMdisk.

 

To make a RAMdisk

 

The steps involved are:

 

  1. Put all the files you want to put on the disk in a suitable directory with the correct directory structure
  2. Zero out a block of memory (this is so that the spare space in your RAMdisk compresses as much as possible - if it was full of whatever random stuff was in ram at th time it would waste space in the final RAMdisk);
  3. Make a filesystem in this memory
  4. Mount it
  5. Copy the files you prepared into it
  6. Unmount it
  7. Compress it.

 

So here's an example. The size of the RAMdisk is 2MB, prepared files are in the directory preparedfiles, and we are making a conventional ext2 RAMdisk, rather than something more exotic. /mnt/ramdisk should already be created as a mount point. You will need to be root.

 

dd if=/dev/zero of=/dev/ram bs=1k count=2048

mke2fs -vm0 /dev/ram 2048

mount -t ext2 /dev/ram /mnt/ramdisk

cp -av preparedfiles /mnt/ramdisk

umount /mnt/ramdisk

dd if=/dev/ram bs=1k count=2048 | gzip -v9 ramdisk . gz

 

The -m0 option to mke2fs specifies that no extra space for the super-user is reserved again to minimise the size of the filesystem.

 

 

Make RAMDISK alternate : buildroot

 

Buildroot (http://buildroot.busybox.net) can be used to generate the RAMdisk if you want to make a RAMdisk with BusyBox utils. BusyBox (http://busybox.net) combines tiny versions of many common UNIX utilities into a single small executable for ARM. It provides replacements for most of the utilities you usually find in GNU fileutils, shellutils, etc. The utilities in BusyBox generally have fewer options than their full-featured GNU cousins.

 

  • Miscellaneous

 

Famous Error 1

 

If the bootloader (apex) parameters (e.g for ARCH_LH79520 etc ) are not the same as the Kenrel on booting you will get what Dave calls the Famous Error 1 in the embedded linux world. As the bootloader supplies all these parameters to the kernel on booting.

 

Silent Kernels

 

One of the problems in development of a kernel for a new machine type is early kernel hangs. Without feed back from the kernel it is difficult to understand what is going wrong. To combat this you can enable under "kernel hacking" the option for "kernel low-level debugging functions". The will enable the usage of the printascii() function. This writes hard coded information directly to the uarts. In order to make maximum usage of the printascii() function it is necessary to modify the printk() function so that all console messages are sent to the uart. A patch for the same is given below.

 

 

Index: kernel/printk.c

===================================================================

RCS file: /home/erik/cvsroot/elinux/kernel/printk.c,v

retrieving revision 1.1.1.94

diff -u -r1.1.1.94 printk.c

--- kernel/printk.c 2001/09/12 02:00:04 1.1.1.94

+++ kernel/printk.c 2001/09/18 16:32:33

@@ -412,6 +412,8 @@

printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);

va_end(args);

+ printascii(printk_buf);

+

/*

* Copy the output into log_buf. If the caller didn't provide

* appropriate log level tags, we insert them here

 

 

Additionally you may need to modify the arch/arm/kernel/debug-armv.S so that the out is pointed to the correct uart.

 

#elif defined(CONFIG_ARCH_LH79520)

.macro addruart,rx

mrc p15, 0, \rx, c1, c0

tst \rx, #1 @ MMU enabled?

moveq \rx, #0x80000000 @ physical base address

movne \rx, #0xf8000000 @ virtual address

@add \rx, \rx, #0x00050000 @ Ser3

add \rx, \rx, #0x00010000 @ Ser1

.endm

 

in this example the printascii() result will be sent to Ser1 and Ser3 is commented out.

 

Kernel Oops

 

Unlike linux on the host machine the "ksymoops" program cannot be used to make sense of the dump. The best shot is to binutil "arm-linux-obdump -C vmlinux" and using the PC seach which instruction caused the offence.

 

Happy Linuxing :)

Comments (0)

You don't have permission to comment on this page.