skload.c 7.67 KB
#include <PR/bcp.h>
#include <PR/bbnand.h>
#include "sha1.h"
#include "boot.h"


#define PI_FLASH_DEV0_BUF0_READ_PAGE 0x9f008a10
#define PI_FLASH_DEV0_BUF1_READ_PAGE \
          (PI_FLASH_DEV0_BUF0_READ_PAGE | PI_FLASH_CTRL_BUF1) 

#define PI_AES_CTRL_BASE    0x80000000
#define PI_AES_DATA_SHIFT(data)  ((data)<<PI_AES_CTRL_DATA_SHIFT)
#define PI_AES_IV_SHIFT(iv)      ((iv)<<PI_AES_CTRL_IV_SHIFT)
#define PI_AES_SIZE_SHIFT(size)  ((size)<<PI_AES_CTRL_SIZE_SHIFT)
#define POLL_AES_BUSY  do{}while((IO_READ(PI_AES_CTRL_REG))&PI_AES_CTRL_BUSY)

#define FLASH_MODULE_PRESENT \
             (!((IO_READ(MI_EINTR_REG)&MI_EINTR_MODULE_REMOVED)))
#define FLASH_MODULE_STATE_CHANGED \
             (IO_READ(MI_EINTR_REG)&MI_INTR_MD)
/* NOTE: define below will clear everything in PI_ERROR_REG,
 *  but for boot code this is the desired effect.
 */
#define FLASH_MODULE_CLEAR_STATE_CHANGED \
             (IO_WRITE(MI_EINTR_REG,MI_INTR_MD))


/* instantiate key and init vector */
#include "sk_key.c"


int readFlashPage(u32 pageNum,int piBuf)
{
    IO_WRITE(PI_FLASH_ADDR_REG,pageNum<<PI_FLASH_PAGE_ADDR_SHIFT);
    if(piBuf)
        IO_WRITE(PI_FLASH_CTRL_REG,PI_FLASH_DEV0_BUF1_READ_PAGE);
    else
        IO_WRITE(PI_FLASH_CTRL_REG,PI_FLASH_DEV0_BUF0_READ_PAGE);        

    do{
        if(!FLASH_MODULE_PRESENT){
            /* module not present during operation */

            /* stop current operation */
            IO_WRITE(PI_FLASH_CTRL_REG,0);

            return ERROR_FLASH_MODULE_REMOVED;
        }
    }while(IO_READ(PI_FLASH_CTRL_REG)&PI_FLASH_CTRL_BUSY);

    if(IO_READ(PI_FLASH_CTRL_REG) & PI_FLASH_CTRL_DBERR)
        return ERROR_FLASH_CTRL_DOUBLE_BIT;
    
    return FLASH_SUCCESS;
}


/* first page of good block will be in pi buf 0 */
int getGoodBlock(int startSearch)
{
    int i, badbits, bitshift;
    u32 blockStatus;
    u32 ret;

    do{
        ret = readFlashPage(startSearch<<PI_FLASH_PAGE_PER_BLOCK_POW2,0);
        if(ret == ERROR_FLASH_MODULE_REMOVED){
            return ret;
        }
        blockStatus = IO_READ(PI_BUFFER_0_OOB_START +
                              (PI_FLASH_OOB_BLOCK_STATUS_OFFSET&(~3)));

        /* Given the current definitions in bbnand.h, blockStatus
         * holds bytes 516, 517, 518 and 519 from the flash page.
         * If more than one bit of byte 517 is 0, the block is bad.
         * The bitshift computation will insure byte 517 is checked
         * (or whatever the defines in bbnand.h dictate).
         */
        bitshift = (3 - (PI_FLASH_OOB_BLOCK_STATUS_OFFSET&3))*8;
        for(badbits=0,i=0;i<8;i++){
            if( !((blockStatus>>(bitshift+i))&1) ){
                TRACE(0x9a);
                badbits++;
            }
        }
        startSearch++;
    }while(badbits>1);

    if(ret == ERROR_FLASH_CTRL_DOUBLE_BIT){
        /* block status was good, but had double-bit ECC error */
        TRACE(0x90);
        return ret;
    }

    return startSearch-1;
}


/* buffer can be 0 or 1 */
void aesStart(u32 buffer, u32 hardwareChaining)
{
    u32 aesCmd=PI_AES_CTRL_BASE;

    aesCmd|=PI_AES_DATA_SHIFT(buffer*32);
    if(hardwareChaining)
        aesCmd|=PI_AES_CTRL_HC;
    else
        aesCmd|=PI_AES_IV_SHIFT(PI_AES_INIT_INDX16);
    aesCmd|=PI_AES_SIZE_SHIFT(31);
    IO_WRITE(PI_AES_CTRL_REG,aesCmd);
}


main()
{
    u32 val,*p32;
    int i,page,currentBlock,togo,dbState,ret;
    SHA1Context sha;
    u8 eflashHash[20];
    int blockCount=0;

    TRACE(0x30);

    /* copy expanded key to pi buf */
    for(i=0;i<44;i++)
        IO_WRITE(PI_AES_EKEY_REG+i*4,ekey[i]);

    /* copy iv to pi buf */
    IO_WRITE(PI_AES_INIT_REG,iv[0]);
    IO_WRITE(PI_AES_INIT_REG+4,iv[1]);
    IO_WRITE(PI_AES_INIT_REG+8,iv[2]);
    IO_WRITE(PI_AES_INIT_REG+12,iv[3]);

    /* trigger flash module in/out sequence if running in simulator
     * (cycles through mdio.dat sequence). 
     */
    IDE_WRITE(PI_IDE3_MD_TRIGGER,0);

    TRACE(0x32);

    /* insure flash module inserted */
    if(FLASH_MODULE_STATE_CHANGED || (!FLASH_MODULE_PRESENT)){
        TRACE(0x34);
        JUMP_HANDLER;
    }

    /*
     * note: we could shave about 1.7msec off a 32K SK load
     *       by utilizing two pi buffers and running the
     *       AES and FLASH controllers in tandem (4.8msec
     *       vs. 3.1msec). This is based on the following 
     *       for 512 page processing -
     *         AES     --> 27usec
     *         FLASH   --> 48usec
     *       Given the added code complexity this doesn't
     *       seem worth it at this point. (this data is for
     *       "faster" flash timing and 62 MHz sysclock)
     */

    currentBlock = 0;
    togo = LOAD_SK_PAGES;
    p32 = (u32 *)PHYS_TO_K1(BOOT_RAM_HI_START);
    do{
        currentBlock = getGoodBlock(currentBlock);
        TRACE(0x40);
        blockCount++;
        TRACE(currentBlock);
        if(currentBlock<0){
            TRACE(0x42);
            if(currentBlock == ERROR_FLASH_MODULE_REMOVED){
                TRACE(0x43);
            }
            JUMP_HANDLER;
        }

        for(page=0;page<PI_FLASH_PAGES_PER_BLOCK;page++){

            /* first page in block is in pi buf 0 */
            if(page==0){
                /* decrypt page */
                if(blockCount==1)
                    aesStart(0,0);
                else
                    aesStart(0,1);
            }
            else{
                ret = readFlashPage(
                    (currentBlock<<PI_FLASH_PAGE_PER_BLOCK_POW2) + page,0);
                if(ret < 0){
                    TRACE(0x46);
                    if(ret == ERROR_FLASH_MODULE_REMOVED){
                        TRACE(0x47);
                    }
                    JUMP_HANDLER;
                }
                aesStart(0,1);
            }

            POLL_AES_BUSY;

            TRACE(0x50);
            for(i=0;i<PI_FLASH_PAGE_DATA_SIZE;i+=4){
                *(p32++) = IO_READ(PI_BUFFER_BASE_REG+i);
            }
            togo--;
            if(togo == 0)
                break;
        }
        currentBlock++;
    }while(togo>0);

    /* initialize SHA */
    SHA1Reset(&sha);

#ifdef DEV_SHORTCUT
    SHA1Input(&sha,(u8 *)PHYS_TO_K1(BOOT_RAM_HI_START),loadLen);
#else
    SHA1Input(&sha,(u8 *)PHYS_TO_K0(BOOT_RAM_HI_START),
              LOAD_SK_PAGES*PI_FLASH_PAGE_DATA_SIZE);
#endif
    SHA1Result(&sha,eflashHash);

    TRACE(0x60);

#if 0
    /* output hash result */
    TRACE( *(((u16 *)eflashHash)+0) );
    TRACE( *(((u16 *)eflashHash)+1) );
    TRACE( *(((u16 *)eflashHash)+2) );
    TRACE( *(((u16 *)eflashHash)+3) );
    TRACE( *(((u16 *)eflashHash)+4) );
    TRACE( *(((u16 *)eflashHash)+5) );
    TRACE( *(((u16 *)eflashHash)+6) );
    TRACE( *(((u16 *)eflashHash)+7) );
    TRACE( *(((u16 *)eflashHash)+8) );
    TRACE( *(((u16 *)eflashHash)+9) );
#endif

    /* compare hash */
    p32 = (u32 *)eflashHash;
    if(     (*(p32++) != IO_READ(VIRAGE2_SK_HASH_START))    ||
            (*(p32++) != IO_READ(VIRAGE2_SK_HASH_START+4))  ||
            (*(p32++) != IO_READ(VIRAGE2_SK_HASH_START+8))  ||
            (*(p32++) != IO_READ(VIRAGE2_SK_HASH_START+12)) ||
            (*(p32++) != IO_READ(VIRAGE2_SK_HASH_START+16)) ){
        /* hash does not match - halt */
        JUMP_HANDLER;
    }
    TRACE(0x64);

    /* flip bram and brom */
    val = IO_READ(MI_SEC_MODE_REG);
    val |= MI_SEC_MODE_SECURE;
    val &= ~MI_SEC_MODE_BROM_LO;
    IO_WRITE(MI_SEC_MODE_REG,val);

    /* jump to SK running cached.
     * XXX: since the sk is otherwise entered in un-cached mode,
     *  this entry will be slightly different. Since the sk code
     *  that runs un-cached will likely be asm, and since it will
     *  switch to cached very early, this should be transparent.
     *  But, it needs to be kept in mind while writing SK code.
     */
    asm(".set noreorder; j 0x9fc00000; nop; .set reorder");

}