Image storage

The media on which the bootable image is stored, and how it is stored (compressed or not compressed) determine what the IPL must do with the image.

The type of removable media used to store the IPL and the IFS affects many aspects of the IPL design. One of the most significant factors is whether the storage media is linearly-mapped (e.g., NOR FLASH), or non-linearly-mapped (e.g., eMMC, SD card), because it determines if the IPL can use XIP.

Other important factors include how the image is stored (compressed on not compressed), and the device on which it is stored (eMMC, SD card, hard disk, etc.; see Image storage methods).

Linearly-mapped devices

With a linearly-mapped device (e.g., a ROM device) the entire image is in directly-addressable storage that maps its entire address space into the processor's address space. The processor can address any location in the OS image, so the IPL needs to copy only the startup code (and not the entire image) into RAM.

Figure 1. Since a linearly-mapped device can be directly mapped into the processor's address space, the IPL can load only the startup code directly from this device into RAM, leaving the rest of the image on the device.

If the removable media is linearly-mapped, the IPL can use eXecute In Place (XIP). If XIP is used, the .text section of the IPL (the code) in the linker file (e.g., mx6sx-sabre-sdb.lnk or vayu-evm.lnk) must be in the linearly-mapped address space.

Note:

All the IPL assembly code can run before the image is copied into RAM.

Non-linearly-mapped devices

With non-linearly-mapped devices (e.g., an eMMC, SD card, or SPI NOR device), the image is in storage that can't be mapped directly into the processor's address space. The processor can't address the OS image, so the IPL needs to copy the entire image (including the startup code) into RAM.

Figure 2. A QNX IPL loading the entire image from a non-linearly-mapped device, because the processor address on these devices can't be directly mapped into the processor's address space.

Compressed images

If a bootable image is too large to store on the removable media in its original form, or if hardware limitations (e.g., slow bus) make copying and extracting the image more efficient that copying the image in its original format, the bootable image may be compressed on either a linearly-mapped or a non-linearly mapped removable storage device.

When it builds the OS image, the mkifs utility checks for the +compress attribute in the build file. If the attribute is set (e.g., [virtual = x86, apic +compress boot = { ), mkifs compresses the image (see the OS Image Buildfiles chapter).

If the image is compressed, it must be copied to RAM and extracted before the main() function in the IPL's second stage calls the image_scan() functions. When you write an IPL or update a system that uses a compressed image, watch out for the following:

CAUTION:
If you change or add components, this will likely increase the size of your image. Check that there is enough room for the new, larger image between the start address of the uncompressed image and the address where you first copy the compressed image into RAM.

For examples of different storage options and how they are used, see Image storage methods in this chapter.

Image locations

The IPL loads the OS image from different types of devices, or over a network, dependent on what the board supports. The more common locations where bootable images are stored include:

Disk
Most embedded systems now use solid-state media such as a USB key, SD or micro SD card, or eMMC , though some may still use a rotating disk. The board determines the kind of media, if any, from which the system can boot.
With an x86 board, for example, booting from disk is the simplest boot method. The APIC performs all the work: it fetches the image from disk, transfers it to RAM, and starts it.

With ARM boards, which don't have an APIC, booting from disk requires at least:

  • A driver that knows how to access the disk.
  • IPL code that examines the disk's partition table and locates the OS image.
  • IPL code that either maps the image portions into a window and transfers bytes to RAM (solid-state disk), or fetches the data bytes from the disk hardware (rotating disk).
Network
If the board has a PCI network card, the OS image can be loaded over an Ethernet network, and placed in the processor's address space.
BOOTP server
On some embedded boards, the ROM monitor contains the BOOTP code. This code knows how to talk to the networking hardware, and how to get the OS image from a remote system.
To boot a QNX Neutrino system using BOOTP, you need a BOOTP ROM for the OS client and a BOOTP server (e.g., bootpd). Since the TFTP protocol is used to move the image from the server to the client, a TFTP server is also needed; on most systems, this server is provided with the BOOTP server (see bootpd in the Utilities Reference).
Serial port
A serial port on the target can be useful during development for downloading an image or as a failsafe mechanism (e.g., if a checksum fails, you can simply reload the OS image via the serial port).
A serial loader can be built into the IPL code, so that the IPL can fetch the OS image from an external hardware port. The IPL process is almost identical to the process used for a network boot, except that instead of an Ethernet port, a serial port is used to fetch the OS image.
A serial loader usually has a minimal impact on the cost of an embedded system. Board vendors often include serial port functionality on their evaluation boards, sometimes through another port, such as the debug port. In many cases, the serial port hardware and serial loader can be used during project development, then omitted from the final assembly.
QNX supplies source code for an embedded serial loader for the 8250 chip, and the QNX Neutrino SDP includes a utility that sends an OS image to a target over a serial or parallel port (see sendnto in the Utilities Reference).

Alternate method for loading the image

As well as supporting a primary method for loading the OS image, the IPL code may also need to support an alternate method for loading the OS image (e.g., an .altboot in the case of a disk boot on x86 boards). This method may also have to be an automatic fallback in the event that the primary image is corrupt. You can use a .boot directory with a list of fallback IFSs that can be loaded from read-only media.

Image validation

To validate a bootable image, use the checksum() function to perform a checksum over the entire image. A call to validate an image looks like this:

checksum (image_paddr, startup_size);
checksum (image_paddr + startup_size, stored_size - startup_size);
Note: You can speed up the checksum calculation by enabling the cache before calling checksum or another function, such as image_scan(), that calls checksum() (see Optimizing an IPL in this chapter, and enable_cache() in the IPL Library).