flash.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,397 行 · 第 1/4 页

C
1,397
字号
#endif        footer_p->infoBase = NULL;        footer_p->signature = FLASH_FOOTER_SIGNATURE;        footer_p->type = TYPE_REDHAT_REDBOOT;        // and compute its checksum        for ( ; count > 0; count--) {            if (*check_ptr > ~check)                check++;            check += *check_ptr++;        }        footer_p->checksum = ~check;    }#endif    // Do this after creating the initialized table because that inherently    // calculates where the high water mark of default RedBoot images is.    if (full_init) {        unsigned long erase_size;        CYG_ADDRESS erase_start;        // Erase everything except default RedBoot images, fis block,         // and config block.        // First deal with the possible first part, before RedBoot images:#if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)        erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;        erase_size =  (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;        if ( erase_size > erase_start ) {            erase_size -= erase_start;            if ((stat = flash_erase((void *)erase_start, erase_size,                                    (void **)&err_addr)) != 0) {                diag_printf("   initialization failed at %p: %s\n",                            err_addr, flash_errmsg(stat));            }        }#endif        // second deal with the larger part in the main:        erase_start = redboot_flash_start; // high water of created images        // Now the empty bits between the end of Redboot and the cfg and dir         // blocks. #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \    defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \    !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)        if (fis_addr > cfg_base) {          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data        } else {          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data        }        if ((stat = flash_erase((void *)erase_start, erase_size,                                (void **)&err_addr)) != 0) {          diag_printf("   initialization failed %p: %s\n",                 err_addr, flash_errmsg(stat));        }        erase_start += (erase_size + flash_block_size);        if (fis_addr > cfg_base) {          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data        } else {          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data        }        if ((stat = flash_erase((void *)erase_start, erase_size,                                (void **)&err_addr)) != 0) {          diag_printf("   initialization failed %p: %s\n",                 err_addr, flash_errmsg(stat));        }        erase_start += (erase_size + flash_block_size);#else  // !CYGSEM_REDBOOT_FLASH_CONFIG                erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data        if ((stat = flash_erase((void *)erase_start, erase_size,                                (void **)&err_addr)) != 0) {          diag_printf("   initialization failed %p: %s\n",                 err_addr, flash_errmsg(stat));        }        erase_start += (erase_size + flash_block_size);          #endif        // Lastly, anything at the end        erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;        if ((stat = flash_erase((void *)erase_start, erase_size,                                (void **)&err_addr)) != 0) {            diag_printf("   initialization failed at %p: %s\n",                        err_addr, flash_errmsg(stat));        }#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS    // In this case, 'fis free' works by scanning for erased blocks.  Since the    // "-f" option was not supplied, there may be areas which are not used but    // don't appear to be free since they are not erased - thus the warning    } else {        diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");#endif    }    fis_update_directory();}static voidfis_list(int argc, char *argv[]){    struct fis_image_desc *img;    int i, image_indx;    bool show_cksums = false;    bool show_datalen = false;    struct option_info opts[2];    void *err_addr;    unsigned long last_addr, lowest_addr;    bool image_found;#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB    // FIXME: this is somewhat half-baked    extern void arm_fis_list(void);    arm_fis_list();    return;#endif    init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG,               (void *)&show_datalen, (bool *)0, "display data length");#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK    init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,               (void *)&show_cksums, (bool *)0, "display checksums");    i = 2;#else    i = 1;#endif    if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {        return;    }    flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);    // Let diag_printf do the formatting in both cases, rather than counting    // cols by hand....    diag_printf("%-16s  %-10s  %-10s  %-10s  %-s\n",                "Name","FLASH addr",                show_cksums ? "Checksum" : "Mem addr",                show_datalen ? "Datalen" : "Length",                "Entry point" );    last_addr = 0;    image_indx = 0;    do {        image_found = false;        lowest_addr = 0xFFFFFFFF;        img = (struct fis_image_desc *) fis_work_block;        for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {            if (img->name[0] != (unsigned char)0xFF) {                if ((img->flash_base > last_addr) && (img->flash_base < lowest_addr)) {                    lowest_addr = img->flash_base;                    image_found = true;                    image_indx = i;                }            }        }        if (image_found) {            img = (struct fis_image_desc *) fis_work_block;            img += image_indx;            diag_printf("%-16s  0x%08lX  0x%08lX  0x%08lX  0x%08lX\n", img->name,                         img->flash_base, #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK                        show_cksums ? img->file_cksum : img->mem_base,                         show_datalen ? img->data_length : img->size, #else                        img->mem_base,                         img->size, #endif                        img->entry_point);        }        last_addr = lowest_addr;    } while (image_found == true);}#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKSstruct free_chunk {    CYG_ADDRESS start, end;};static intfind_free(struct free_chunk *chunks){    CYG_ADDRESS *fis_ptr, *fis_end;    void *err_addr;    struct fis_image_desc *img;    int i, idx;    int num_chunks = 1;    // Do not search the area reserved for pre-RedBoot systems:    fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +                               CYGNUM_REDBOOT_FLASH_RESERVED_BASE +                               CYGBLD_REDBOOT_MIN_IMAGE_SIZE);    fis_end = (CYG_ADDRESS *)flash_end;    chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr;    chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end;    flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);    img = (struct fis_image_desc *) fis_work_block;    for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {        if (img->name[0] != (unsigned char)0xFF) {            // Figure out which chunk this is in and split it            for (idx = 0;  idx < num_chunks;  idx++) {                if ((img->flash_base >= chunks[idx].start) &&                     (img->flash_base <= chunks[idx].end)) {                    if (img->flash_base == chunks[idx].start) {                        chunks[idx].start += img->size;                        if (chunks[idx].start >= chunks[idx].end) {                            // This free chunk has collapsed                            while (idx < (num_chunks-1)) {                                chunks[idx] = chunks[idx+1];                            }                            num_chunks--;                        }                    } else if ((img->flash_base+img->size) == chunks[idx].end) {                        chunks[idx].end = img->flash_base;                    } else {                        // Split chunk into two parts                        if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {                            chunks[idx+1].start = img->flash_base + img->size;                            chunks[idx+1].end = chunks[idx].end;                            if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {                                diag_printf("Warning: too many free chunks\n");                                return num_chunks;                            }                        }                        chunks[idx].end = img->flash_base;                    }                    break;                }            }        }    }    return num_chunks;}#endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKSstatic voidfis_free(int argc, char *argv[]){#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS    unsigned long *fis_ptr, *fis_end, flash_data;    unsigned long *area_start;    void *err_addr;    // Do not search the area reserved for pre-RedBoot systems:    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE +                                 CYGBLD_REDBOOT_MIN_IMAGE_SIZE);    fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;    area_start = fis_ptr;    while (fis_ptr < fis_end) {        flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);        if (flash_data != (unsigned long)0xFFFFFFFF) {            if (area_start != fis_ptr) {                // Assume that this is something                diag_printf("  0x%08lX .. 0x%08lX\n",                            (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);            }            // Find next blank block            area_start = fis_ptr;            while (area_start < fis_end) {                flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);                if (flash_data == (unsigned long)0xFFFFFFFF) {                    break;                }                area_start += flash_block_size / sizeof(CYG_ADDRESS);            }            fis_ptr = area_start;        } else {            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);        }    }    if (area_start != fis_ptr) {        diag_printf("  0x%08lX .. 0x%08lX\n",                     (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);    }#else    struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];    int idx, num_chunks;    num_chunks = find_free(chunks);    for (idx = 0;  idx < num_chunks;  idx++) {        diag_printf("  0x%08lX .. 0x%08lX\n", chunks[idx].start, chunks[idx].end);    }#endif}// Find the first unused area of flash which is long enoughstatic boolfis_find_free(CYG_ADDRESS *addr, unsigned long length){#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS    unsigned long *fis_ptr, *fis_end, flash_data;    unsigned long *area_start;    void *err_addr;    // Do not search the area reserved for pre-RedBoot systems:    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE +                                 CYGBLD_REDBOOT_MIN_IMAGE_SIZE);    fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;    area_start = fis_ptr;    while (fis_ptr < fis_end) {        flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);        if (flash_data != (unsigned long)0xFFFFFFFF) {            if (area_start != fis_ptr) {                // Assume that this is something                if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {                    *addr = (CYG_ADDRESS)area_start;                    return true;                }            }            // Find next blank block            area_start = fis_ptr;            while (area_start < fis_end) {                flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);                if (flash_data == (unsigned long)0xFFFFFFFF) {                    break;                }                area_start += flash_block_size / sizeof(CYG_ADDRESS);            }            fis_ptr = area_start;        } else {            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);        }    }    if (area_start != fis_ptr) {        if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {            *addr = (CYG_ADDRESS)area_start;            return true;        }    }    return false;#else    struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];    int idx, num_chunks;    num_chunks = find_free(chunks);    for (idx = 0;  idx < num_chunks;  idx++) {        if ((chunks[idx].end - chunks[idx].start) >= length) {            *addr = (CYG_ADDRESS)chunks[idx].start;            return true;        }    }    return false;#endif}static voidfis_create(int argc, char *argv[]){    int i, stat;    unsigned long length, img_size;    CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;    char *name;    bool mem_addr_set = false;    bool exec_addr_set = false;    bool entry_addr_set = false;    bool flash_addr_set = false;    bool length_set = false;    bool img_size_set = false;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?