diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c index 198b723..4ec59bc 100644 --- a/drivers/io/io_block.c +++ b/drivers/io/io_block.c @@ -198,6 +198,7 @@ io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -208,6 +209,17 @@ (length > 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; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -216,8 +228,13 @@ do { lba = (cur->file_pos + cur->base) / block_size; 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 * aligned with block size, we need to use @@ -231,10 +248,11 @@ } assert(count == buf->length); cur->file_pos += count - skip; - if (skip) { + if (skip || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size caused + * by skip or not aligned buffer, block buffer + * is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -242,13 +260,16 @@ } left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we have to read * full block by block buffer instead. * The size isn't aligned with block size. * 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); } else @@ -256,10 +277,10 @@ assert(count == left); left = left - (skip + padding); cur->file_pos += left; - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size or + * buffer, block buffer is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -283,6 +304,7 @@ io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -294,6 +316,17 @@ (ops->read != 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; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -303,12 +336,12 @@ lba = (cur->file_pos + cur->base) / block_size; if (left >= buf->length) { /* Since left is larger, it's impossible to padding. */ - if (skip) { + if (skip || buffer_not_aligned) { /* * The beginning address (file_pos) isn't - * aligned with block size, we need to use - * block buffer to write block. Since block - * device is always relied on DMA operation. + * aligned with block size or buffer isn't + * aligned, we need to use block buffer to + * write block. */ count = ops->read(lba, buf->offset, buf->length); @@ -324,7 +357,7 @@ cur->file_pos += count - skip; left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we need to avoid @@ -332,6 +365,9 @@ * skipping the beginning is the only way. * The size isn't aligned with block size. * 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); assert(count == left);