Saturday, December 25, 2010

Working with ELDK

• Create a new directory where the ELDK is to be installed, say:
bash$ mkdir /opt/eldk
• Mount a CD or an ISO image with the distribution:
bash$ mount /dev/cdrom /mnt/cdrom
• Run the installation utility included on the distribution to install into that specified directory:
bash$ /mnt/cdrom/install -d /opt/eldk
• After the installation utility completes, export the CROSS_COMPILE variable:
bash$ export CROSS_COMPILE=ppc_8xx-
The trailing '-' character in the CROSS_COMPILE variable value is optional and has no effect on
the cross tools behavior.
• Add the directories /opt/eldk/usr/bin and /opt/eldk/bin to PATH:
bash$ PATH=$PATH:/opt/eldk/usr/bin:/opt/eldk/bin
• Compile a file:
bash$ ${CROSS_COMPILE}gcc -o hello_world hello_world.c
You can also call the cross tools using the generic prefix ppc-linux- for example:
bash$ ppc-linux-gcc -o hello_world hello_world.c
3.5. Working with ELDK 14
• or, equivalently:
bash$ /opt/eldk/usr/ppc-linux/bin/gcc -o hello_world hello_world.c

The value of the CROSS_COMPILE variable must correspond to the target CPU family you want the cross
tools to work for. Refer to the table below for the supported CROSS_COMPILE variable values:
3.5.A Table of possible values for $CROSS_COMPILE
CROSS_COMPILE Value | Predefined Compiler Flag | FPU present or not
ppc_4xx- | -mcpu=403 | No
ppc_4xxFP- | -mcpu=405fp | Yes
ppc_6xx- | -mcpu=603 | Yes
ppc_74xx- | -mcpu=7400 | Yes
ppc_8xx- | -mcpu=860 | No
ppc_85xx- | -mcpu=8540 | Yes
For compatibility with older versions of the ELDK and with other toolkits the following values for
$CROSS_COMPILE can be used, too: ppc_7xx- and ppc_82xx-. These are synonyms for ppc_6xx.

Thursday, December 23, 2010

An Example of Creating a Compressed RAM Disk

----------------------------------------------

To create a RAM disk image, you will need a spare block device to
construct it on. This can be the RAM disk device itself, or an
unused disk partition (such as an unmounted swap partition). For this
example, we will use the RAM disk device, "/dev/ram".

Note: This technique should not be done on a machine with less than 8 MB
of RAM. If using a spare disk partition instead of /dev/ram, then this
restriction does not apply.

a) Decide on the RAM disk size that you want. Say 2 MB for this example.
Create it by writing to the RAM disk device. (This step is not currently
required, but may be in the future.) It is wise to zero out the
area (esp. for disks) so that maximal compression is achieved for
the unused blocks of the image that you are about to create.

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

b) Make a filesystem on it. Say ext2fs for this example.

mke2fs -vm0 /dev/ram 2048

c) Mount it, copy the files you want to it (eg: /etc/* /dev/* ...)
and unmount it again.

d) Compress the contents of the RAM disk. The level of compression
will be approximately 50% of the space used by the files. Unused
space on the RAM disk will compress to almost nothing.

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

e) Put the kernel onto the floppy

dd if=zImage of=/dev/fd0 bs=1k

f) Put the RAM disk image onto the floppy, after the kernel. Use an offset
that is slightly larger than the kernel, so that you can put another
(possibly larger) kernel onto the same floppy later without overlapping
the RAM disk image. An offset of 400 kB for kernels about 350 kB in
size would be reasonable. Make sure offset+size of ram_image.gz is
not larger than the total space on your floppy (usually 1440 kB).

dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400

g) Use "rdev" to set the boot device, RAM disk offset, prompt flag, etc.
For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
have 2^15 + 2^14 + 400 = 49552.

rdev /dev/fd0 /dev/fd0
rdev -r /dev/fd0 49552

That is it. You now have your boot/root compressed RAM disk floppy. Some
users may wish to combine steps (d) and (f) by using a pipe.

Manually building a custom initial RAM disk

Because there is no hard drive in many embedded systems based on Linux, the initrd also serves as the permanent root file system.I'm using a standard Linux desktop so you can follow along without an embedded target. Other than cross-compilation, the concepts (as they apply to initrd construction) are the same for an embedded target.

Utility (mkird) to create a custom initrd
# Create an empty ramdisk image
dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE

# Make it an ext2 mountable file system
/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE

# Mount it so that we can populate
mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0

Saturday, December 18, 2010

Sasken Tech Round F2F Interview Questions181210 (channi)

1. What is difference between pointers and arrays?
Is it possible to create an array using pointers?
2. What is the circular linked list?
How to find whether a linked list is a circular linked list or not?
3. What is the difference between USB 1.0 and 2.0?
4. How we can insert module in to the kernel dynamically?

Friday, December 10, 2010

http://free-electrons.com/
About U-boot:

http://book.opensourceproject.org.cn/embedded/embeddedprime/opensource/0136130550/ch07lev1sec4.html

Wednesday, December 1, 2010

NAME
memory: memccpy(), memchr(), memcmp(), memcpy(), memmove(), memset(),
bcmp(), bcopy(), bzero(), ffs() - memory operations

SYNOPSIS
#include

void *memccpy(void *__restrict s1, const void *__restrict s2, int c,
size_t n);

void *memchr(const void *s, int c, size_t n);

int memcmp(const void *s1, const void *s2, size_t n);

void *memcpy(void *__restrict s1, const void *__restrict s2, size_t n);

void *memmove(void *s1, const void *s2, size_t n);

void *memset(void *s, int c, size_t n);

#include

int bcmp(const void *s1, const void *s2, size_t n);

void bcopy(const void *s1, void *s2, size_t n);

void bzero(void *s, size_t n);

int ffs(int i);

Remarks
bcmp(), bcopy(), bzero(), ffs(), and are provided solely
for portability of BSD applications, and are not recommended for new
applications where portability is important. For portable
applications, use memcmp(), memmove(), and memset(), respectively.
ffs() has no portable equivalent.

DESCRIPTION
These functions operate as efficiently as possible on memory areas
(arrays of bytes bounded by a count, not terminated by a null byte).
They do not check for the overflow of any receiving memory area.

Definitions for all these functions, the type size_t, and the constant
NULL are provided in the header file.

memccpy() Copy bytes from the object pointed to by s2 into the
object pointed to by s1, stopping after the first
occurrence of byte c has been copied, or after n bytes
have been copied, whichever comes first. If copying
takes place between objects that overlap, the behavior
is undefined. memccpy() returns a pointer to the byte

after the copy of c in s1, or a NULL pointer if c was
not found in the first n bytes of s2.

memchr() Locate the first occurrence of c (converted to an
unsigned char) in the initial n bytes (each interpreted
as unsigned char) of the object pointed to by s.
memchr() returns a pointer to the located byte, or a
NULL pointer if the byte does not occur in the object.

memcmp() Compare the first n bytes of the object pointed to by
s1 to the first n bytes of the object pointed to by s2.
memcmp() returns an integer greater than, equal to, or
less than zero, according to whether the object pointed
to by s1 is greater than, equal to, or less than the
object pointed to by s2. The sign of a non-zero return
value is determined by the sign of the difference
between the values of the first pair of bytes (both
interpreted as unsigned char) that differ in the
objects being compared.

memcpy() Copy n bytes from the object pointed to by s2 into the
object pointed to by s1. If copying takes place
between objects that overlap, the behavior is
undefined. memcpy() returns the value of s1.

memmove() Copy n bytes from the object pointed to by s2 into the
object pointed to by s1. Copying takes place as if the
n bytes from the object pointed to by s2 are first
copied into a temporary array of n bytes that does not
overlap the objects pointed to by s1 and s2, and then
the n bytes from the temporary array are copied into
the object pointed to by s1. memmove() returns the
value of s1.

memset() Copy the value of c (converted to an unsigned char)
into each of the first n bytes of the object pointed to
by s. memset() returns the value of s.

bcopy() copies n bytes from the area pointed to by s1 to the
area pointed to by s2.

bcmp() Compare the first n bytes of the area pointed to by s1
with the area pointed to by s2. bcmp() returns zero if
they are identical; non-zero otherwise. Both areas are
assumed to be n bytes in length.

bzero() Clear n bytes in the area pointed to by s by setting
them to zero.

ffs() Find the first bit set (beginning with the least
significant bit) and return the index of that bit.

Bits are numbered starting at one. A return value of 0
indicates that i is zero.
the ‘Volatile’ Keyword in C

One of my favourite interview questions for novice programmers is: “What is the use of the ‘volatile’ keyword?” For experienced programmers, I ask: “Can we qualify a variable as both ‘const’ and ‘volatile’—if so, what is its meaning?” I bet most of you don’t know the answer, right?

The keyword ‘volatile’ is to do with compiler optimisation. Consider the following code:

long *timer = 0x0000ABCD;
// assume that at location 0x0000ABCD the current time is available
long curr_time = *timer;
// initialize curr_time to value from ‘timer’
// wait in while for 1 sec (i.e. 1000 millisec)
while( (curr_time - *timer) < 1000 )
{
curr_time = *timer; // update current time
}
print_time(curr_time);
// this function prints the current time from the
// passed long variable

Usually, hardware has a timer that can be accessed from a memory location. Here, assume that it’s 0×0000ABCD and is accessed using a long * variable ‘timer’ (in the UNIX tradition, time can be represented as a long variable and increments are done in milliseconds). The loop is meant to wait one second (or 1,000 milliseconds) by repeatedly updating curr_time with the new value from the timer. After a one second delay, the program prints the new time. Looks fine, right?

However, from the compiler point of view, what the loop does is stupid—it repeatedly assigns curr_time with *timer, which is equivalent to doing it once outside the loop. Also, the variable ‘timer’ is de-referenced repeatedly in the loop—when it is enough to do it once. So, to make the code more efficient (i.e., to optimise it), it may modify loop code as follows:

curr_time = *timer; // update current time
long temp_time = *timer;
while( (curr_time - temp_timer) < 1000 )
{ /* do nothing here */
}

As you can see, the result of this transformation is disastrous: the loop will never terminate because neither is curr_time updated nor is the timer de-referenced repeatedly to get new (updated time) values.

What we need is a way to tell the compiler not to ‘play around’ with such variables by declaring them volatile, as in:

volatile long * timer = 0x0000ABCD;
volatile curr_time = *timer;

Now, the compiler will not do any optimisation on these variables. This, essentially, is the meaning of the ‘volatile’ keyword: It declares the variables as ‘asynchronous’ variables, i.e., variables that are ‘not-modified-sequentially’. Implicitly, all variables that are not declared volatile are ‘synchronous variables’.

How about qualifying a variable as both const and volatile? As we know, when we declare a variable as const, we mean it’s a ‘read-only’ variable—once we initialise it, we will not change it again, and will only read its value. Here is a modified version of the example:

long * const timer = 0x0000ABCD;
// rest of the code as it was before..

We will never change the address of a timer, so we can put it as a const variable. Now, remember what we did to declare the timer as volatile:

volatile long * timer = 0x0000ABCD;

We can now combine const and volatile together:

volatile long * const timer = 0x0000ABCD;

It reads as follows: the timer is a const pointer to a long volatile variable. In plain English, it means that the timer is a variable that I will not change; it points to a value that can be changed without the knowledge of the compiler!
the ‘Volatile’ Keyword in C

One of my favourite interview questions for novice programmers is: “What is the use of the ‘volatile’ keyword?” For experienced programmers, I ask: “Can we qualify a variable as both ‘const’ and ‘volatile’—if so, what is its meaning?” I bet most of you don’t know the answer, right?

The keyword ‘volatile’ is to do with compiler optimisation. Consider the following code:

long *timer = 0x0000ABCD;
// assume that at location 0x0000ABCD the current time is available
long curr_time = *timer;
// initialize curr_time to value from ‘timer’
// wait in while for 1 sec (i.e. 1000 millisec)
while( (curr_time - *timer) < 1000 )
{
curr_time = *timer; // update current time
}
print_time(curr_time);
// this function prints the current time from the
// passed long variable

Usually, hardware has a timer that can be accessed from a memory location. Here, assume that it’s 0×0000ABCD and is accessed using a long * variable ‘timer’ (in the UNIX tradition, time can be represented as a long variable and increments are done in milliseconds). The loop is meant to wait one second (or 1,000 milliseconds) by repeatedly updating curr_time with the new value from the timer. After a one second delay, the program prints the new time. Looks fine, right?

However, from the compiler point of view, what the loop does is stupid—it repeatedly assigns curr_time with *timer, which is equivalent to doing it once outside the loop. Also, the variable ‘timer’ is de-referenced repeatedly in the loop—when it is enough to do it once. So, to make the code more efficient (i.e., to optimise it), it may modify loop code as follows:

curr_time = *timer; // update current time
long temp_time = *timer;
while( (curr_time - temp_timer) < 1000 )
{ /* do nothing here */
}

As you can see, the result of this transformation is disastrous: the loop will never terminate because neither is curr_time updated nor is the timer de-referenced repeatedly to get new (updated time) values.

What we need is a way to tell the compiler not to ‘play around’ with such variables by declaring them volatile, as in:

volatile long * timer = 0x0000ABCD;
volatile curr_time = *timer;

Now, the compiler will not do any optimisation on these variables. This, essentially, is the meaning of the ‘volatile’ keyword: It declares the variables as ‘asynchronous’ variables, i.e., variables that are ‘not-modified-sequentially’. Implicitly, all variables that are not declared volatile are ‘synchronous variables’.

How about qualifying a variable as both const and volatile? As we know, when we declare a variable as const, we mean it’s a ‘read-only’ variable—once we initialise it, we will not change it again, and will only read its value. Here is a modified version of the example:

long * const timer = 0x0000ABCD;
// rest of the code as it was before..

We will never change the address of a timer, so we can put it as a const variable. Now, remember what we did to declare the timer as volatile:

volatile long * timer = 0x0000ABCD;

We can now combine const and volatile together:

volatile long * const timer = 0x0000ABCD;

It reads as follows: the timer is a const pointer to a long volatile variable. In plain English, it means that the timer is a variable that I will not change; it points to a value that can be changed without the knowledge of the compiler!