Booting from a bank-switched device

Let's assume we're booting from a bank-switched or paged device (e.g. paged flash, disk device, network, etc.), and that the image is uncompressed. The IPL needs to handle these main tasks:

  1. The IPL must first use a C function to talk to the device in question. We'll use a serial download for this discussion. For serial downloads, the IPL uses image_download_8250(), a function that specifically knows how to configure and control the 8250 class of serial controllers.

    Once the controller is set up, the function's task is to copy the image via the serial controller to a location in RAM.

  2. We now have an OS image in RAM. The IPL then uses the image_scan() function, which takes a start address and end address as its parameters. It returns the address at which it found the image:
    unsigned long image_scan (unsigned long start,
                              unsigned long end);
    

     

    The image_scan() function:

    • Scans for a valid OS signature over the range provided. Note that this can be multiple OS images.
    • Copies the startup header from the image to a struct startup_header variable.
    • Authenticates the startup signature (STARTUP_HDR_SIGNATURE).
    • Performs a checksum on the startup.
    • Performs a checksum on the OS image filesystem.
    • Saves the address and version number of the OS in case it's set up to scan for multiple OS images.
  3. Once the OS image has been found and validated, the IPL's next function to call is image_setup(), which takes the address of the image as its parameter and always returns 0:
    int image_setup (unsigned long address)
    

     

    The image_setup() function:

    • Copies the startup header from the image to a struct startup_header variable. Although this was performed in image_scan() (and startup_header is a global), it's necessary here because image_scan() can scan for multiple images, which will overwrite this structure.
    • Calculates the address to which startup is to be copied, based on the ram_paddr and paddr_bias structure members (from the startup header).
    • Fills in the imagefs_paddr structure member, based on where the image is stored. The startup program relies on this member, because it's the one responsible for copying the OS image filesystem to its final location in RAM. The startup program doesn't necessarily know where the image is stored.
    • Copies the final startup structure to the ram_paddr address, and then copies the startup program itself.

    At this phase, the startup program has been copied to RAM (and it must always execute from RAM), and the startup header has been patched with the address of the OS image.

    Note: Since the startup program is responsible for copying the image filesystem to its final destination in RAM, the IPL must copy the image to a location that's linearly accessible by the startup program, which has no knowledge of paged devices (serial, disk, parallel, network, etc.).

    Note also that if the image is compressed, then the IPL can copy the compressed image to a location that won't interfere with startup's decompression of the image to its final destination in RAM. When the image lives in flash (or ROM or whatever linear storage device), this isn't an issue. But when the image is stored on a paged device, more care must be taken in placing the image in a RAM location that won't interfere with startup's decompression of the image. Here are the rules:

    Uncompressed
    If the image is uncompressed, then the IPL can copy the image from the paged device directly to its destined location. Startup will compare the addresses and realize that the image doesn't need to be copied.
    Compressed
    If the image is compressed, then startup must copy and decompress the image using a different location than the final RAM location.
  4. The last phase is to jump to the startup entry point. This is accomplished by calling image_start():
    int image_start (unsigned long address);
    

     

    The image_start() function should never return; it returns -1 if it fails.

    The function jumps to the startup_vaddr address as defined in the startup header.