static int flash_nvram_write(uint32_t dst, void *src, uint32_t len) { int rc; if (!try_lock(&flash_lock)) return OPAL_BUSY; if (nvram_flash->busy) { rc = OPAL_BUSY; goto out; } /* TODO: When we have async jobs for PRD, turn this into one */ if ((dst + len) > nvram_size) { prerror("FLASH_NVRAM: write out of bound (0x%x,0x%x)\n", dst, len); rc = OPAL_PARAMETER; goto out; } nvram_flash->busy = true; unlock(&flash_lock); rc = blocklevel_write(nvram_flash->bl, nvram_offset + dst, src, len); lock(&flash_lock); nvram_flash->busy = false; out: unlock(&flash_lock); return rc; }
static void program_file(const char *file, uint32_t start, uint32_t size) { int fd, rc; ssize_t len; uint32_t actual_size = 0; fd = open(file, O_RDONLY); if (fd == -1) { perror("Failed to open file"); exit(1); } printf("About to program \"%s\" at 0x%08x..0x%08x !\n", file, start, start + size); check_confirm(); if (dummy_run) { printf("skipped (dummy)\n"); close(fd); return; } printf("Programming & Verifying...\n"); progress_init(size >> 8); while(size) { len = read(fd, file_buf, FILE_BUF_SIZE); if (len < 0) { perror("Error reading file"); exit(1); } if (len == 0) break; if (len > size) len = size; size -= len; actual_size += len; rc = blocklevel_write(bl, start, file_buf, len); if (rc) { if (rc == FLASH_ERR_VERIFY_FAILURE) fprintf(stderr, "Verification failed for" " chunk at 0x%08x\n", start); else fprintf(stderr, "Flash write error %d for" " chunk at 0x%08x\n", rc, start); exit(1); } start += len; progress_tick(actual_size >> 8); } progress_end(); close(fd); /* If this is a flash partition, adjust its size */ if (ffsh && ffs_index >= 0) { printf("Updating actual size in partition header...\n"); ffs_update_act_size(ffsh, ffs_index, actual_size); } }
static void set_ecc(uint32_t start, uint32_t size) { uint32_t i = start + 8; uint8_t ecc = 0; printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size); check_confirm(); erase_range(start, size, true); printf("Programming ECC bits...\n"); progress_init(size); while (i < start + size) { blocklevel_write(bl, i, &ecc, sizeof(ecc)); i += 9; progress_tick(i - start); } progress_end(); }
int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len) { uint32_t erase_size; const void *write_buf = buf; void *write_buf_start = NULL; uint64_t ecc_start; void *erase_buf; int rc = 0; if (!write_buf || !bl) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } FL_DBG("%s: 0x%" PRIx64 "\t0x%" PRIx64 "\n", __func__, pos, len); if (!(bl->flags & WRITE_NEED_ERASE)) { FL_DBG("%s: backend doesn't need erase\n", __func__); return blocklevel_write(bl, pos, buf, len); } rc = blocklevel_get_info(bl, NULL, NULL, &erase_size); if (rc) return rc; if (ecc_protected(bl, pos, len, &ecc_start)) { FL_DBG("%s: region has ECC\n", __func__); len = ecc_buffer_size(len); write_buf_start = malloc(len); if (!write_buf_start) { errno = ENOMEM; return FLASH_ERR_MALLOC_FAILED; } if (memcpy_to_ecc(write_buf_start, buf, ecc_buffer_size_minus_ecc(len))) { free(write_buf_start); errno = EBADF; return FLASH_ERR_ECC_INVALID; } write_buf = write_buf_start; } erase_buf = malloc(erase_size); if (!erase_buf) { errno = ENOMEM; rc = FLASH_ERR_MALLOC_FAILED; goto out_free; } rc = reacquire(bl); if (rc) goto out_free; while (len > 0) { uint32_t erase_block = pos & ~(erase_size - 1); uint32_t block_offset = pos & (erase_size - 1); uint32_t size = erase_size > len ? len : erase_size; int cmp; /* Write crosses an erase boundary, shrink the write to the boundary */ if (erase_size < block_offset + size) { size = erase_size - block_offset; } rc = bl->read(bl, erase_block, erase_buf, erase_size); if (rc) goto out; cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size); FL_DBG("%s: region 0x%08x..0x%08x ", __func__, erase_block, erase_size); if (cmp != 0) { FL_DBG("needs "); if (cmp == -1) { FL_DBG("erase and "); bl->erase(bl, erase_block, erase_size); } FL_DBG("write\n"); memcpy(erase_buf + block_offset, write_buf, size); rc = bl->write(bl, erase_block, erase_buf, erase_size); if (rc) goto out; } len -= size; pos += size; write_buf += size; } out: release(bl); out_free: free(write_buf_start); free(erase_buf); return rc; }
int blocklevel_smart_write(struct blocklevel_device *bl, uint32_t pos, const void *buf, uint32_t len) { uint32_t erase_size; const void *write_buf = buf; void *write_buf_start = NULL; void *erase_buf; int rc = 0; if (!write_buf || !bl) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } if (!(bl->flags & WRITE_NEED_ERASE)) return blocklevel_write(bl, pos, buf, len); rc = blocklevel_get_info(bl, NULL, NULL, &erase_size); if (rc) return rc; if (ecc_protected(bl, pos, len)) { len = ecc_buffer_size(len); write_buf_start = malloc(len); if (!write_buf_start) { errno = ENOMEM; return FLASH_ERR_MALLOC_FAILED; } if (memcpy_to_ecc(write_buf_start, buf, ecc_buffer_size_minus_ecc(len))) { free(write_buf_start); errno = EBADF; return FLASH_ERR_ECC_INVALID; } write_buf = write_buf_start; } erase_buf = malloc(erase_size); if (!erase_buf) { errno = ENOMEM; rc = FLASH_ERR_MALLOC_FAILED; goto out; } while (len > 0) { uint32_t erase_block = pos & ~(erase_size - 1); uint32_t block_offset = pos & (erase_size - 1); uint32_t size = erase_size > len ? len : erase_size; int cmp; /* Write crosses an erase boundary, shrink the write to the boundary */ if (erase_size < block_offset + size) { size = erase_size - block_offset; } rc = bl->read(bl, erase_block, erase_buf, erase_size); if (rc) goto out; cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size); if (cmp != 0) { if (cmp == -1) bl->erase(bl, erase_block, erase_size); memcpy(erase_buf + block_offset, write_buf, size); rc = bl->write(bl, erase_block, erase_buf, erase_size); if (rc) goto out; } len -= size; pos += size; write_buf += size; } out: free(write_buf_start); free(erase_buf); return rc; }