Example #1
0
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;
}
Example #2
0
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);
    }
}
Example #3
0
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();
}
Example #4
0
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;
}
Example #5
0
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;
}