V2 RBL functions — allow applications to access RBL services


#include <cyg/rbl/rbl.h>

cyg_bool rbl_update_codeV(cyg_uint32 count, void* buffers[], cyg_uint32 lengths[]);

cyg_bool rbl_update_dataV(cyg_uint32 count, void* buffers[], cyg_uint32 lengths[]);

cyg_bool rbl_load_dataV(cyg_uint32 count, void* buffers[], cyg_uint32 lengths[]);

cyg_bool rbl_update_code_begin(void);

cyg_bool rbl_update_code_block(void* buffer, cyg_uint32 length);

cyg_bool rbl_update_code_end(void);

cyg_bool rbl_update_code_abort(void);

cyg_bool rbl_update_data_begin(void);

cyg_bool rbl_update_data_block(void* buffer, cyg_uint32 length);

cyg_bool rbl_update_data_end(void);

cyg_bool rbl_update_data_abort(void);

cyg_bool rbl_load_data_begin(void);

cyg_bool rbl_load_data_block(void* where, cyg_uint32 length);

cyg_bool rbl_update_data_end(void);


The original V1 API required single buffers for all update and load operations. This proved unduly restrictive, especially when installing a new code image obtained over a network, because there would be no guarantee that a single buffer of the required size could be dynamically allocated when required. Hence the API was extended for V2 with vector functions, allowing the code and data to be spread over multiple buffers, and with transaction functions, allowing new code images to be installed a piece at a time.

Vector Functions

The three vector functions rbl_update_codeV, rbl_update_dataV and rbl_load_dataV work in terms of a series of buffers rather than a single buffer. For example rbl_load_data is equivalent to:

rbl_load_data(cyg_uint8* where, cyg_uint32 size)
    cyg_uint8    dataV[1];
    cyg_uint32   sizesV[1];

    dataV[0]  = where;
    sizesV[0] = size;
    return rbl_load_dataV(1, dataV, sizesV);

Obviously the vector functions become rather more useful for counts greater than 1. The update functions still require that all of the new images are resident in memory, but they no longer have to be in a single contiguous buffer.

When updating some flash drivers may impose limitations on the sizes. For example if the target hardware has a single 16-bit wide flash device then the flash driver may require that all flash write operations happen in multiples of 2 bytes, and the entries in the sizesV array should satisfy this requirement.

Transaction Functions

The transaction functions begin/block/end allow RBL operations to be performed in stages. For example rbl_load_dataV is equivalent to:

rbl_load_dataV(cyg_uint32 count, cyg_uint8* whereV[], cyg_uint32 sizesV[])
    cyg_uint32 i;

    if (! rbl_load_data_begin()) {
        return false;
    for (i = 0; i < count; i++) {
        if (! rbl_load_data_block(whereV[i], sizesV[i])) {
            return false;
    return rbl_load_data_end();

The begin function must be called at the start of a function. At any one time there can be only one code update, one data update, and one data load in progress, and the begin function will block if another thread is performing a conflicting RBL operation. Once the transaction is started the application can perform one or more block operations, and the transaction should normally be committed with an end function call. For an update the begin function will erase the appropriate flash blocks, the block function will write data to the flash, and the end function will write trailer data containing size, checksum and sequence number. At that point the image becomes the new primary code or data RBL block.

As an additional restriction, rbl_update_data_end will block if some other thread is currently loading data. This avoids confusion since otherwise that thread would end up loading data that is no longer primary, and it also avoids problems if another update operation is started immediately.

Unlike the simple or vector update functions, the transaction functions do not require that all of the new image is present in memory at the same time. Instead it is possible to begin a transaction, fetch the first part of the image over the network and install that, fetch the next part, and so on. If the application is unable to complete an update, for example because the network connection is lost, then there should be a call to the abort function instead of to the end function. When a transaction is aborted no trailer gets written to flash so the new image remains invalid and the old image stays as the primary.

As with the vector operations the flash driver may impose limitations on the size arguments to rbl_update_code_block and rbl_update_block. For example if the target hardware uses a 16-bit wide flash chip then the size argument may have to be a multiple of two bytes.

Error Conditions

All of the RBL functions return a simple boolean to indicate failure. In reality failures are unlikely, but can be caused by the following:

  1. The currently installed RedBoot was built without RBL functionality so there is no code in the system to keep track of RBL images and install new ones.
  2. RedBoot uses a different version of the RBL protocol, for example V1 when the application has been built with V2.
  3. The RedBoot RBL code was unable to initialize the system. This can happen if the actual hardware does not match the RedBoot configuration, for example if the flash chips actually present are smaller than expected and cannot hold all the code and data blocks specified by the CYGDAT_RBL_RESERVED_FLASH_BLOCKS, CYGNUM_RBL_CODE_BLOCKS and CYGNUM_RBL_DATA_BLOCKS configuration options.
  4. An attempt is made to load or update data when RedBoot has been configured with zero RBL data blocks,
  5. An attempt is made to load more data than is actually present in the current data image, or to install a new image that does not fit in the number of configured flash blocks.
  6. An unexpected error occurs inside the flash driver, for example an attempt to erase a flash block fails.

For the transaction functions, if an error occurs then the transaction is automatically aborted. There is no need for the application to call rbl_update_code_abort or rbl_update_data_abort explicitly, or to end a load operation.