Frequently Asked Questions

rev 1.5
Q: How large should a FLASH/ROM part be?
Q: What are the BSP limitations compared with desktop Linux?
Q: At what address does the rrload bootloader store downloaded data?
Q: What block drivers do each of the file systems require?
Q: Why won't my file compile with xflat-gcc?
Q: Are there any performance issues caused by the XFLAT data accessors?
Q: How do I create my own XFLAT data accessor?
Q: What software do I need to provide to my customers if they request the source code?
Q: Why doesn't uClinux support fork() and how do I use vfork() in its place?
Q: How do I add a SD RAM part or flash part to the BSP configuration tool?
Q: What real-time extensions does your BSP support?
Q: What causes the rrload error "can not handle out-of-order tftp blocks" when downloading the kernel or filesystem?
Q: The Cadenux BSPs for the ARM7 chips use uClinux. What applications have been ported to uClinux?
Q: What books are available to learn more about the Linux kernel?
Q: What extra packages are necessary for using our BSP's on Fedora Core 4?
Q: How do I use VFAT long filenames with UTF characters?


Q: How large should a FLASH/ROM part be?

A: Normally, we recommend a minimum size of 4MByte. About 0.8Kbyte to 1.2MByte of flash storage is required for the kernel and bootloader (depending upon the size of the kernel and the FLASH memory losses do to the alignment of erase blocks). The rest of the flash is used to hold a file system.

However, using some compression technologies a 2MByte flash part can also be used successfully if:

  1. The kernel is stored in a compressed form in FLASH. The kernel would be decompressed into RAM when the system is booted. We can expect compression to reduce the kernel size by 40-60%. This would leave approximately 1.3MByte to 1.7MByte for a file system.

  2. Then there are 3 options for the file system:

    • The file system is very small (approximately 1.3MByte to 1.7 MByte).

    • The filesystem is also compressed on FLASH and decompressed into RAM (as with a romfs file system). This could support a read-only file system of approximately 2.2MByte to 4.3MByte in RAM. This is about the same file system size that could be supported on a 4MByte flash part!

    • Or, if a read-write file system is needed, a compressed, write-able, flash filesystem (like JFFS2) could be used. In this case, the filesystem is not compressed, but rather the contents of the filesystem are compressed and decompressed into RAM on-the-fly as needed.

Q: What are the BSP limitations compared with desktop Linux?

A: The embedded device has significantly less hardware, thus limiting what is possible compared to a desktop computer. The other big difference is the BSP comes with uClinux (instead of Linux) and uClibc (instead of glibc). The set of applications is much smaller as well.

The main difference between uClinux used in the BSP and desktop Linux is uClinux is designed to work with processors that do not have memory management unit (MMU) support. This hardware limitation means one process can write to memory "owned" by another process, or even owned by the Linux kernel. There is no processor hardware to memory access violations. No MMU support also means other features, like fork() are not supported (but vfork() is supported).

uClibc supports a subset of the functionality supported by glibc. The differences can be found on the uClibc website.

Q: At what address does the rrload bootloader store downloaded data?

A: The rrload bootloader stores the downloaded data, either bootloader, kernel or file system data, at the address specified in the file being downloaded. Normally the rrbin format is used since it the most compact format. The rrbin format consists of 3 ASCII text lines followed by the contents of the data being downloaded in binary format. The 3 ASCII text lines provide information to rrload about where to store the downloaded data, the size of the downloaded data, and the starting execution address if the downloaded data is an ARM7 executable file.

Given an rrbin file, say linux.rr, you can see the 3 ASCII lines using the following command:

$ head -3 linux.rr
>LoadAddr :0x02A00000
>EntryAddr:0x02A0B000
>NumBytes :0x000DFF58

The value of the LoadAddr indicates where in memory the downloaded will be stored. This value overrides the destination you specify when using the rrload copy command in command line mode.

Q: What block drivers do each of the file systems require?

A: The following table lists which block driver is required for a file system.

File System Block Driver
romfs CONFIG_BLK_DEV_BLKMEM
minix CONFIG_BLK_DEV_RAM
jffs CONFIG_BLK_DEV_FLASH
jffs2 CONFIG_BLK_DEV_MTD
compact flash CONFIG_BLK_DEV_IDE

Q: Why won't my file compile with xflat-gcc?

A: What you are seeing may be normal (if somewhat less than desirable) behavior of xflat-gcc. This is usually the consequence of attempting to access global variables that are normally exported from shared libraries.

The technical approach to MMU-less shared library support used by the XFLAT shared libraries without an MMU has some limitations that shared library support with an MMU does not. In particular, you cannot access global variables across shared library boundaries. This is not so much a consequence of the shared library implementation as it is a consequence of the GOT-less implementation that is the standard for embedded ARM binaries: The absence of a GOT and the limitations of the FLAT/XFLAT binary formats do not support the indirection that you would need to relocate the data references. Consider the following trivial code example:

    #include <unistd.h>
    extern char *optarg;

This will not compile under xflat-gcc even though the code usage is consistent with the getopt() man page. In order to explain why this will not compile, we'll have to dig a little deeper "under the hood:"

The global variable optarg is defined in the libc shared library. So you will never be able to able to access it directly from your code using extern char * optarg; given the limitations on the access of global variables. But why does this cause a compilation error?

The Cadenux tool change retains the header files that you use under a directory path something like: /opt/Cadenux/[processor]/[kernel]/crossdev/arm-uclinux/include. If you look at unistd.h in that include directory, you will see that it includes getopt.h (at least under the version of uClibc current used in the toolchain). And if you look at getopt.h in that same directory, you will see that it already contains extern char *optarg;. So what is happening?

xflat-gcc is described here. Note that xflat-gcc is not really a compiler; it is a wrapper around the real compiler, arm-uclinux-gcc. The main thing that xflat-gcc does is to redirect the source of all of the compiler's include files. When you "#include <unistd.h>," you don't get the header file from the /opt/Cadenux/[processor]/[kernel]/crossdev/arm-uclinux/include directory. Rather, xflac-gcc will take the unistd.h header file from /opt/Cadenux/[processor]/[kernel]/crossdev/arm-uclinux/include/xflat! Similarly, when unistd.h includes getopt.h, that header file will also come from the xflat header file subdirectory.

Now, look at this .../xflat/optarg.h. It is tiny, it contains little more than:

    #include_next <getopt.h>
    #include <xflat_accessors.h>

    #undef optarg
    #define optarg (*(char**)xflat_varptr(XFLAT_OPTARG))

So, when you reference the variable optarg, you don't actually reference the variable, you actually dereference a function that returns a pointer to the variable. Because of this definition, the extern char *optarg; declaration in your C code will not compile. You could #undef optarg before the extern, but then you build would only fail at link time (or worse yet, maybe at run time!).

The solution: Just remove the extern char * optarg;; you don't need it.

xflat-gcc performs this same trick on numerous other variables exported from libc such as errno, stdout, etc. and it does this without any special knowledge or code changes in the user code. But a few exported variables, like optarg, optind, and environ are more troublesome, primarily because the man page usages suggests that they be explicitly externed. You can see the full list of such variables at ..include/xflat/xflat_accessors.h. Should I be concerned with the performance implications of these data accessors? Read on.

Q: Are there any performance issues caused by the XFLAT data accessors?

A: As described above and elsewhere, the global variables cannot be shared between your program code and shared libraries. Instead, the xflat-gcc tool inserts data accessor functions to manage access to global variables across such module boundaries: When you reference such a global variable, you don't actually reference the variable, you actually dereference a function that returns a pointer to the variable.

Typical dereferencing in this manner should not cause an measurable performance degradation if it is infrequent. However, such dereferencing could be a performance issue if such a variable is referenced at a high duty, say, in a "tight" loop. Then the small amount of processing required to access the variable could become a performance issue. In this case, you might want to save a pointer to the variable reference so that you do not call the accessor function at a high rate. For example, instead of:

    #include <stdio.h>
    ...
    int i;
    for (i = 0; i < 10000; i++)

      fprintf(stderr, "Error number %s\n", i);

Try something like:

    #include <stdio.h>
    ...
    FILE *mystderr = stderr;
    int i;
    for (i = 0; i < 10000; i++)

      fprintf(mystderr, "Error number %s\n", i);

Then, the stderr accessor function is called only once and outside of the "tight" loop.

Using such accessor functions has been a common practice with uClibc (stdout, stderr, etc. were already really function calls). XFLAT just required that this practice be extended.

Q: How do I create my own XFLAT data accessor?

A: Suppose your shared library exports a global variable something like:

    foo_t foo;

Where foo_t would be any type and foo could be any name. The you write an accessor function like:

    foo_t *get_foo(void) { return &foo; }

You would build this into your shared library. It is now an exported function that can be called across shared library boundaries. Then, in your program, change code like:

    foo_t *foo = &foo;
    foo.bar = 1;
    foo_t bar = foo;

to:

    foo_t *foo = get_foo();
    (*get_foo()).bar = 1;
    foo_t bar = (*get_foo());

Notice that in every case except for the first, the following macro will do the job with no code changes:

    /* Instead of extern foo_t foo, use */
    extern foo_t *get_foo(void);
    #define foo (*get_foo())

Q: What software do I need to provide to my customers if they request the source code?

A: The GPL and LGPL licenses state under what conditions the source code must be provided to person receiving a device containing Open Source software licensed using either the GPL or LGPL license. You only need to provide the Open Source software bundle to a person receiving a device containing the Open Source software if the person requests the source code. Refer to the license applicable to the software in question to determine if you need to include the software in the source code bundle.

For a device using embedded Linux, the software in the device will be in one of five categories:

Code linked with the Linux kernel Since the Linux kernel uses the GPL license, the source code for all software linked with the kernel must be part of the source code bundle. This includes any changes to kernel and any drivers that are linked with the kernel executable.
Kernel modules If a Linux driver is built as a module, then the source code to the module only needs to be included in the source code bundle if the module is an Open Source module. Several Cadenux drivers are proprietary and are licensed with stipulations that the driver must be built as a module.
Bootloader The rrload bootloader is an Open Source GPL licensed bootloader. The rrload source code must be included in the source code bundle.
Applications and libraries in the device's file system If the applications are linked to any libraries, then the license associated with each library must be examined to see if the application source code needs to be included in the source code bundle. If dynamic linking is used, (using a shared library technology like XFLAT or using a microprocessor that support a memory management unit) with LGPL licensed libraries, then the source code doesn't need to be part of the source code bundle.
Other Open Source software The source code to all Open Source software used in the device must be included in the source code bundle. This includes any changes make to the source code.

The above information is intended to provide an overview. Refer to the appropriate licenses to determine what software needs to be included in the source code bundle for your specific case.

Q: Why doesn't uClinux support fork() and how do I use vfork() in its place?

A: The fork() system call requires that the system duplicate the data segment if the child process writes to it. This behavior can not be emulated without memory management unit (MMU) support.

Use the following steps when converting an application from using fork() to using vfork(). These steps were derived from an email sent by Joe deBlaquiere on Tue, 21 Nov 2000 to the uclinux-dev@uClinux.org list.

  1. You need to make sure that the child process doesn't modify global data (or data within the current stack frame of the vfork() call) except resources which are duplicated by the system call such as file descriptors. Any data modified will be modified in the parent process.
  2. You cannot return back up the call stack from the routine where the vfork() occurs. As long as the child process is calling down, it is working out of the unused portion of the stack. If you return back up, you'll surely squash the parent's stack.
  3. The parent process will hang until the child process performs the exec() or exit(). It is possible that you can reach a deadlock condition if you blindly replace fork() with vfork().
Q: How do I add a SD RAM part or flash part to the BSP configuration tool?

A: There are three BSP configuration utility files that need to be modified, along with any source code files that will use the newly defined part.

The two BSP configuration utility files to be modified are:

  • toolchain/config-tools/memconfig.tk - GUI generation file that allows the part to be selected. To add a part to the GUI, simply find a similar part and duplicate the logic. Usually only three lines need to be changed. Remember to increment the number of items in the menu list and add information to the help string.
  • toolchain/config-tools/memconfig.c - logic to build a reasonable BSP configuration. When adding support for a new part, simply add a string identifying the part and add the string to the table of known parts. For flash parts, you need to provide the size of the part and the size of the largest erase block. Typically only two lines need to be changed.
  • toolchain/config-tools/memconfig.h - header file used by the BSP configuration utility. This is a different file than the memconfig.h file generated by the BSP configuration utility (and stored in the rrload/ and linux/include/asm/arch/ directories). Add a new define for the part and increase the number of supports parts. This is also typically a two line change.
Q: What real-time extensions does your BSP support?

A: DSPLinux supports real-time extensions derived from the MontaVista real-time extensions. DSPLinux supports a preemptable kernel and a real-time scheduler. Lock-breaking logic is also supported. In addition, kernel instrumentation has been added to monitor interrupt latency and preemption latency.

Real-time configuration:

  1. You can enable / disable the real-time related features using the Linux kernel configuration utility (make xconfig or make menuconfig in the linux directory). They are located in the kernel hacking menu.
  2. The instrumentation to monitor either interrupt latency or preemption latency significantly degrades performance. Only use these features during development.
  3. Do not enable interrupt latency instrumentation (CONFIG_ILATENCY) at the same time you enable kernel preemption (CONFIG_PREEMPT).
Q:What causes the rrload error "can not handle out-of-order tftp blocks" when downloading the kernel or filesystem?

A: If you use rrload TFTP network download and interrupt the download before it completes, then a TFTP process continues to run on the machine hosting the TFTP server (usually your Linux workstation). If you again download using TFTP, then multiple TFTP processes attempt to send the data to your target hardware. The processes use different TFTP packet numbering and rrload detects the incorrect numbering and generates the out-of-order message.

An easy way to see if a TFTP process is running is to use the BSP check configuration utility. In the top level development directory, type "make chkconfig". If extra TFTP processes are running, an error message is printed showing the process ID number. You can use "sudo kill -9 <process ID>" to kill the unwanted TFTP processes.

Q:The Cadenux BSPs for the ARM7 chips use uClinux. What applications have been ported to uClinux?

A: Many Open Source applications have been ported to uClinux. There is a uClinux CVS server which contains the ported source code. You can browse the CVS server here.

Q:What books are avaiable to learn more about the Linux kernel?

A: For the Linux 2.4 kernel

Understanding the Linux Kernel, 2nd Edition
By Daniel P. Bovet, Marco Cesati
2nd Edition December 2002
ISBN: 0-596-00213-0

For the Linux 2.6 kernel:

Linux Kernel Development, 2nd Edition
By Robert Love
ISBN: 0672327201
Copyright: 2005

For Linux driver development:

Linux Device Drivers, 3rd Edition
By Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman
3rd Edition February 2005
ISBN: 0-596-00590-3
Q:What extra packages are necessary for using our BSP's on Fedora Core 4

A:

1. Using yum install: sudo yum install gcc glibc-headers glibc-kernheaders glibc-devel.i386

If you don't have yum configured here you will find a clear guide to configure it.

2. Disable SELinux so the command mkfs can be used (necessary for build the BSP's fs image)

You can know if SELinux is active by running sestatus on a terminal. If it says:

      SELinux status:    disabled

SELinux is already disabled, otherwise you can disable it by editing the file /etc/sysconfig/selinux and set SELINUX=disabled. You will need to reboot your machine to apply the cahnges.

Q: How do I use VFAT long filenames with UTF characters?

A: You need to make sure the kernel has the necessary codepages supported and you need to provide additional parameters when mounting a VFAT file system.

  1. Kernel configuration:

    $ cd
    $ source setenv
    $ cd linux
    $ make xconfig

      File System --> Native Language Support --> Enable: Traditional Chinese charset (Big5)

  2. Mount parameters:

    # mount -t vfat -o codepage=950 iocharset=utf8 /dev/mmca1 /mnt/mmc

Q:

A:

Copyright 2002, 2003, 2004, 2005 Cadenux. All rights reserved.