Saturday, August 22, 2009

ARM Linux Kernel Boot Requirements(www.embeddedsoftwarelabs.com)



Kernel and Device Drivers

The Linux kernel itself is very portable and configurable. In fact, porting Linux to new hardware can take less time than the equivalent task using an RTOS when the board's CPU type and serial port device is already supported by the core kernel. Once the kernel is up and running, device drivers can be tested. Many devices already have device drivers for Linux, even if they aren't distributed with the core kernel. The modular architecture of the kernel and its well designed internal mechanisms mean that device drivers are often usable on architectures other than those for which they were originally designed. The key point here is that investing effort in writing Linux kernel device drivers correctly yields device support for a number of different platforms when Linux is used on each of those platforms.

Some companies are understandably reluctant to write device drivers for a single operating system. Instead, they prefer to add a level of abstraction between the driver code and OS to enable a different OS to be used without altering the driver code. The same aim can be achieved by writing the core code of the device driver as a set of ANSI C, non-blocking functions which handle all of the low-level hardware accesses. These functions present a C API to the device. Then, an OS-specific driver is written which calls the common ANSI C routines. However, even this method still has its drawbacks.

  • The Linux kernel provides primitives for hardware access, taking care of things like endian conversions, cache coherency, memory barriers, CPU pipelines, optimized data copying etc. These would be unavailable to the OS-agnostic driver functions.
  • Developers learn a lot by studying device drivers in the core kernel and can quickly pick up techniques used. Implementing a policy of writing core code of device drivers as portable C functions tends to discourage developers from studying existing kernel code. Worse, the code might already exist in the kernel, but because the developer isn't familiar with the Linux kernel source code, the existing code has been missed. Significant effort can therefore be wasted, potentially costing the company in time to market.
It is the author's view that device drivers should always be targeted and therefore optimized for the OS being used. It doesn't take long to port a driver to a different OS; the advantages of having some common code shared by drivers for different OSes are often canceled out by the practicalities of software development: fixing a bug in a device driver for one OS may introduce a bug when the code is used in another OS. Device drivers are difficult to regression test and it is common for device driver developers to have specific knowledge of only a subset of the number of different OSes using a section of code.

Tools for Embedded Linux

People who are used to supported, proprietary tools provided by RTOS vendors are often disappointed by the tools available to support development for Embedded Linux. There are several reasons for this:
  • Most Embedded Linux tools are Open Source and run on UNIX/Linux development hosts. Many RTOS developers are used to working on Windows development hosts and lack of familiarity with the environment makes the tools seem harder to use.
  • Because of the wide range of applications that Linux is able to execute, Embedded Linux systems are much more complex under the hood than any RTOS environment. Tools are therefore much more difficult to develop. Separate memory address spaces for user processes and kernel and the way that the OS pages memory in and out make analyzing the system externally very difficult for any development tool.
  • RTOS developers sometimes expect to find exact equivalents of RTOS tools available for Embedded Linux. Tools like MemScope for analyzing memory usage, for example, don't work for Embedded Linux because the virtual memory model breaks assumptions made by those RTOS tools. In Linux, a user application automatically cleans up when it exits, including any memory that it allocates. So many simple applications don't bother freeing allocated memory or closing files when the application is short-lived. When developing long-lived applications (e.g. daemons that run all the time that the system is up), developers must use good programming practices to find memory leaks, timing bugs, data bounds check errors etc by unit testing rather than relying on OS tools to find the problems during integration.


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

Booting ARM Linux


In order to boot ARM Linux, you require a boot loader, which is a small program that runs before the main kernel. The boot loader is expected to initialise various devices, and eventually call the Linux kernel, passing information to the kernel.
Essentially, the boot loader should provide (as a minimum) the following:
  1. Setup and initialise the RAM.
  2. Initialise one serial port.
  3. Detect the machine type.
  4. Setup the kernel tagged list.
  5. Call the kernel image.
1. Setup and initialise RAM
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
The boot loader is expected to find and initialise all RAM that the kernel will use for volatile data storage in the system. It performs this in a machine dependent manner. (It may use internal algorithms to automatically locate and size all RAM, or it may use knowledge of the RAM in the machine, or any other method the boot loader designer sees fit.)
2. Initialise one serial port
Existing boot loaders: OPTIONAL, RECOMMENDED
New boot loaders: OPTIONAL, RECOMMENDED
The boot loader should initialise and enable one serial port on the target. This allows the kernel serial driver to automatically detect which serial port it should use for the kernel console (generally used for debugging purposes, or communication with the target.)
As an alternative, the boot loader can pass the relevant 'console=' option to the kernel via the tagged lists specifing the port, and serial format options as described in
linux/Documentation/kernel-parameters.txt.
3. Detect the machine type
Existing boot loaders: OPTIONAL
New boot loaders: MANDATORY
The boot loader should detect the machine type its running on by some method. Whether this is a hard coded value or some algorithm that looks at the connected hardware is beyond the scope of this document. The boot loader must ultimately be able to provide a MACH_TYPE_xxx value to the kernel. (see linux/arch/arm/tools/mach-types).
4. Setup the kernel tagged list
Existing boot loaders: OPTIONAL, HIGHLY RECOMMENDED
New boot loaders: MANDATORY
The boot loader must create and initialise the kernel tagged list. A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE. The ATAG_CORE tag may or may not be empty. An empty ATAG_CORE tag has the size field set to '2' (0x00000002). The ATAG_NONE must set the size field to zero.
Any number of tags can be placed in the list. It is undefined whether a repeated tag appends to the information carried by the previous tag, or whether it replaces the information in its entirety; some tags behave as the former, others the latter.
The boot loader must pass at a minimum the size and location of the system memory, and root filesystem location. Therefore, the minimum tagged list should look:
 +-----------+
base -> | ATAG_CORE |  |
+-----------+  |
| ATAG_MEM  |  | increasing address
+-----------+  |
| ATAG_NONE |  |
+-----------+  v
The tagged list should be stored in system RAM.
The tagged list must be placed in a region of memory where neither the kernel decompressor nor initrd 'bootp' program will overwrite it. The recommended placement is in the first 16KiB of RAM.
5. Calling the kernel image
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
There are two options for calling the kernel zImage. If the zImage is stored in flash, and is linked correctly to be run from flash, then it is legal for the boot loader to call the zImage in flash directly.
The zImage may also be placed in system RAM (at any location) and called there. Note that the kernel uses 16K of RAM below the image to store page tables. The recommended placement is 32KiB into RAM.
In either case, the following conditions must be met:
  • CPU register settings
    • r0 = 0.
    • r1 = machine type number discovered in (3) above.
    • r2 = physical address of tagged list in system RAM.
  • CPU mode
    • All forms of interrupts must be disabled (IRQs and FIQs.)
    • The CPU must be in SVC mode. (A special exception exists for Angel.)
  • Caches, MMUs
    • The MMU must be off.
    • Instruction cache may be on or off.
    • Data cache must be off and must not contain any stale data.
  • Devices
    • DMA to/from devices should be quiesced.
  • The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image.
http://www.arm.linux.org.uk/developer/booting.php#

No comments:

Post a Comment