Pages

2010-09-21

Linux: Creating Linux Kernel U-Boot Images


To make a U-Boot image file containing the Elf binary vmlinux kernel file, it is first required to use objcopy to get the raw binary data, followed by the mkimage tool to encapsulate it (as a .ub file). In this example the kernel is also compressed to save space (this is recommended, but not necessary).  

$ arm-linux-objcopy -O binary vmlinux arm-vmlinux.bin
$ gzip --best --force arm-vmlinux.bin
$ mkimage -A arm -O linux -T kernel -C gzip -a 0x8C001000 -e 0x8C002000\ -n "ARM Linux 2.6" -d arm-vmlinux.bin.gz arm-vmlinux.ub

The addresses for the two parameters -a (load address) and -e (execute address) depend of the specific target board that is being used.

And if we want also to make an INITRD image we do -T ramdisk

2010-09-13

Linux: Managing double linked list in the Linux kernel

 #include <linux/list.h>
  • LIST_HEAD(list_name): Creat an new double linked list.
  • list_add(n,p): Inserts an element pointed to by n right after the specified element pointed to by p. To insert n at the beginning of the list, set p to the address of the list head.
  • list_add_tail(n,p): Inserts an element pointed to by n right before the specified element pointed to by p. To insert n at the end of the list, set p to the address of the list head.
  • list_del(p): Deletes an element pointed to by p.
  • list_empty(p): Checks if the list specified by the address p of its head is empty.
  • list_entry(p,t,m): Returns the address of the data structure of type t in which the list_head field that has the name m and the address p is included.
  • list_for_each(p,h): Scans the elements of the list specified by the address h of the head; in each iteration, a pointer to the list_head structure of the list element is returned in p.
  • list_for_each_entry(p,h,m): Returns the address of the data structure embedding the list_head structure rather than the address of the list_head structure itself.

    2010-09-09

    Linux: Catchnig Net Device Notification in the Linux Kernel

    A Net Device notification, is sent when we access a network device. To catch such event we do:
    #include <linux/notifier.h>
    #include <asm/kdebug.h>
    #include <linux/netdevice.h>
    #include <linux/inetdevice.h>


    static struct notifier_block my_dev_notifier = 
    {
      .notifier_call = my_dev_event_handler,
    }; 


    int my_dev_event_handler(struct notifier_block *self, unsigned long val, void *data)
    {
      printk("my_dev_event: Val=%ld, Interface=%s\n", val,  ((struct net_device *) data)->name);
      return 0;
    /* ... */ 
    register_netdevice_notifier(&my_dev_notifier); 
    In this example, Val will take 1 (when we do from the shell ifconfig eth0 up) or 0 (ifconfig eth0 down).

    Name will be the name of the network device (eth0, eth1, etc...).

    2010-09-08

    Linux: Catching Die Notification in the Linux Kernel

    A die notification (die_chain), is sent when a kernel function triggers a trap or a fault, caused by an oops, page fault, or a breakpoint hit. To catch such event we do:
    #include <linux/notifier.h>
    #include <asm/kdebug.h> 
    static struct notifier_block my_die_notifier = 
    {
      .notifier_call = my_die_event_handler,
    };

    int my_die_event_handler(struct notifier_block *self, unsigned long val, void *data)
    {
      struct die_args *args = (struct die_args *) data;
      if (val == 1) /* oops */

      { 
        printk("my_die_event: OOPs! at EIP=%lx\n", args->regs->eip);
      } 
      return 0;
    }
    /* ... */ 
    register_die_notifier(&my_die_notifier);

    Linux: Making some delays at the kernel context

    To make some delays in the kernel context there are two solutions.

    First, busy-waiting (for two seconds):
    unsigned long timeout = jiffies + (2*HZ);
    while (time_before(jiffies, timeout)) continue;
    Or we can use sleep-waiting (better):
    unsigned long timeout = jiffies + (2*HZ);
    schedule_timeout(timeout);
    Also, we have the msleep() function for sleeping in milliseconds, udelay() for microseconds delays and ndelay() for nanoseconds delays. We should include the header file <asm/delay.h>

    Linux: Measuring Boot Time

    // Purpose of this utility is to timestamp each line coming over stdin
    // USAGES:
    //    tstamp.exe < /dev/ttyS0
    //    <commands> | tstamp.exe
    // 
    
    #include <stdio.h>
    #include <time.h>
    #include <sys/time.h>
    
    char buf[10*1024];
    
    main(int argc)
    {
      struct timeval tv;
      double time_start,time_now,time_prev;
      int first=1;
    
      if(argc!=1) // as of now no arguments are allowed. print usage
      {
         printf("Timestamps each line coming over stdin\n"
                 "\tUSAGES:\n"
                 "\t\ttstamp.exe < /dev/ttyS0\n"
                 "\t\t<commands> | tstamp.exe\n"
                 "\t\tetc..\n");
         printf("Output is printed in the following format\n"
                   "\tcolumn1 is elapsed time since first message"
                   "\tcolumn2 is elapsed time since previous message\n"
                 "\tcolumn3 is the message\n");
     
         exit(0);
      }
    
      printf("\tcolumn1 is elapsed time since first message\n"
               "\tcolumn2 is elapsed time since previous message\n"
             "\tcolumn3 is the message\n");
    
      while(1)
      {
        if(gets(buf))
        {
           gettimeofday(&tv, NULL); // get system time
           time_now = tv.tv_sec + (tv.tv_usec*(1.0/1000000.0)); // convert to double
           if(first) // if first time, notedown the time_start
             first = 0,  time_start = time_prev = time_now;
    
           printf("%03.3f %02.3f: ",(float)(time_now-time_start),
                          (float)(time_now-time_prev)); // print the column1 and 2
    
           puts(buf); // now print the message as column3
           time_prev = time_now;
        }
      }
    }

    2010-09-07

    Linux: Mount Root File System on NFS

    To enable your embedded system to mount its root file system via NFS we must configure our target's kernel for NFS support. There is also a configuration option to enable root mounting of an NFS remote directory.

    To statically configure our target's IP address, our kernel command line might look like this:

    console=ttyS0,115200                                      ip=192.168.1.139:192.168.1.1:192.168.1.1:255.255.255.0:embedded_host:eth0:off     nfsroot=192.168.1.1:/home/me/my_remote_folder root=/dev/nfs rw
    Where:

     ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<PROTO>
     
    Here, client-ip is the target's IP address; server-ip is the address of the NFS server; gw-ip is the gateway (router), in case the server-ip is on a different subnet; and netmask defines the class of IP addressing. hostname is a string that is passed as the target hostname; device is the Linux device name, such as eth0; and PROTO defines the protocol used to obtain initial IP parameters.

    For a sample example using DHCP protocol:

    console=ttyS0,115200 root=/dev/nfs rw ip=dhcp
       nfsroot=192.168.1.9://home/me/my_remote_folder

    Linux: Mounting NFS Filesystem

    First we should export the directory that will be mounted by the remote computer via NFS, we do:

    echo "/home/me/my_remote_folder *(rw,sync,no_root_squash)" > /etc/exports
    We should then restart our NFS server with the new configuration file using:
    /etc/init.d/nfs restart
    or
     /usr/sbin/exportfs -av
     /sbin/service nfs restart 
    We can Use /etc/init.d/nfs status to verify that the NFS server is running.

    On an embedded system with NFS enabled, the following command mounts the my_remote_folder directory exported by the NFS server on a mount point of our choosing:
    mount -t nfs mycomputer:/home/me/my_remote_folder /mnt/nfs
    Where mycomputer is the name of your computer on the network or his IP address.

    2010-09-01

    U-Boot: Booting Linux Kernel with Initrd support

    # tftpboot 0x10000000 kernel-uImage
    ...
    Load address: 0x10000000
    Loading: ############################ done
    Bytes transferred = 1069092 (105024 hex)

    # tftpboot 0x10800000 initrd-uboot
    ...
    Load address: 0x10800000
    Loading: ########################################### done
    Bytes transferred = 282575 (44fcf hex)

    # bootm 0x10000000 0x10800040
    Uncompressing kernel.................done.
    ...
    RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
    ...
    RAMDISK: Compressed image found at block 0
    VFS: Mounted root (ext2 filesystem).
    Greetings: this is linuxrc from Initial RAMDisk
    Mounting /proc filesystem

    BusyBox v1.00 (2005.03.14-16:37+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.

    # (<<<< Busybox command prompt)