/* * Copyright (c) 2011 Apple Inc. All rights reserved. * * This document is the property of Apple Inc. * It is considered confidential and proprietary. * * This document may not be reproduced or transmitted in any form, * in whole or in part, without the express written permission of * Apple Inc. */ #include #include #include #include #include #include #include #include #include #include "util_boot.h" #include "anc_bootrom.h" #include "anc_llb.h" #define BOOT_NUM_ELEMENT (12) #define BOOT_NUM_PSLOTS (32) typedef struct { uint32_t page : 8; uint32_t slot : 8; uint32_t pslot : 8; uint32_t RFU : 8; } UtilBoot_location_t; typedef struct { UtilBoot_location_t location[UTIL_NUM_ELEMENT]; uint32_t prevUtilDMversion; uint32_t prevUtilDMslot; bool BCopyPresent; uint8_t minorVersion; } UtilBoot_t; typedef struct { UtilBootDM_t s; uint32_t version; uint32_t RFU; // was used by mxcfg uint16_t erases[UTIL_NUM_PSLOTS]; uint8_t clogMajor; uint8_t clogMinor; uint8_t pendDefect; // defect pending (shuffle in progress). uint8_t pad[4096 - sizeof(UtilBootDM_t) - 11 - UTIL_NUM_PSLOTS*2]; }UtilDM_t; extern anc_ppn_device_params_t *anc_geom; #define CASSERT(x, name) typedef char __ASP_CASSERT_##name[(x) ? 1 : -1] CASSERT(sizeof(UtilDM_t)==4096, sizeUtilDMcorrect); extern int anc_num_channel; #define quantup(num, gran) (((num) + (gran) - 1) / (gran)) #define ROUNDUPTO(num, gran) ((((num) + (gran) - 1) / (gran)) * (gran)) static UtilDM_t* UtilDM; static UtilDM_t* UtilDM_backup; static UtilBoot_t Util; #define META_LBA_INDEX 0 static uint32_t meta[4]; // prototypes uint32_t Boot_Slip (uint32_t slot); void Boot_BandDip (uint32_t pslot, uint32_t* band, uint32_t* dip); static int anc_read_fw_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size); bool Boot_PostProcessDM(UtilDM_t *p, uint32_t slot, uint32_t page, uint32_t *meta); #if WITH_LLB_NVRAM bool Boot_Read(void *buffer, uint32_t page, uint32_t slot, uint32_t *meta); uint32_t Boot_Find_Fast_Scan(void *buffer, uint32_t page, uint32_t slot); void Boot_Find_Fast(void *buffer); void Boot_Find_UtilDM(void *buffer); static int anc_read_nvram_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size); #endif #if WITH_LLB_BLKDEV static int anc_read_llb_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size); #endif // POR equivalent. Resets the Nand but does not do discovery. Zeros out the UtilDM->s.utilMajor to indicate UtilDM not loaded. bool anc_reset(int resetMode) { bool err; UtilDM->s.utilMajor = 0; // indicate UtilDM not loaded. meta[1]=0; meta[2]=0; meta[3]=0; err = anc_bootrom_init(true, resetMode); if (err != 0) { return false; } else { return true; } } // Entry point from LLB bool anc_firmware_init(void) { bool err; struct blockdev *bdev; #if WITH_LLB_NVRAM struct blockdev *nv_bdev; #endif #if WITH_LLB_BLKDEV struct blockdev *llb_bdev; #endif UtilDM = memalign(sizeof(UtilDM_t), CPU_CACHELINE_SIZE); UtilDM_backup = memalign(sizeof(UtilDM_t), CPU_CACHELINE_SIZE); if (!UtilDM) { dprintf(DEBUG_CRITICAL, "Failed to malloc UtilDM\n"); return false; } if (!UtilDM_backup) { dprintf(DEBUG_CRITICAL, "Failed to malloc UtilDM_backup\n"); return false; } bzero(UtilDM, sizeof(UtilDM_t)); bzero(UtilDM_backup, sizeof(UtilDM_t)); uint32_t block_size; uint32_t size; err = anc_llb_init(); if (err != 0) { dprintf(DEBUG_CRITICAL,"Failed to reset ANC\n"); return false; } // Load UtilDM meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM; if (anc_llb_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM_backup, &meta[0])!=BOOT_SIZE_UTILDM) { UtilDM->s.utilMajor = 0; return(false); } Boot_PostProcessDM(UtilDM_backup,0,0,meta); dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor); if (UtilDM->s.eSize[BOOT_ELEMENT_FW] == 0) { dprintf(DEBUG_CRITICAL,"No firmware region programmed; not creating block device\n"); return false; } bdev = malloc(sizeof(struct blockdev)); if (!bdev) { dprintf(DEBUG_CRITICAL,"Failed to allocate blockdev\n"); return false; } block_size = BOOT_BYTES_PER_SEC * UtilDM->s.secPerPage; size = ROUNDUPTO(UtilDM->s.eSize[BOOT_ELEMENT_FW] * BOOT_BYTES_PER_SEC, block_size); if (construct_blockdev(bdev, "anc_firmware", size, block_size) != 0) { dprintf(DEBUG_CRITICAL,"Failed to construct block device\n"); free(bdev); return false; } bdev->read_block_hook = &anc_read_fw_block; if (register_blockdev(bdev) != 0) { dprintf(DEBUG_CRITICAL,"Failed to register bdev\n"); free(bdev); return false; } // ANC DMA has a minimum 16byte alignment requirement // But if the CPU isn't coherent with ANC, we need to increase the alignment requirement #if WITH_NON_COHERENT_DMA blockdev_set_buffer_alignment(bdev, __max(ANC_MIN_ALIGNMENT, CPU_CACHELINE_SIZE)); #else blockdev_set_buffer_alignment(bdev, ANC_MIN_ALIGNMENT); #endif #if 0 uint32_t *buf; uint32_t i; buf = (uint32_t *)INSECURE_MEMORY_BASE; dprintf(DEBUG_CRITICAL,"Starting test at %p\n", buf); memset(buf, 0, 520192); anc_read_fw_block(NULL, buf, 0, 127); for (i = 0; i < 520192 / 4; i++) { if (buf[i] != i) { panic("Miscompare at 0x%08X got 0x%08X", i, buf[i]); } } dprintf(DEBUG_CRITICAL,"compare passed\n"); anc_read_fw_block(NULL, buf, 126, 1); i = 126 * 1024; uint32_t j; for (j = 0; j < 1024; j++, i++) { if (buf[j] != i) { panic("Miscompare expected 0x%08X got 0x%08X", i, buf[j]); } } #endif #if WITH_LLB_NVRAM // keep trying to find the latest Boot_Find_UtilDM(UtilDM_backup); Boot_Find_Fast(UtilDM_backup); nv_bdev = malloc(sizeof(struct blockdev)); if (!nv_bdev) { dprintf(DEBUG_CRITICAL,"Failed to allocate nvram blockdev\n"); return false; } if (construct_blockdev(nv_bdev, "nvram", 8192, 8192) != 0) { dprintf(DEBUG_CRITICAL,"Failed to construct block device\n"); free(nv_bdev); return false; } nv_bdev->read_block_hook = &anc_read_nvram_block; if (register_blockdev(nv_bdev) != 0) { dprintf(DEBUG_CRITICAL,"Failed to register bdev\n"); free(nv_bdev); return false; } #endif #if WITH_LLB_BLKDEV llb_bdev = malloc(sizeof(struct blockdev)); if (!llb_bdev) { dprintf(DEBUG_CRITICAL,"Failed to allocate LLB blockdev\n"); return false; } block_size = BOOT_BYTES_PER_SEC * UtilDM->s.secPerPage; size = ROUNDUPTO(UtilDM->s.eSize[BOOT_ELEMENT_LLB] * BOOT_BYTES_PER_SEC, block_size); if (construct_blockdev(llb_bdev, "anc_llb", size, block_size) != 0) { dprintf(DEBUG_CRITICAL,"Failed to construct block device\n"); free(llb_bdev); return false; } llb_bdev->read_block_hook = &anc_read_llb_block; // ANC DMA has a minimum 16byte alignment requirement // But if the CPU isn't coherent with ANC, we need to increase the alignment requirement #if WITH_NON_COHERENT_DMA blockdev_set_buffer_alignment(llb_bdev, __max(ANC_MIN_ALIGNMENT, CPU_CACHELINE_SIZE)); #else blockdev_set_buffer_alignment(llb_bdev, ANC_MIN_ALIGNMENT); #endif if (register_blockdev(llb_bdev) != 0) { dprintf(DEBUG_CRITICAL,"Failed to register bdev\n"); free(llb_bdev); return false; } #endif return true; } // LLB loader. Will load UtilDM on first read request which will reset the UtilDM->s.utilMajor to be current. size_t anc_read_llb(void* data, size_t max_size) { uint32_t page; uint32_t size, thisSize; uint32_t secPerPage; bool err; if(0 == UtilDM->s.utilMajor) { err = anc_bootrom_init(false, 0); // do discovery if(err) { return(0); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM; if (!anc_bootrom_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM, &meta[0])) { UtilDM->s.utilMajor = 0; return(false); } dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_LLB; secPerPage = UtilDM->s.secPerPage; page = BOOT_PAGE_LLB; // LLB doesn't start at page=0 size = (uint32_t) max_size / BOOT_BYTES_PER_SEC; dprintf(DEBUG_CRITICAL,"Reading LLB for size=%d\n", size); if(size > UtilDM->s.eSize[BOOT_ELEMENT_LLB]) { size = UtilDM->s.eSize[BOOT_ELEMENT_LLB]; dprintf(DEBUG_CRITICAL,"Trimmed size to written size of %5d\n", size); } max_size = size; // record for result to caller while(size) { if(size > secPerPage) { thisSize = secPerPage; } else { thisSize = size; } if(!anc_bootrom_read_phys_page(BOOT_BAND_LLB, BOOT_DIP_LLB, page, thisSize, data, &meta[0])) { break; } size -= thisSize; page++; data += thisSize * BOOT_BYTES_PER_SEC; } return( (max_size - size) * BOOT_BYTES_PER_SEC ); } // the code below this comment is required for loading the FW element. // clone of UtilDM_Slip from product code uint32_t Boot_Slip(uint32_t pslot) { uint32_t i; i = 0; while(i < UtilDM->s.numDefects && (pslot >= UtilDM->s.defects[i]) ) { pslot++; i++; } return(pslot); } // clone of UtilDM_BandDip // Converts the physical slot to a band,dip that is consistent with Nand engine's usage. returns dip and writes band to bandPtr void Boot_BandDip(uint32_t pslot, uint32_t* bandPtr, uint32_t* dipPtr) { uint32_t bus; uint32_t die; uint32_t plane; uint32_t cau; uint32_t slot_itr; uint32_t band; uint32_t num_bus; uint32_t die_per_bus; uint32_t cau_per_die; if (anc_get_dies_per_channel() * anc_num_channel == UtilDM->s.numDie) { num_bus = anc_num_channel; } else { // geom_num_bus is incorrect because a bus didn't come up. num_bus = UtilDM->s.numDie / anc_get_dies_per_channel(); } die_per_bus = UtilDM->s.numDie / anc_num_channel; cau_per_die = UtilDM->s.numPlanes; bus = 0; die = 0; plane = 0; band = 0; for (slot_itr = 0; slot_itr < pslot; slot_itr++) { bus++; if(bus >= num_bus) { bus = 0; die++; if (die >= die_per_bus){ die = 0; plane++; if (plane >= cau_per_die) { plane=0; band++; } } } } cau = (die * cau_per_die) + plane; *bandPtr = band; *dipPtr = anc_get_dip(bus, cau); } // leveraged core UtilDM_PostProcess bool Boot_PostProcessDM(UtilDM_t *p, uint32_t page, uint32_t slot, uint32_t *meta) { uint32_t wasGrownDef; uint32_t newV; uint32_t currV; bool result = false; if (meta[0] == BOOT_ERR_BLANK) { dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] BLANK! \n", slot, page); } else if (p->s.utilMajor != BOOT_UTIL_MAJOR) { dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] !!!!! Found UtilDM with different major version =0x%08x ", slot, page, p->s.utilMajor); return false; } else if (p->s.utilMinor < Util.minorVersion) { dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] !!!!! Found UtilDM with major version 0x%08x but minor version 0x%08x (less than minimum 0x%08x)", slot, page, p->s.utilMajor, p->s.utilMinor, Util.minorVersion); return false; } else { newV = p->version; currV = UtilDM->version; if (newV >= currV) { Util.prevUtilDMversion = currV; Util.prevUtilDMslot = Util.location[BOOT_ELEMENT_UTILDM].slot; Util.location[BOOT_ELEMENT_UTILDM].slot = slot; Util.location[BOOT_ELEMENT_UTILDM].page = page; dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Adopting version=0x%08x numDefects=%2d numSlots=%2d\n", slot, page, newV, p->s.numDefects, p->s.numSlots); wasGrownDef = UtilDM->s.numDefects; memcpy(UtilDM, p, sizeof(UtilDM_t)); if (wasGrownDef != UtilDM->s.numDefects) { result = true; } if (slot == BOOT_SLOT_FAST_B) { Util.BCopyPresent = true; } else { Util.BCopyPresent = false; // Always expect a B copy on the right of A } } else if (!Util.BCopyPresent && (slot == BOOT_SLOT_FAST_B) && ((currV == (newV + 1)))) { // This is the case where we have a newer copy on the left of the older copy // accept B copy if it's version is 1 less than A copy, consider B slot, the previous slot Util.prevUtilDMversion = newV; Util.prevUtilDMslot = slot; dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Adopting B copy version=0x%08x numDefects=%2d numSlots=%2d", slot, page, newV, p->s.numDefects, p->s.numSlots); Util.BCopyPresent = true; } else { dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Ignoring version=0x%08x numDefects=%2d numSlots=%2d", slot, page, newV, p->s.numDefects, p->s.numSlots); } } return result; } static int anc_read_fw_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) { uint32_t slot; uint32_t slotB; // offset for the B copy of FW. 0 indicates not doing retry uint32_t pslot; uint32_t page; uint32_t band; uint32_t dip; uint32_t thisSize; uint32_t secPerPage; uint32_t pagePerSlot; uint32_t err; uint32_t max_size; // Incoming sectors are in terms of page size (to prevent the client from // attempting a sub-page read). sectors *= UtilDM->s.secPerPage; offset *= UtilDM->s.secPerPage; dprintf(DEBUG_INFO,"Reading sectors from FW element from offset=%4d for a size=%4d\n", offset, sectors);; if(BOOT_UTIL_MAJOR != UtilDM->s.utilMajor) { dprintf(DEBUG_CRITICAL,"Exiting anc_read_fw because UtilDM->s.utilMajor is incorrect\n"); return(0); } if(offset > UtilDM->s.eSize[BOOT_ELEMENT_FW]) { dprintf(DEBUG_CRITICAL,"Requested offset exceeds size of firmware\n"); return(0); } if(sectors + offset > UtilDM->s.eSize[BOOT_ELEMENT_FW]) { dprintf(DEBUG_CRITICAL,"Attempt to read past end of firmware\n"); return(0); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_FW; secPerPage = UtilDM->s.secPerPage; pagePerSlot = UtilDM->s.numPages; page = BOOT_PAGE_FW; // starting location for FW in [slot,page] slot = BOOT_SLOT_FW; while(offset >= secPerPage) { offset -= secPerPage; page++; if(page >= pagePerSlot) { page = 0; slot++; } } // lba now converted to page/slot err = 0; slotB = 0; max_size = sectors; // save for result while(sectors) { pslot = Boot_Slip(slot+slotB); Boot_BandDip(pslot, &band, &dip); thisSize = sectors; if(thisSize > secPerPage) { thisSize = secPerPage; } if (anc_llb_read_phys_page(band, dip, page, thisSize, data, &meta[0])!=secPerPage) { dprintf(DEBUG_CRITICAL,"Failed to read page\n"); if(!slotB) { slotB = UtilDM->s.sizeFWslots; } else { break; } } else { slotB = 0; sectors -= thisSize; data += thisSize * BOOT_BYTES_PER_SEC; page++; if(page >= pagePerSlot) { page = 0; slot++; } } } if(err) { dprintf(DEBUG_CRITICAL,"Encountered error = %d\n", err); } return (max_size - sectors) / secPerPage; } #if WITH_LLB_BLKDEV // LLB loader. Will load UtilDM on first read request which will reset the UtilDM->s.utilMajor to be current. static int anc_read_llb_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) { uint32_t page; uint32_t size, thisSize, max_size, secRead; uint32_t secPerPage; bool err; if(0 == UtilDM->s.utilMajor) { err = anc_bootrom_init(false, 0); // do discovery if(err) { return(0); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM; if (anc_llb_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM, &meta[0])!=BOOT_SIZE_UTILDM) { UtilDM->s.utilMajor = 0; return(false); } dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_LLB; secPerPage = UtilDM->s.secPerPage; page = BOOT_PAGE_LLB + offset; size = sectors * secPerPage; dprintf(DEBUG_SPEW,"Reading LLB for size=%d, page=%u\n", sectors, (unsigned int)page); if(size > UtilDM->s.eSize[BOOT_ELEMENT_LLB]) { size = UtilDM->s.eSize[BOOT_ELEMENT_LLB]; dprintf(DEBUG_CRITICAL,"Trimmed size to written size of %5d\n", size); } max_size = size; // record for result to caller while(size) { if(size > secPerPage) { thisSize = secPerPage; } else { thisSize = size; } secRead = anc_llb_read_phys_page(BOOT_BAND_LLB, BOOT_DIP_LLB, page, thisSize, data, &meta[0]); if ((secRead == 0) || (secReadsecPerPage)) { // only allow partial NAND page at the end of read break; } size -= thisSize; page++; data += thisSize * BOOT_BYTES_PER_SEC; } return( (max_size - size) / secPerPage ); } #endif #if WITH_LLB_NVRAM static int anc_read_nvram_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) { uint32_t slot; uint32_t slotB; // offset for the B copy of FW. 0 indicates not doing retry uint32_t pslot; uint32_t page; uint32_t band; uint32_t dip; uint32_t thisSize; uint32_t secPerPage; uint32_t pagePerSlot; uint32_t err; uint32_t max_size; // Incoming sectors are in terms of page size (to prevent the client from // attempting a sub-page read). sectors *= 2; // blocksize is 8k not 4k dprintf(DEBUG_INFO,"Reading sectors from NVRAM element from offset=%4d for a size=%4d\n", offset, sectors); if(BOOT_UTIL_MAJOR != UtilDM->s.utilMajor) { dprintf(DEBUG_CRITICAL,"Exiting anc_read_fw because UtilDM->s.utilMajor is incorrect\n"); return(0); } if(offset > 0) { dprintf(DEBUG_CRITICAL,"Requested offset exceeds size of nvram\n"); return(0); } if(sectors + offset > UtilDM->s.eSize[BOOT_ELEMENT_NVRAM]) { dprintf(DEBUG_CRITICAL,"Attempt to read past end of nvram\n"); return(0); } meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_NVRAM; secPerPage = UtilDM->s.secPerPage; pagePerSlot = UtilDM->s.numPages; page = Util.location[BOOT_ELEMENT_NVRAM].page; // starting location for NVRAM in [slot,page] slot = Util.location[BOOT_ELEMENT_NVRAM].slot; err = 0; slotB = 0; max_size = sectors; // save for result if (page==0 && slot==0) {// NVRAM not populated sectors=0; } while(sectors) { pslot = Boot_Slip(slot+slotB); Boot_BandDip(pslot, &band, &dip); thisSize = sectors; if(thisSize > secPerPage) { thisSize = secPerPage; } if(!anc_llb_read_phys_page(band, dip, page, thisSize, data, &meta[0])) { dprintf(DEBUG_CRITICAL,"Failed to read page\n"); if(!slotB) { slotB = 1; } else { break; } } else { slotB = 0; sectors -= thisSize; data += thisSize * BOOT_BYTES_PER_SEC; page++; if(page >= pagePerSlot) { page=0; slot++; if (sectors) { // still more to read? err=1; break; } } } } if(err) { dprintf(DEBUG_CRITICAL,"Encountered error = %d\n", err); } return (max_size - sectors) / 2; } uint32_t Boot_Find_Fast_Scan(void *buffer, uint32_t page, uint32_t slot) { uint32_t element; uint32_t ElementSizePages; if (0 == page) { UtilDM->version = 1; } for (; page < UtilDM->s.numPages;) { meta[0] = BOOT_LBA_TOKEN_UNKNOWN; if (Boot_Read(buffer,page,slot,meta)) { if ((meta[0] >= BOOT_LBA_TOKEN_FAST_FIRST) && (meta[0] <= BOOT_LBA_TOKEN_FAST_LAST)) { element = meta[0] - BOOT_LBA_TOKEN_ELEMENTS; dprintf(DEBUG_INFO,"UTIL_MINOR - [%2d,%2d] Found %d\n", slot, page, element); if (0 == UtilDM->s.eSize[element]) { dprintf(DEBUG_CRITICAL,"UTIL - Element of unknown size!!! \n"); page++; } else { if (element == BOOT_ELEMENT_UTILDM) { Boot_PostProcessDM(buffer,page,slot,meta); } else { Util.location[element].slot = slot; Util.location[element].page = page; dprintf(DEBUG_INFO,"UTIL_MINOR - Found location [%2d,%2d] for element %d\n", Util.location[element].slot, Util.location[element].page,element); } page += quantup(UtilDM->s.eSize[element], UtilDM->s.secPerPage); } } else if (!((meta[0] >= BOOT_LBA_TOKEN_FAST_FIRST) && (meta[0] <= BOOT_LBA_TOKEN_FAST_LAST)) && (meta[0] < BOOT_LBA_TOKEN_UNKNOWN)) { element = meta[0] - BOOT_LBA_TOKEN_ELEMENTS; ElementSizePages = 0; if (element < UTIL_NUM_ELEMENT) { ElementSizePages = quantup(UtilDM->s.eSize[element], UtilDM->s.secPerPage); } if ((ElementSizePages == 0) || ((page + ElementSizePages) > UtilDM->s.numPages)) { dprintf(DEBUG_CRITICAL,"UTIL - [%2d,%2d] Something Broken, UtilDM->s.eSize[%d]=%d!!\n", slot, page, element, ElementSizePages); page = 0; break; } else { dprintf(DEBUG_CRITICAL,"Skipping unknown element %d\n", element); } page += ElementSizePages; } } else { if ( BOOT_ERR_BLANK != meta[0]) { // something ugly ?, either unknown LBA value or unc dprintf(DEBUG_CRITICAL,"UTIL - [%2d,%2d] Something Broken !! meta=%x\n", slot, page, meta[0]); page = 0; } else { dprintf(DEBUG_INFO,"UTIL_MINOR - [%2d,%2d] Blank !!\n", slot, page); } break; } } return page; } // passed in a single sector seg with buffer allocated void Boot_Find_Fast(void *buffer) { uint32_t page; uint32_t slot, tmpslot; uint32_t element; tmpslot = slot = Util.location[BOOT_ELEMENT_UTILDM].slot;// slot with the highest version UtilDM if ((BOOT_SLOT_FAST_B == slot) && (BOOT_SLOT_FAST_A == Util.prevUtilDMslot) && (Util.prevUtilDMversion == UtilDM->version)) { // NORMAL state slot = BOOT_SLOT_FAST_A; page = Boot_Find_Fast_Scan(buffer, 1, slot); if (page) { slot = BOOT_SLOT_FAST_B; // read copy B meta[0] = BOOT_LBA_TOKEN_UNKNOWN; if (!Boot_Read(buffer,page-1,slot,meta)) { dprintf(DEBUG_INFO,"UTIL - Fast Copy B last page broken!\n"); page = 0; } else if (page < UtilDM->s.numPages) { // last written page of B is ok, check next page is blank slot = BOOT_SLOT_FAST_B; meta[0] = BOOT_LBA_TOKEN_UNKNOWN; if (!Boot_Read(buffer,page,slot,meta) && meta[0]!=BOOT_ERR_BLANK) { dprintf(DEBUG_CRITICAL,"UTIL - Fast Copy B next location not Blank!!\n"); page = 0; } } } } else { // spew enough data to know why we failed the IF term. dprintf(DEBUG_CRITICAL,"UTIL - FastA:%2d slot:%2d prevSlot:%2d prevV:%08x currV:%08x\n", BOOT_SLOT_FAST_A, slot, Util.prevUtilDMslot, Util.prevUtilDMversion, UtilDM->version); if ((BOOT_SLOT_LLB != Util.prevUtilDMslot) && !(!Util.BCopyPresent && (BOOT_SLOT_FAST_B == Util.prevUtilDMslot))) { /*Scan the older copy first*/ slot = Util.prevUtilDMslot; Boot_Find_Fast_Scan(buffer, 0, slot); } slot = tmpslot; Boot_Find_Fast_Scan(buffer, 0, slot); page = 0; } for (element = BOOT_ELEMENT_FAST_FIRST; element <= BOOT_ELEMENT_FAST_LAST; element++) { dprintf(DEBUG_INFO,"UTIL - Location [%2d,%2d] for element %d\n", Util.location[element].slot, Util.location[element].page, element); } } bool Boot_Read(void *buffer, uint32_t page, uint32_t slot, uint32_t *meta) { uint32_t band, dip; uint32_t pslot = Boot_Slip(slot);//+slotB); Boot_BandDip(pslot, &band, &dip); return (anc_llb_read_phys_page(band, dip, page, 1, buffer, &meta[0])); } void Boot_Find_UtilDM(void *buffer) { uint32_t firstSlot = Util.location[BOOT_ELEMENT_UTILDM].slot; uint32_t slot, page; UtilDM->s.numSlots = 32; //UTIL_BLIND_SEARCH; page=0; for (slot = BOOT_SLOT_FAST_A; slot < UtilDM->s.numSlots;) { if (slot == UtilDM->pendDefect) { slot++; continue; } meta[0]=BOOT_LBA_TOKEN_UNKNOWN; Boot_Read(buffer,page,slot,meta); if (Boot_PostProcessDM(buffer,page,slot,meta)) { dprintf(DEBUG_INFO,"UTIL - defect growth\n"); // don't assume that we're aligned. slot = BOOT_SLOT_FAST_A; // start over Util.location[BOOT_ELEMENT_UTILDM].slot = firstSlot; // and assimlate again. } else { slot++; } } if (0 == UtilDM->version) { // found nothing? dprintf(DEBUG_CRITICAL,"UTIL - Found no UtilDM!!! Nand should be blank\n"); UtilDM->s.numSlots = 0; // then reset numSlots UtilDM->s.numDefects = 0; } } #endif