ChorusOS 4.0 Porting Guide

SBC8260 Board Reboot Program Implementation

This section explains the implementation of the SBC8260 reboot program.

Reboot Program Initialization

Example 4-1is the reboot program initialization source code provided in src/nucleus/bsp/powerpc/sbc8260/src/reboot/reboot.c.


Example 4-1 reboot_main

#define MAX_CHUNKS 16
#define STR_LENGTH 256

PrstChunk chunks[MAX_CHUNKS];
char chunk_id_buf[STR_LENGTH];

RebootDesc rebootDesc;
BootConfRebootEntry rebootEntry;

DbgOps_reset	resetOp;

BootParams bootParams;

    void
reboot_main(BootConf* conf, BootParams* bootp)
{
		if (conf->rebootDesc == 0) {
       /*
        * This is a cold reboot.
        */

       /*
        * Intialize printf()/scanf() support library
        */
       _stdc_consInit(conf->dbgOps.consRead, conf->dbgOps.consWrite);

       /*
        * Register hot reboot descriptor
        */
       rebootDesc.rebootOp = do_reboot;
       rebootDesc.hot.prstMem.numChunks = 0;
       rebootDesc.hot.prstMem.chunks = chunks;
       rebootDesc.hot.prstMem.maxChunks = MAX_CHUNKS;
       rebootDesc.hot.prstMem.curStrLen = 0;
       rebootDesc.hot.prstMem.maxStrLen = STR_LENGTH;
       rebootDesc.hot.prstMem.str = chunk_id_buf;

       conf->rebootDesc = &rebootdesc;

       /*
        * Save hot reboot entry point
        */
       rebootEntry = conf->rebootEntry;

       /*
        * Save reset entry point
        */
       resetOp = conf->dbgOps.reset;

       /*
        * Save bootparams
        */
       if (bootp) {
           bootParams = *bootp;
       }
		} else {
       /*
        * This is a hot reboot. 
        *
        * Nothing to do as the reboot program was intialized at the last cold 
        * reboot.
        */
		}
}

The reboot program is installed only once during a cold boot. For subsequent hot reboots, the reboot program maintains the section of the system state that must be kept. reboot_main() is the reboot program entry point and is called by the bootstrap program each time the system boots.

For a cold boot, when the rebootDesc field of the conf argument is NULL, the reboot program intializes its static data. Whereas for a hot boot the reboot program re-intialization is empty.

One purpose of the program is to maintain a stable system state during hot reboots. This state is represented by a generic HotRebootDesc structure (see "HotRebootDesc Structure") and a board specific BootParams structure (see "Bootstrap Program Implementation").

The bootstrap program exports the address of the reboot service routine, do_reboot(), in the rebootOp field of the rebootDesc structure. The microkernel jumps to this routine to proceed with any kind of reboot. See "HotRebootDesc Structure" for details.

HotRebootDesc Structure

Example 4-2 is the HotRebootDesc structure definition provided in kernel/include/chorus/bki/reboot.h.


Example 4-2 HotRebootDesc structure

/*
 * PrstChunk::status bit values
 */

#define PRST_CHUNK_ALLOCATED 0x1
#define PRST_CHUNK_MAPPED    0x2

/*
 * Descriptor of a chunk of persistent memory
 */

typedef struct PrstChunk {
    char*   id;              /* name string */
    int     status;          /* status bit string */
    VmSize  size;            /* size in bytes */

    PhAddr  paddr;           /* starting physical address 
                              * valid if PRST_CHUNK_ALLOCATED is set */
    VmAddr  vaddr;           /* starting virtual address */
                              * valid if PRST_CHUNK_MAPPED is set */
} PrstChunk;


/*
 * Persistent memory descriptor
 */

typedef struct PrstMem {
    int        maxChunks;    /* max number of persistent memory chunks */
    int        numChunks;    /* number of persistent memory chunks */
    PrstChunk* chunks;       /* array of persistent memory chunks */
    int        maxStrLen;    /* max cumulated size of chunk ids */
    int        curStrLen;    /* current cumulated size of chunk ids */
    char*      str;          /* chunk ids buffer*/
} PrstMem;

/*
 * The state kept over a hot reboot
 */

typedef struct HotRebootDesc {
    PrstMem    prstMem;      /* persistent memory descriptor */
} HotRebootDesc;

The prstMem field of HotRebootDesc describes the persistent memory (the portion of system RAM that must remain the same during subsequent hot reboots). The description is an array of PrstChunk structures, each one describing a persistent memory device (a contiguous named portion of persistent memory). The array is statically allocated in the reboot program data segment.

A persistent memory device is described by its symbolic name, id, the starting physical address, paddr, the starting virtual addresses, vaddr, and the size.

Different operating system components are involved in persistent memory device allocations:

Rebooting the Board

This section describes how the reboot program reboots the board.

Example 4-3 is the reboot service routine source code provided in src/nucleus/bsp/powerpc/sbc8260/src/reboot/reboot.c


Example 4-3 do_reboot() routine

    void
do_reboot(RebootDesc* rd, KnRebootReq* req)
{
    ASSERT(rd == &rebootDesc);

    if (req->mode == K_REBOOT_COLD) {
        rebootCold(req);
    }

    if (req->mode == K_REBOOT_HOT) {
        rebootHot(req);
    }

    if (req->mode == K_REBOOT_NEW) {
        rebootNew(req);
    }

    ASSERT(0);
}

This service routine dispatches execution to a particular reboot procedure.

Cold Reboot

Example 4-4 is the cold reboot service routine source code provided in src/nucleus/bsp/powerpc/sbc8260/src/reboot/reboot.c.


Example 4-4 coldReboot() routine

    void
rebootCold(KnRebootReq* req)
{
    printf ("Cold reboot ...\n");
    resetOp(0);
}

This cold reboot service calls the debug agent hardware reset service routine.

Hot Reboot

Example 4-5 is the hot reboot service routine source code provided in src/nucleus/bsp/powerpc/sbc8260/src/reboot/reboot.c.


Example 4-5 hotReboot() routine

#define STACK_SIZE 0x400
char stack[STACK_SIZE];

    void
rebootHot(KnRebootReq* req)
{
    printf ("Hot reboot ...\n");

    /*
     * Extend the persistemt memory w.r.t the rebbot request
     */
    prstExtend(&rebootDesc.hot.prstMem, &req->u.hot);

    /*
     * switch to a private stack
     */
    call_and_switch_stack(req, rebootHot_cont, stack + STACK_SIZE);
}


    void
rebootHot_cont(KnRebootReq* req)
{
    /*
     * Disable I/D-Caches.
     */
    cachesDisable();

    /*
     * Disable pagination.
     */
    setMSR(getMSR() & ~(MSR_IR | MSR_DR));

    /*
     * Reboot
     */
    rebootEntry(&rebootDesc, &bootParams);
}

This hot reboot service routine:

Note that the implementation switches from the original stack to a small stack area which is statically allocated in the reboot program data segment. This occurs prior to the MMU disabling to ensure that the current stack is safely accessible in the real mode. See "call_and_switch_stack() routine" for details.

Rebooting The New System Image

The ChorusOS boot monitor is implemented as an application on top of ChorusOS. The boot monitor reads the new system image from an external medium (for example, a network) and stores that image in a buffer. It then performs a sysReboot() request that eventually invokes the rebootNew() service routine. To simplify the reboot implementation, the ChorusOS boot monitor has to use a ChorusOS system, configured with flat memory management, model.s. Example 4-6 is the service routine source code provided in src/nucleus/bsp/powerpc/sbc8260/src/reboot/reboot.c.


Example 4-6 rebootNew() Routine

    void
rebootNew(KnRebootReq* req)
{
    KnNewRebootReq* nreq = >u.nw;
    BootParams* bootp;

    printf ("Boot new image ...\n");

    if (nreq->workSize < (launch_end - launch_start) + sizeof(BootParams)) {
        printf ("Not enough working memory to reboot\n");
        printf ("Try cold reboot\n");
        resetOp(0);
    }

    /*
     * Disable I/D-Caches.
     */
    cachesDisable();

    if (nreq->ipcSiteNb) {
        /*
         * Get Chours IPC site number from the loader
         */
        bootParams.ipcSiteNb = nreq->ipcSiteNb;
    }

    /*
     * Copy bootParams at the end of the working area
     */
    bootp = (BootParams*) (nreq->workAddr + nreq->workSize - 
                           sizeof(BootParams));
    bcopy(&bootParams, bootp, sizeof(BootParams));

    /*
     * Copy the launch routine to the working memory
     */
    bcopy(launch_start, (void*) nreq->workAddr, launch_end - launch_start);

    /*
     * Jump to the copied launch code
     */
    ((launch) nreq->workAddr)(nreq->dstAddr, nreq->srcAddr, 
                          nreq->size, nreq->entry, bootp);
}

The caller (that is, sysReboot()) provides a working area that is separate to that from the current system image, including the currently executing reboot program. The buffer, holding the new system image, and the system image destination area are also outside the working area. In the working area, the rebootNew() routine installs the bootParams structure and a small positional independent program, called launch(), and then runs launch(). The launch() program copies the new system image from the buffer to the destination address and jumps to its entry point, passing the address of the bootParams structure as the first argument. See "launch() Routine" for details.