Пример #1
0
int blocklevel_write(struct blocklevel_device *bl, uint32_t pos, const void *buf, uint32_t len)
{
	int rc;
	struct ecc64 *buffer;
	uint32_t ecc_len = ecc_buffer_size(len);

	if (!bl || !bl->write || !buf) {
		errno = EINVAL;
		return FLASH_ERR_PARM_ERROR;
	}

	if (!ecc_protected(bl, pos, len)) {
		return bl->write(bl, pos, buf, len);
	}

	buffer = malloc(ecc_len);
	if (!buffer) {
		errno = ENOMEM;
		return FLASH_ERR_MALLOC_FAILED;
	}

	if (memcpy_to_ecc(buffer, buf, len)) {
		errno = EBADF;
		rc = FLASH_ERR_ECC_INVALID;
		goto out;
	}
	rc = bl->write(bl, pos, buffer, ecc_len);
out:
	free(buffer);
	return rc;
}
Пример #2
0
int flash_smart_write_corrected(struct blocklevel_device *bl, uint32_t dst, const void *src,
		      uint32_t size, bool ecc)
{
	struct ecc64 *buf;
	int rc;

	if (!ecc)
		return flash_smart_write(bl, dst, src, size);

	buf = malloc(ecc_buffer_size(size));
	if (!buf)
		return FLASH_ERR_MALLOC_FAILED;

	rc = memcpy_to_ecc(buf, src, size);
	if (rc) {
		rc = FLASH_ERR_ECC_INVALID;
		goto out;
	}

	rc = flash_smart_write(bl, dst, buf, ecc_buffer_size(size));

out:
	free(buf);
	return rc;
}
Пример #3
0
int flash_write_corrected(struct blocklevel_device *bl, uint32_t pos, const void *buf,
		uint32_t len, bool verify, bool ecc)
{
	struct ecc64 *bufecc;
	uint32_t copylen, copylen_minus_ecc;
	int rc;
	uint8_t ret;

	if (!ecc)
		return flash_write(bl, pos, buf, len, verify);

	/* Copy the buffer in chunks */
	bufecc = malloc(ecc_buffer_size(COPY_BUFFER_LENGTH));
	if (!bufecc)
		return FLASH_ERR_MALLOC_FAILED;

	while (len > 0) {
		/* What's left to copy? */
		copylen = MIN(len, COPY_BUFFER_LENGTH);
		copylen_minus_ecc = ecc_buffer_size_minus_ecc(copylen);

		/* Add the ecc byte to the data */
		ret = memcpy_to_ecc(bufecc, buf, copylen_minus_ecc);
		if (ret) {
			rc = FLASH_ERR_ECC_INVALID;
			goto err;
		}

		/* Write ECCed data to the flash */
		rc = flash_write(bl, pos, bufecc, copylen, verify);
		if (rc)
			goto err;

		/* Update for next copy */
		len -= copylen_minus_ecc;
		buf = (uint8_t *)buf + copylen_minus_ecc;
		pos += copylen;
	}

	rc = 0;

err:
	free(bufecc);
	return rc;
}
Пример #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;
}
Пример #5
0
int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf,
		uint64_t len)
{
	int rc, ecc_protection;
	struct ecc64 *buffer;
	uint64_t ecc_len;
	uint64_t ecc_start, ecc_pos, ecc_diff;

	FL_DBG("%s: 0x%" PRIx64 "\t%p\t0x%" PRIx64 "\n", __func__, pos, buf, len);
	if (!bl || !buf) {
		errno = EINVAL;
		return FLASH_ERR_PARM_ERROR;
	}

	ecc_protection = ecc_protected(bl, pos, len, &ecc_start);

	FL_DBG("%s: 0x%" PRIx64 " for 0x%" PRIx64 " ecc=%s\n",
		__func__, pos, len, ecc_protection ?
		(ecc_protection == -1 ? "partial" : "yes") : "no");

	if (!ecc_protection)
		return blocklevel_raw_write(bl, pos, buf, len);

	/*
	 * The region we're writing to has both ecc protection and not.
	 * Perhaps one day in the future blocklevel can cope with this.
	 */
	if (ecc_protection == -1) {
		FL_ERR("%s: Can't cope with partial ecc\n", __func__);
		errno = EINVAL;
		return FLASH_ERR_PARM_ERROR;
	}

	pos = with_ecc_pos(ecc_start, pos);

	ecc_pos = ecc_buffer_align(ecc_start, pos);
	ecc_diff = pos - ecc_pos;
	ecc_len = ecc_buffer_size(len + ecc_diff);

	FL_DBG("%s: adjusted_pos: 0x%" PRIx64 ", ecc_pos: 0x%" PRIx64
			", ecc_diff: 0x%" PRIx64 ", ecc_len: 0x%" PRIx64 "\n",
			__func__, pos, ecc_pos, ecc_diff, ecc_len);

	buffer = malloc(ecc_len);
	if (!buffer) {
		errno = ENOMEM;
		rc = FLASH_ERR_MALLOC_FAILED;
		goto out;
	}

	if (ecc_diff) {
		uint64_t start_chunk = ecc_diff;
		uint64_t end_chunk = BYTES_PER_ECC - ecc_diff;
		uint64_t end_len = ecc_len - end_chunk;

		/*
		 * Read the start bytes that memcpy_to_ecc_unaligned() will need
		 * to calculate the first ecc byte
		 */
		rc = blocklevel_raw_read(bl, ecc_pos, buffer, start_chunk);
		if (rc) {
			errno = EBADF;
			rc = FLASH_ERR_ECC_INVALID;
			goto out;
		}

		/*
		 * Read the end bytes that memcpy_to_ecc_unaligned() will need
		 * to calculate the last ecc byte
		 */
		rc = blocklevel_raw_read(bl, ecc_pos + end_len, ((char *)buffer) + end_len,
				end_chunk);
		if (rc) {
			errno = EBADF;
			rc = FLASH_ERR_ECC_INVALID;
			goto out;
		}

		if (memcpy_to_ecc_unaligned(buffer, buf, len, ecc_diff)) {
			errno = EBADF;
			rc = FLASH_ERR_ECC_INVALID;
			goto out;
		}
	} else {
		if (memcpy_to_ecc(buffer, buf, len)) {
			errno = EBADF;
			rc = FLASH_ERR_ECC_INVALID;
			goto out;
		}
	}
	rc = blocklevel_raw_write(bl, pos, buffer, ecc_len);

out:
	free(buffer);
	return rc;
}
Пример #6
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;
}