ChorusOS 4.0 Porting Guide

bootconf Implementation

This section describes the bootconf program implementation provided in Sun Embedded Workshop 4.0.

The main role of bootconf is to hold the BootConf structure described in "bootconf Structure". The structure is generated by the mkimage tool using the ChorusOS configuration file, as described in Chapter 5, System Image Configuration. mkimage then links the generated BootConf structure with the described in this section.

The role of the bootconf code is to install the standalone binaries (such as the bootstrap program, debug agents and debug drivers) and to transfer control to the bootstrap program by passing a pointer to the BootConf structure as an argument.

The bootconf implementation assumes that the memory bank containing the bootconf binary has already been installed at the bank's starting address by the initial loader or PROMer.

The bootconf code is board-independent; it can be used on any board based on a given CPU. Examples in this section are for the PowerPC family of boards. The implementations for other boards have similar logic and structure.

The bootconf implementation is contained in two source files, bconf_crt0.s and bconf_main.c.

bconf_crt0.s Source File

The kernel/snippet/nucleus/boot_tools/bconf_crt0.s file contains the bootconf startup routine, bconf_start().


Example 3-2 bconf_start()

        .section        .chr.my.rw.vaddr
rw_vaddr:       
        .section        .chr.my.rw.kaddr
rw_kaddr:       
        .section        .chr.my.rw.size
rw_size:        
        
        .section        .chr.my.bss.vaddr
bss_vaddr:      
        .section        .chr.my.bss.size
bss_size:       

        .section        .text
                
        GLOBAL(bconf_start)
bconf_start:
        GLOBAL(__mkimage__label__start)
__mkimage__label__start:
        LoadAddr(r5,bconf_main)         /* bconf_main(r3) */
        b       .L1


        GLOBAL(bconf_reboot_start)
bconf_reboot_start:
        GLOBAL(__mkimage__label__reboot)
__mkimage__label__reboot:
        LoadAddr(r5,bconf_reboot_main)  /* bconf_reboot_main(r3, r4) */
        b       .L1


.L1:    
        /*
         * Copy read/write segment if necessary
         *
         * (note that the segment can include the code that we are executing)
         */

        LoadAddr(r8,  rw_kaddr)         /* r8 = src_addr */
        LoadAddr(r9,  rw_vaddr)         /* r9 = dst_addr */ 
        LoadAddr(r10, rw_size)          /* r10 = size    */
                
        cmpwi   r10,0                   /* if (size)                    */
        beq     .L3                     /*                              */
        cmpw    r8, r9                  /*   if (dst_addr != src_addr)  */
        beq     .L3                     /*                              */
.L2:                                    /*     do {                     */
        lbz     r0,0(r8)                /*       r0 = *src_addr         */
        stb     r0,0(r9)                /*       *dst_addr = r0         */
        addi    r8,r8,1                 /*       ++src_addrq            */
        addi    r9,r9,1                 /*       ++dst_addr             */
        subic.  r10,r10,1               /*       --size                 */
        bne     .L2                     /*     } while (size)           */
.L3:                                    /*                              */
        /*
         * Zero bss segment if necessary
         */

        LoadAddr(r9,  bss_vaddr)        /* r9 = dst_addr                */
        LoadAddr(r10, bss_size)         /* r10 = size                   */

        cmpwi   r10,0                   /* if (size)                    */
        beq     .L5                     /*                              */
        li      r0,0                    /*   r0 = 0                     */
.L4:                                    /*   do {                       */
        stb     r0,0(r9)                /*     *dst_addr = 0            */
        addi    r9,r9,1                 /*     ++dst_addr               */
        subic.  r10,r10,1               /*     --size                   */
        bne     .L4                     /*   } while (size)             */
.L5:
        /*
         * Setup the stack
         */
stack_setup:

        LoadAddr(r1, heap)              /* sp = heap[]        */
        LoadAddr(r9, heapSize)          /*                    */
        lwz     r9, 0(r9)               /*                    */
        add     r1, r1, r9              /* sp = sp + heapSize */

        /*
         * Jump to the main
         *
         * (note that if the code was also copied we must jump into the copy)
         */
jump_to_main:

        mtlr    r5
        blr

The bootconf program defines two entry points bconf_start() and bconf_reboot_start(). The power-up initialization program enters using bconf_start() for a cold boot, whereas the reboot program enters using bconf_reboot_start() in the hot reboot path.

The install_me() routine tests whether the read-write segment and bss are link-edited in place (that is, at their places within the memory bank). To obtain the segment's layout within its memory bank and link-editing address, bconf_start() refers to predefined sections that mkimage relocated as follows:

If necessary, install_me() copies the read-write segment and sets the bss to zero. Note that the bootconf code can be part of the read-write segment.

The stack_setup() routine initializes the stack pointer with the limit of the heap. The heap location and size are defined by heapStart and heapLimit (see "Heap and Stack").

The jump_to_main() routine jumps to the bconf_main() routine. If the bootconf code is part of the previously copied read-write segment, this jump transfers control from the original to the copy. The bconf_start program passes the content of register r3 as an opaque argument to bconf_main().

The __mkimage_label_start label enables the power-up program to transfer control to bootconf, as described in Example 3-1.

Note also that bconf_crt0.s preserves the value of r3 and r4 to allow callers to pass, at most, two arguments to the subsequent programs. For example, the initial loader can pass one board-dependent argument to the bootstrap program in r3, whereas the reboot program can pass two arguments (see "Hot Reboot").

bconf_main.c Source File

The kernel/snippet/nucleus/boot_tools/bconf_main.c file contains the bootconf main routine, bconf_main().


Example 3-3 bconf_main()

BootConfRebootEntry __mkimage__label__REF_reboot = 0;

    void
bconf_main(void* cookie)
{
    int i;

    /*
     * Register hot reboot entry
     */
    bootConf->rebootEntry = __mkimage__label__REF_reboot;

    /*
     * Install all standalone sections
     */
    binInstallByMask(BIN_STANDALONE);

    /*
     * Launch bootstrap program
     */
    for (i = 0; i < bootConf->numBins; ++i) {
        BinDesc* bin = &bootConf->binDesc[i];
        if (bin->type == BIN_BOOTSTRAP) {
            (* (BootstrapEntry) bin->entry)(bootConf, cookie);
        }
    }
}

First of all, the bconf_main() routine registers the bootconf hot reboot entry point in the bootConf structure. Note that the registered address must be a reference to the bootconf image. This address can be different from the entry point's link-edit address if the bootconf text segment is not XIP. To provide the reference, the mkimage tool stores the system image address of the location __mkimage__label__rebootin the data location __mkimage__label__REF_reboot.

The bconf_main() routine calls binInstallByMask() to copy (if necessary), the read-write segments of all standalone binaries and to zero their bss. Calling binInstallByMask() at this point, bconf_main() assumes that any memory banks containing standalone binaries have already been installed at the required address. See "binInstallByMask and binInstallByType()" for more information.

The binInstallByMask() function is implemented by the bootstrap framework library (see "Common Bootstrap Implementation Framework").

Finally, the bconf_main() function retrieves the descriptor pointing to the bootstrap program binary in the bootConf structure, and jumps to its entry point. It passes as arguments the address of the bootConf structure and an opaque value from the initial loader.

The kernel/snippet/nucleus/boot_tools/bconf_main.c file also contains the second main routine, bconf_reboot_main(), which is used for performing a hot reboot:


Example 3-4 bconf_reboot_main()

     
    void 
bconf_reboot_main(RebootDesc* rd, void* cookie)
{
		if (rd) {
			/*
			 * Restore the pointer to the persistent memory description
			 */
      bootConf->rebootDesc = rd;
		}

			/*
		 	 * Join the cold bootstrap path
		 	*/
		bconf_main(cookie);
}

bconf_reboot_main() registers a reference to the system state, preserved by the hot reboot (see "Hot Reboot" for details) in the bootConf structure, and then joins the cold reboot pass.