util.c 15.7 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
#include <PR/bcp.h>
#include <PR/bbsim.h>
#include <PR/bbnand.h>
#include <PR/bbvirage.h>
#include <aes.h>
#include <bb_nn.h>
#include "util.h"
#include "nvram.h"
#include "rand.h"
#include <algorithms.h>
#include "PR/bbdebug.h"
#include "PR/rdb.h"


/*
 * globals visible to all files
 */

BbVirage2 *v2 = (BbVirage2 *)PHYS_TO_K1(VIRAGE2_RAM_START);
BbVirage01 v01;	/* memory resident copy of the current virage0,1 contents */

/* global api rights vector. a bitmask corresponding to
 * skapi_call_table[] entry ordinal indices.
 */
u32 gApiRights;


/*
 * DEBUGGING SUPPORT
 */

#define DEBUG_OUT_CHAR(c) (void)(c)
#define NIBBLE_TO_ASCII(v) ((v)<10?('0'+(v)):('a'+(v)-10))

#ifdef SK_LOG_MEM 

#define LOG_START_ADDR 0xa0400000
#define LOG_LENGTH     0x00010000

static u8 *pLogOut = (u8 *)LOG_START_ADDR;
#undef DEBUG_OUT_CHAR
#define DEBUG_OUT_CHAR(c)  \
       if( (u32)(pLogOut-LOG_START_ADDR) < (u32)LOG_LENGTH ) *(pLogOut++)=(c)

#endif /* SK_LOG_MEM */

#ifdef SK_LOG_IDE

#undef DEBUG_OUT_CHAR
#define BACKDOOR_PRINT		0x046fffe0
#define DEBUG_OUT_CHAR(c)  \
        IDE_WRITE(BACKDOOR_PRINT, (c))

#endif /* SK_LOG_IDE */


#ifdef SK_LOG_RDB
#define PROBE_IDE_RDB() \
	(IDE_WRITE(IDE_RDB_RDATA_REG+0,0xbabe), \
	 IDE_WRITE(IDE_RDB_RDATA_REG+2,0xcafe), \
	 ((IDE_READ(IDE_RDB_RDATA_REG+0) == 0xbabe) & \
	  (IDE_READ(IDE_RDB_RDATA_REG+2) == 0xcafe)))
void
message(const char* buf) {

    /* write 1 character at a time to debug port */
    if (PROBE_IDE_RDB()) {
	while(*buf) {
	    IDE_WRITE(IDE_RDB_RDATA_REG, ((RDB_TYPE_GtoH_PRINT << 2)|1) << 8 | *buf++);
	    IDE_WRITE(IDE_RDB_CTRL_REG, IDE_RDB_CTRL_SET_BB_REQ|IDE_RDB_CTRL_CLR_HOST_ACK);
	    while((IDE_READ(IDE_RDB_STATUS_REG) & IDE_RDB_STATUS_HOST_ACK) == 0)
		    ;
	}
    }
}

void output_int32_hex(u32 val)
{
    int i;
    char buf[11];
    buf[0] = '0'; buf[1] = 'x';
    for(i = 0; i < 8; i++)
	buf[2+i] = NIBBLE_TO_ASCII((val>>(4*(7-i)))&0xf);
    buf[10] = 0;
    message(buf);
}

#else

#if defined(SK_LOG_IDE) || defined(SK_LOG_MEM)
void message(const char* s) {
    while((*s)) {
        DEBUG_OUT_CHAR(*(s++));
    }
}

void output_int32_hex(u32 val)
{
    DEBUG_OUT_CHAR('0');
    DEBUG_OUT_CHAR('x');
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>28)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>24)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>20)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>16)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>12)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>8)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>4)&0xf));
    DEBUG_OUT_CHAR(NIBBLE_TO_ASCII((val>>0)&0xf));
}

#endif
#endif

#ifdef DEBUG
void output_int32_array(u32 *d, int num)
{
    int i;
    for (i=0; i<num; i++) {
        output_int32_hex(d[i]);
        message("\n");
    }
}
#endif

/* 
 * UTILS USED BY MULTIPLE SOURCE FILES
 */

/*
 * If the public key in Virage 2k array is zero, generate it and
 * fill it in. Else copy it.
 */
void getBbPublicKey(BbEccPublicKey pubkey)
{
    int i;
    for (i=0; i<sizeof(BbEccPublicKey)/sizeof(u32); i++) {
        if (v2->publicKey[i] != 0) {
            wmemcpy(pubkey, v2->publicKey, sizeof(BbEccPublicKey)/4);
            return;
        }
    }

    eccGenPublicKey(pubkey, v2->privateKey);
    wmemcpy(v2->publicKey, pubkey, sizeof(BbEccPublicKey)/4);

}

void setAccessRights(BbContentMetaDataHead *cmdh)
{
    u32 v;
    /* setup hardware access based on rights in ticket */
    IO_WRITE(PI_ACCESS_REG, cmdh->hwAccessRights & BB_CMD_HWAR_PI_MASK);
    v = USB_SECURE_MODE_ON;
    if(cmdh->hwAccessRights & BB_CMD_HWAR_USB_MASK)
	v = USB_SECURE_MODE_OFF;
    IO_WRITE(USB0_SECURE_MODE_REG, v);
    IO_WRITE(USB1_SECURE_MODE_REG, v);

    v = IO_READ(MI_SEC_MODE_REG) & ~MI_SEC_MODE_IRAM_ACCESS;
    if(cmdh->hwAccessRights & BB_CMD_HWAR_IRAM_MASK)
    	v |= MI_SEC_MODE_IRAM_ACCESS;
    IO_WRITE(MI_SEC_MODE_REG, v);

    /* setup future skapi rights based on rights in ticket */
    gApiRights=cmdh->secureKernelRights;
}

/*
 * Signature verification
 */

int verifyRsaSigDataChain(
    SkDataChain *data,
    int number,  /* number in above chain */
    u32 *rsaPubkey,         /* size determined by sigType arg */
    BbRsaExponent rsaExp,
    u32 sigType,           /* signature type, BB_SIG_TYPE_* */
    BbGenericSig *signature /* compare against this */
    )
{
    /* 
     * calculate hash
     */
    u8 hash[20];
    SHA1Context sha;
    int i;

    SHA1Reset(&sha);
    for(i=0; i< number; i++){
        if (data[i].size > 0){
            SHA1Input(&sha,data[i].data,data[i].size);
        }
    }
    SHA1Result(&sha,(u8 *)hash);

    /* decrypt and compare */
    return verifyRsaSigFromHash((u32 *)hash, rsaPubkey, 
				rsaExp, sigType, signature);
}


int verifyRsaSigFromHash(
			 BbShaHash hash,
			 u32 *rsaPubkey,  /* size determined by sigType arg */
			 BbRsaExponent rsaExp,
			 u32 sigType,    /* signature type, BB_SIG_TYPE_* */
			 BbGenericSig *signature /* compare against this */
			 )
{
    
    unsigned char  cmdComputedSig[sizeof(BbRsaPublicKey4096)];
    u32 printStart, len;

    /* compute number of bits from type */
    if (sigType == BB_SIG_TYPE_RSA2048){
	len = 2048;
	printStart = sizeof(BbRsaPublicKey2048);
    } else if(sigType == BB_SIG_TYPE_RSA4096){
	len = 4096;
	printStart = sizeof(BbRsaPublicKey4096);
    } else
        return SK_FAIL;

    bsl_rsa_verify(cmdComputedSig, (u32 *)signature, rsaPubkey, &rsaExp, len);
    printStart -= sizeof(BbShaHash);
    if (memcmp(hash, cmdComputedSig+printStart, sizeof(BbShaHash)) == 0)
	return SK_SUCCESS;
    else
        return SK_FAIL;

}



/* can only get max 8 words */
int getHWRandoms(u32 *keydata, int words){
    int i, k;
    u8 randchar;
    u32 grabbedrandom;
    SHA1Context sha;
    u8 blocal[RAND_INPUT_BYTES];
    u8 b[NBITS/8];
    u8 hash_data[20];
    int ret;
    int block;

    if(words > 8){
      return SK_API_FAIL;
    }
    do{
      for(block =0; block < RAND_NUM_BLOCKS; block++){
	for(i = 0; i < RAND_INPUT_BYTES; i++){
	  randchar = 0;
	  for (k=0; k < 8; k++){
            grabbedrandom = IO_READ(MI_RANDOM_REG);
	    randchar = (u8) (randchar+ (u8)((grabbedrandom & 0x01) << k));  
	  }
	  blocal[i] = randchar;
	}

	SHA1Reset(&sha);
	SHA1Input(&sha, blocal, RAND_INPUT_BYTES);
	SHA1Result(&sha, hash_data);
      
	memcpy(((u8 *)b)+(block*sizeof(BbShaHash)),
	       hash_data, sizeof(BbShaHash));
      }
      
      ret = dofips(b, NBITS/8);
    }while(ret == SK_API_FAIL);

    /* random numbers are good: take two random sized
     * blocks of data and return their hashes
     */
    
    SHA1Reset(&sha);
    SHA1Input(&sha, b, b[0]+1);
    SHA1Input(&sha, (u8 *) v2->appStateKey, sizeof(BbAesKey));
    SHA1Input(&sha, (u8 *) v2->selfMsgKey, sizeof(BbAesKey));
    SHA1Result(&sha, hash_data);
    if(words > 4){
      wmemcpy(keydata, (u32 *)hash_data, 4);
      SHA1Reset(&sha);
      SHA1Input(&sha, b, b[1]+1);
      SHA1Result(&sha, hash_data);
      wmemcpy(keydata + 4, (u32 *)hash_data, words - 4);
    }
    else{
      wmemcpy(keydata, (u32 *)hash_data, words);
    }
        
    return SK_API_SUCCESS;
}



int 
getRandoms(u32 *randoms, int numwords){
  int block;
  int extras;
  int numblocks = numwords/8;
  extras = numwords % 8;

  /* do the < 8 words first */
  if (extras > 0){
    if(getHWRandoms(randoms, extras) != SK_API_SUCCESS){
      return SK_API_FAIL;
    }
  }
  randoms += extras;
  for(block =0; block < numblocks; block++){
    if(getHWRandoms(randoms + block*8, 8) != SK_API_SUCCESS){
      return SK_API_FAIL;
    }
  }
  
  return SK_API_SUCCESS;
}
  
/* wrapper for libcrypto call which loops over until any component of
 * sign is not zero 
 */
void computeEccSig(u8 *data, u32 datasize, BbEccPrivateKey private_key, BbEccSig sign, u32 identity){
   u32 randoms[8];
   BSL_error ret;
   do{
     getRandoms(randoms, 8);
     ret = bsl_compute_ecc_sig(data, datasize, private_key, randoms, sign, identity);
   }while(ret != BSL_OK);
}

/* wrapper for libcrypto call which calls ecc verify and return success or
 * failure based on internal result
 */
int verifyEccSig(u8 *data, u32 datasize, BbEccPublicKey public_key, BbEccSig sign, u32 identity){
  boolean res;
  bsl_verify_ecc_sig(data, datasize, public_key, sign, &res, identity);
  if(res != BSL_TRUE){
    return SK_API_FAIL;
  }
  return SK_API_SUCCESS;
}
  

int pollDma()
{
    while(IO_READ(PI_STATUS_REG) & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY)) {
        if (IO_READ(PI_STATUS_REG) & PI_STATUS_ERROR){
            message("DMA Failed!!!\n");
            return SK_FAIL;
        }
    }
    IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);

    return SK_SUCCESS;
}

/* dramAddr is physical.
 * dma full flash page from indicated pi buffer.
 * enforce 2B size alignment.
 */
int piBufDma(u32 piBuf,u32 dramAddr,u32 bytes,u32 dir)
{
    /* TODO: read status - insure no dma or io in progress */

    /* XXX: check if this is really needed
    bytes++;
    bytes&=~1;
    */

    /* dma dram to pi buffer */
    IO_WRITE(PI_DRAM_ADDR_REG,dramAddr);
    IO_WRITE(PI_CART_ADDR_REG,piBuf?PI_BUFFER_DATA_SIZE:0);
    if(dir==SK_DMA_BUF_TO_DRAM)
        IO_WRITE(PI_DMA_BUFFER_WR_REG,bytes-1);
    else
        IO_WRITE(PI_DMA_BUFFER_RD_REG,bytes-1);

    return pollDma();
}


/* 
 * AES drivers
 */

void aesHwInit(u32 *key,u32 *iv)
{
    u32 ekey[44];

    aes_HwKeyExpand((u8 *)key, (u8 *)ekey);
    wmemcpy((void*)PHYS_TO_K1(PI_AES_EKEY_REG), ekey, 44);
    wmemcpy((void*)PHYS_TO_K1(PI_AES_INIT_REG), iv, 4);
}

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);
}


/*
 * page based app loading
 */

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 SK_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 SK_ERROR_FLASH_CTRL_DOUBLE_BIT;

    return SK_SUCCESS;
}


/*
 * clib string funcs
 */

char *strchr(const char *s, int c)
{   /* find first occurrence of c in char s[] */
    const char ch = c;
    
    for (; *s != ch; ++s)
        if (*s == '\0')
            return (NULL);
    return ((char *) s);
}

size_t strlen(const char *s)
{   /* find length of s[] */
    const char *sc;
    
    for (sc = s; *sc != '\0'; ++sc);
    return (sc - s);
}

int strcmp(const char *s,const char *t)
{
    for(;*s==*t;s++,t++)
        if(*s=='\0')
            return 0;
    return *s - *t;
}


int strncmp(const char *s,const char *t, int bytes)
{
    int i;
    int result = 0;
    for(i =0; i< bytes; i++){
        if(s[i] != t[i]){
            result = -1;
        }
    }
    return result;
}


char *strstr(const char * s1,const char * s2)
{
    int l1, l2;
    
    l2 = strlen(s2);
    if (!l2)
        return (char *) s1;
    l1 = strlen(s1);
    while (l1 >= l2) {
        l1--;
        if (!memcmp(s1,s2,l2))
            return (char *) s1;
        s1++;
    }
    return NULL;
}

/* XXX: comment out occasionally to catch any hidden dependencies on memcpy,
 * such as copying large structs to functions on stack.
 */
void *memcpy(void *s1, const void *s2, size_t n)
{   /* copy char s2[n] to s1[n] in any order */
    char *su1;
    const char *su2;
    
    for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n)
        *su1 = *su2;
    return (s1);
}


void* wmemcpy(void* s1, const void* s2, size_t n) {
    u32 *su1;
    const u32 *su2;
    for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n)
        *su1 = *su2;
    return (s1);
}

void *memset(void *s, int c, size_t n)
{
    u8* s1 = s;
    int i;
    for(i = 0; i < n; i++)
	s1[i] = c;
    return s;
}

void bzero(void* s, size_t n)
{
    memset(s, 0, n);
}

int memcmp(const void *s1, const void *s2, size_t n)
{
    const u8* a = s1, * b = s2;
    u8 a1, b1;
    while (n-- > 0) {
	if ((a1 = *a++) == (b1 = *b++)) continue;
	return a1 - b1;
    }
    return 0;
}


/*
 * virage[01] management
 */

s8 gCurv01 = -1;

static u16
v01Sum(u16* v) {
    u16 sum = 0;
    int i;
    for(i = 0; i < (VIRAGE0_RAM_END-VIRAGE0_RAM_START)/2; i++)
	sum += v[i];
    return sum;
}

static int
v01Validate(u32 vaddr, BbVirage01* bbv)
{
    wmemcpy(bbv, (void*)PHYS_TO_K1(vaddr), (VIRAGE0_RAM_END-VIRAGE0_RAM_START)/4);
    /* checksum */
    if (v01Sum((u16*)bbv) == BB_VIRAGE01_CKSUM)
	return bbv->seq;
    return -1;
}

int
v01Update(BbVirage01* v)
{
    /* recompute the checksum, serial number and
     * store over the older of v[01]
     */
    v->seq++;
    v->sum = 0;
    v->sum = BB_VIRAGE01_CKSUM - v01Sum((u16*)v);
    if (nms_store_and_verify(gCurv01 == 1 ? VIRAGE0_CTRL_REG : VIRAGE1_CTRL_REG,
		v, sizeof *v/4) < 0)
	return SK_FAIL;
    gCurv01 ^= 1;
    return SK_SUCCESS;
}

int
v01Load(BbVirage01* v)
{
    int v0status, v1status;
    nms_init();
    /* issue recalls on both v[01] and resolve which one is more
     * up to date
     */
    if (nms_recall(VIRAGE0_CTRL_REG) < 0)
	return SK_FAIL;
    v0status = v01Validate(PHYS_TO_K1(VIRAGE0_RAM_START), v);
    if (nms_recall(VIRAGE1_CTRL_REG) < 0)
	return SK_FAIL;
    v1status = v01Validate(PHYS_TO_K1(VIRAGE1_RAM_START), v);

    if (v0status < 0 && v1status < 0) {
	/* initialize virage */
	memset(v, 0, sizeof *v);
	gCurv01 = 0;
	return v01Update(v);
    } else if (v0status > v1status) {
	/* re-fetch v0 */
	if (nms_recall(VIRAGE0_CTRL_REG) < 0 ||
	    v01Validate(PHYS_TO_K1(VIRAGE0_RAM_START), v) < 0)
	    return SK_FAIL;
	gCurv01 = 0;
    } else {
	gCurv01 = 1;
    }
    return SK_SUCCESS;
}

u16*
getCcSlot(BbTicketId tid) {
    tid &= ~BB_TICKET_ID_LIMITED;
    if (tid < v01.tidWindow || tid >= v01.tidWindow+BB_MAX_CC)
	return 0;
    return &v01.cc[tid-v01.tidWindow];
}

#define SK_BETWEEN(a, x, b)     ((((unsigned)(x))-(a)) <= (((unsigned)(b))-(a)))
#define SK_PTR_VALID(s, e, a) \
		(SK_BETWEEN(K0BASE, (u32)(s), K0BASE+0x800000) & \
		 SK_BETWEEN(K0BASE, (u32)(e), K0BASE+0x800000) & \
		 !(((u32)(s))&(a-1)))
#define SK_BUNDLE_PTR_VALID(s, e, a) \
		(SK_BETWEEN(CMDBUNDLE_STORAGE_START, (u32)(s), CMDBUNDLE_STORAGE_START+16384) & \
		 SK_BETWEEN(CMDBUNDLE_STORAGE_START, (u32)(e), CMDBUNDLE_STORAGE_START+16384) & \
		 !(((u32)(s))&(a-1)))

int
ptrValid(void* start, u32 len, int align) {
    return SK_PTR_VALID(start, (u8*)start+len, align);
}

int bundlePtrValid(void* start, u32 len, int align)
{
    return SK_BUNDLE_PTR_VALID(start, (u8*)start+len, align);
}


int
certChainPtrsValid(BbCertBase *chain[BB_CERT_CHAIN_MAXLEN])
{
    if (!ptrValid(chain, sizeof chain, 4))
	return 0;
    if (!ptrValid(chain[0], sizeof(BbCertBase), 4))
	return 0;
    if(chain[0]->certType == BB_CERT_TYPE_SERVER){
        if (!ptrValid(chain[0], sizeof(BbRsaCert), 4))
            return 0;
        if (strcmp(chain[0]->issuer,BB_CERT_STR_ROOT) &&
            !ptrValid(chain[1], sizeof(BbRsaCert), 4))
            return 0;
    }
    else{
        if (!ptrValid(chain[0], sizeof(BbEccCert), 4))
            return 0;
        if (!ptrValid(chain[1], sizeof(BbRsaCert), 4))
            return 0;
        if (!ptrValid(chain[2], sizeof(BbRsaCert), 4))
            return 0;
    }
    return 1;
}

#ifdef SK_STACK_CHECK
int stackCheckUsage()
{
    u32 *p;
    for(p = (u32 *)PHYS_TO_K0(INTERNAL_RAM_START); 
        p < (u32 *)PHYS_TO_K0(INTERNAL_RAM_END-SK_CONTEXT_SIZE); 
        p++){
        if(*p != 0xdeadbeef)
            break;
    }
    return (u32)(PHYS_TO_K0(INTERNAL_RAM_END-SK_CONTEXT_SIZE))-((u32)p); 
}
#endif