int hal_flash_program(void *addr, void *data, int len, void **err) { int swabbed = 0; cyg_uint32 *p; int i, retval; if (is_swabbed_redboot(addr, data) #if (CYG_BYTEORDER == CYG_LSBFIRST) && defined(CYGOPT_REDBOOT_FLASH_BYTEORDER_MSBFIRST) #ifdef CYGOPT_REDBOOT_FIS || addr == fis_addr #endif #ifdef CYGSEM_REDBOOT_FLASH_CONFIG || addr == cfg_base #endif #endif ) { swabbed = 1; for (i = 0, p = data; i < len; i += 4, ++p) *p = CYG_SWAP32(*p); } retval = flash_program(addr, data, len, err); if (swabbed) { for (i = 0, p = data; i < len; i += 4, ++p) *p = CYG_SWAP32(*p); } return retval; }
// Try to figure out if RedBoot is re-flashing a RedBoot with // a different endianess. This is obviously not foolproof, but // should be good enough. static inline int is_swabbed_redboot(void *faddr, cyg_uint32 *p) { if (faddr == (void *)0x50000000 && (CYG_SWAP32(p[1]) == 0xe59ff018) && (CYG_SWAP32(p[2]) == 0xe59ff018) && (CYG_SWAP32(p[3]) == 0xe59ff018) && (CYG_SWAP32(p[4]) == 0xe59ff018) && (p[5] == 0)) return 1; return 0; }
// // Little endian mode requires some trickery due to the way the IXP4xx // AHB and expansion busses work. // int hal_flash_read(void *addr, void *data, int len, void **err) { int retval; retval = flash_read(addr, data, len, err); if (0 #if (CYG_BYTEORDER == CYG_LSBFIRST) && defined(CYGOPT_REDBOOT_FLASH_BYTEORDER_MSBFIRST) #ifdef CYGOPT_REDBOOT_FIS || addr == fis_addr #endif #ifdef CYGSEM_REDBOOT_FLASH_CONFIG || addr == cfg_base #endif #endif ) { cyg_uint32 *p; int i; for (i = 0, p = data; i < len; i += 4, ++p) *p = CYG_SWAP32(*p); } return retval; }
// Change endianness of config data void conf_endian_fixup(void *ptr) { #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER struct _config *p = (struct _config *)ptr; unsigned char *dp = p->config_data; void *val_ptr; int len; cyg_uint16 u16; cyg_uint32 u32; p->len = CYG_SWAP32(p->len); p->key1 = CYG_SWAP32(p->key1); p->key2 = CYG_SWAP32(p->key2); p->cksum = CYG_SWAP32(p->cksum); while (dp < &p->config_data[sizeof(config->config_data)]) { len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + config_length(CONFIG_OBJECT_TYPE(dp)); val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); switch (CONFIG_OBJECT_TYPE(dp)) { // Note: the data may be unaligned in the configuration data case CONFIG_BOOL: if (sizeof(bool) == 2) { memcpy(&u16, val_ptr, 2); u16 = CYG_SWAP16(u16); memcpy(val_ptr, &u16, 2); } else if (sizeof(bool) == 4) { memcpy(&u32, val_ptr, 4); u32 = CYG_SWAP32(u32); memcpy(val_ptr, &u32, 4); } break; case CONFIG_INT: if (sizeof(unsigned long) == 2) { memcpy(&u16, val_ptr, 2); u16 = CYG_SWAP16(u16); memcpy(val_ptr, &u16, 2); } else if (sizeof(unsigned long) == 4) { memcpy(&u32, val_ptr, 4); u32 = CYG_SWAP32(u32); memcpy(val_ptr, &u32, 4); } break; } dp += len; } #endif }
// fis_endian_fixup() is used to swap endianess if required. // static inline void fis_endian_fixup(void *addr) { #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER struct fis_image_desc *p = addr; int cnt = fisdir_size / sizeof(struct fis_image_desc); while (cnt-- > 0) { p->flash_base = CYG_SWAP32(p->flash_base); p->mem_base = CYG_SWAP32(p->mem_base); p->size = CYG_SWAP32(p->size); p->entry_point = CYG_SWAP32(p->entry_point); p->data_length = CYG_SWAP32(p->data_length); p->desc_cksum = CYG_SWAP32(p->desc_cksum); p->file_cksum = CYG_SWAP32(p->file_cksum); p++; } #endif }
static void do_swab(int argc, char *argv[]) { // Fill a region of memory with a pattern struct option_info opts[4]; unsigned long base; long len; bool base_set, len_set; bool set_32bit, set_16bit; init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&base, (bool *)&base_set, "base address"); init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, (void *)&len, (bool *)&len_set, "length"); init_opts(&opts[2], '4', false, OPTION_ARG_TYPE_FLG, (void *)&set_32bit, (bool *)0, "fill 32 bit units"); init_opts(&opts[3], '2', false, OPTION_ARG_TYPE_FLG, (void *)&set_16bit, (bool *)0, "fill 16 bit units"); if (!scan_opts(argc, argv, 1, opts, 4, 0, 0, "")) { return; } if (!base_set || !len_set) { diag_printf("usage: swab -b <addr> -l <length> [-2|-4]\n"); return; } if (set_16bit) { // 16 bits at a time while ((len -= sizeof(cyg_uint16)) >= 0) { *(cyg_uint16 *)base = CYG_SWAP16(*(cyg_uint16 *)base); base += sizeof(cyg_uint16); } } else { // Default - 32 bits while ((len -= sizeof(cyg_uint32)) >= 0) { *(cyg_uint32 *)base = CYG_SWAP32(*(cyg_uint32 *)base); base += sizeof(cyg_uint32); } } }