Commit ee3e9359 authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #676 from hzhuang1/fix_io_unaligned

io: block: fix unaligned buffer
parents 41b568f5 9d063aa2
...@@ -198,6 +198,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -198,6 +198,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
io_block_ops_t *ops; io_block_ops_t *ops;
size_t aligned_length, skip, count, left, padding, block_size; size_t aligned_length, skip, count, left, padding, block_size;
int lba; int lba;
int buffer_not_aligned;
assert(entity->info != (uintptr_t)NULL); assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info; cur = (block_dev_state_t *)entity->info;
...@@ -208,6 +209,17 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -208,6 +209,17 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
(length > 0) && (length > 0) &&
(ops->read != 0)); (ops->read != 0));
if ((buffer & (block_size - 1)) != 0) {
/*
* buffer isn't aligned with block size.
* Block device always relies on DMA operation.
* It's better to make the buffer as block size aligned.
*/
buffer_not_aligned = 1;
} else {
buffer_not_aligned = 0;
}
skip = cur->file_pos % block_size; skip = cur->file_pos % block_size;
aligned_length = ((skip + length) + (block_size - 1)) & aligned_length = ((skip + length) + (block_size - 1)) &
~(block_size - 1); ~(block_size - 1);
...@@ -216,8 +228,13 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -216,8 +228,13 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
do { do {
lba = (cur->file_pos + cur->base) / block_size; lba = (cur->file_pos + cur->base) / block_size;
if (left >= buf->length) { if (left >= buf->length) {
/* Since left is larger, it's impossible to padding. */ /*
if (skip) { * Since left is larger, it's impossible to padding.
*
* If buffer isn't aligned, we need to use aligned
* buffer instead.
*/
if (skip || buffer_not_aligned) {
/* /*
* The beginning address (file_pos) isn't * The beginning address (file_pos) isn't
* aligned with block size, we need to use * aligned with block size, we need to use
...@@ -231,10 +248,11 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -231,10 +248,11 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
} }
assert(count == buf->length); assert(count == buf->length);
cur->file_pos += count - skip; cur->file_pos += count - skip;
if (skip) { if (skip || buffer_not_aligned) {
/* /*
* Since it's not aligned with block size, * Since there's not aligned block size caused
* block buffer is used to store data. * by skip or not aligned buffer, block buffer
* is used to store data.
*/ */
memcpy((void *)buffer, memcpy((void *)buffer,
(void *)(buf->offset + skip), (void *)(buf->offset + skip),
...@@ -242,13 +260,16 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -242,13 +260,16 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
} }
left = left - (count - skip); left = left - (count - skip);
} else { } else {
if (skip || padding) { if (skip || padding || buffer_not_aligned) {
/* /*
* The beginning address (file_pos) isn't * The beginning address (file_pos) isn't
* aligned with block size, we have to read * aligned with block size, we have to read
* full block by block buffer instead. * full block by block buffer instead.
* The size isn't aligned with block size. * The size isn't aligned with block size.
* Use block buffer to avoid overflow. * Use block buffer to avoid overflow.
*
* If buffer isn't aligned, use block buffer
* to avoid DMA error.
*/ */
count = ops->read(lba, buf->offset, left); count = ops->read(lba, buf->offset, left);
} else } else
...@@ -256,10 +277,10 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ...@@ -256,10 +277,10 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
assert(count == left); assert(count == left);
left = left - (skip + padding); left = left - (skip + padding);
cur->file_pos += left; cur->file_pos += left;
if (skip || padding) { if (skip || padding || buffer_not_aligned) {
/* /*
* Since it's not aligned with block size, * Since there's not aligned block size or
* block buffer is used to store data. * buffer, block buffer is used to store data.
*/ */
memcpy((void *)buffer, memcpy((void *)buffer,
(void *)(buf->offset + skip), (void *)(buf->offset + skip),
...@@ -283,6 +304,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, ...@@ -283,6 +304,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
io_block_ops_t *ops; io_block_ops_t *ops;
size_t aligned_length, skip, count, left, padding, block_size; size_t aligned_length, skip, count, left, padding, block_size;
int lba; int lba;
int buffer_not_aligned;
assert(entity->info != (uintptr_t)NULL); assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info; cur = (block_dev_state_t *)entity->info;
...@@ -294,6 +316,17 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, ...@@ -294,6 +316,17 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
(ops->read != 0) && (ops->read != 0) &&
(ops->write != 0)); (ops->write != 0));
if ((buffer & (block_size - 1)) != 0) {
/*
* buffer isn't aligned with block size.
* Block device always relies on DMA operation.
* It's better to make the buffer as block size aligned.
*/
buffer_not_aligned = 1;
} else {
buffer_not_aligned = 0;
}
skip = cur->file_pos % block_size; skip = cur->file_pos % block_size;
aligned_length = ((skip + length) + (block_size - 1)) & aligned_length = ((skip + length) + (block_size - 1)) &
~(block_size - 1); ~(block_size - 1);
...@@ -303,12 +336,12 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, ...@@ -303,12 +336,12 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
lba = (cur->file_pos + cur->base) / block_size; lba = (cur->file_pos + cur->base) / block_size;
if (left >= buf->length) { if (left >= buf->length) {
/* Since left is larger, it's impossible to padding. */ /* Since left is larger, it's impossible to padding. */
if (skip) { if (skip || buffer_not_aligned) {
/* /*
* The beginning address (file_pos) isn't * The beginning address (file_pos) isn't
* aligned with block size, we need to use * aligned with block size or buffer isn't
* block buffer to write block. Since block * aligned, we need to use block buffer to
* device is always relied on DMA operation. * write block.
*/ */
count = ops->read(lba, buf->offset, count = ops->read(lba, buf->offset,
buf->length); buf->length);
...@@ -324,7 +357,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, ...@@ -324,7 +357,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
cur->file_pos += count - skip; cur->file_pos += count - skip;
left = left - (count - skip); left = left - (count - skip);
} else { } else {
if (skip || padding) { if (skip || padding || buffer_not_aligned) {
/* /*
* The beginning address (file_pos) isn't * The beginning address (file_pos) isn't
* aligned with block size, we need to avoid * aligned with block size, we need to avoid
...@@ -332,6 +365,9 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, ...@@ -332,6 +365,9 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* skipping the beginning is the only way. * skipping the beginning is the only way.
* The size isn't aligned with block size. * The size isn't aligned with block size.
* Use block buffer to avoid overflow. * Use block buffer to avoid overflow.
*
* If buffer isn't aligned, use block buffer
* to avoid DMA error.
*/ */
count = ops->read(lba, buf->offset, left); count = ops->read(lba, buf->offset, left);
assert(count == left); assert(count == left);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment