1 /* 2 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <debug.h> 33 #include <errno.h> 34 #include <io_block.h> 35 #include <io_driver.h> 36 #include <io_storage.h> 37 #include <platform_def.h> 38 #include <string.h> 39 #include <utils.h> 40 41 typedef struct { 42 io_block_dev_spec_t *dev_spec; 43 uintptr_t base; 44 size_t file_pos; 45 size_t size; 46 } block_dev_state_t; 47 48 #define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0)) 49 50 io_type_t device_type_block(void); 51 52 static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 53 io_entity_t *entity); 54 static int block_seek(io_entity_t *entity, int mode, ssize_t offset); 55 static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 56 size_t *length_read); 57 static int block_write(io_entity_t *entity, const uintptr_t buffer, 58 size_t length, size_t *length_written); 59 static int block_close(io_entity_t *entity); 60 static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 61 static int block_dev_close(io_dev_info_t *dev_info); 62 63 static const io_dev_connector_t block_dev_connector = { 64 .dev_open = block_dev_open 65 }; 66 67 static const io_dev_funcs_t block_dev_funcs = { 68 .type = device_type_block, 69 .open = block_open, 70 .seek = block_seek, 71 .size = NULL, 72 .read = block_read, 73 .write = block_write, 74 .close = block_close, 75 .dev_init = NULL, 76 .dev_close = block_dev_close, 77 }; 78 79 static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; 80 static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; 81 82 /* Track number of allocated block state */ 83 static unsigned int block_dev_count; 84 85 io_type_t device_type_block(void) 86 { 87 return IO_TYPE_BLOCK; 88 } 89 90 /* Locate a block state in the pool, specified by address */ 91 static int find_first_block_state(const io_block_dev_spec_t *dev_spec, 92 unsigned int *index_out) 93 { 94 int result = -ENOENT; 95 for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) { 96 /* dev_spec is used as identifier since it's unique */ 97 if (state_pool[index].dev_spec == dev_spec) { 98 result = 0; 99 *index_out = index; 100 break; 101 } 102 } 103 return result; 104 } 105 106 /* Allocate a device info from the pool and return a pointer to it */ 107 static int allocate_dev_info(io_dev_info_t **dev_info) 108 { 109 int result = -ENOMEM; 110 assert(dev_info != NULL); 111 112 if (block_dev_count < MAX_IO_BLOCK_DEVICES) { 113 unsigned int index = 0; 114 result = find_first_block_state(NULL, &index); 115 assert(result == 0); 116 /* initialize dev_info */ 117 dev_info_pool[index].funcs = &block_dev_funcs; 118 dev_info_pool[index].info = (uintptr_t)&state_pool[index]; 119 *dev_info = &dev_info_pool[index]; 120 ++block_dev_count; 121 } 122 123 return result; 124 } 125 126 127 /* Release a device info to the pool */ 128 static int free_dev_info(io_dev_info_t *dev_info) 129 { 130 int result; 131 unsigned int index = 0; 132 block_dev_state_t *state; 133 assert(dev_info != NULL); 134 135 state = (block_dev_state_t *)dev_info->info; 136 result = find_first_block_state(state->dev_spec, &index); 137 if (result == 0) { 138 /* free if device info is valid */ 139 zeromem(state, sizeof(block_dev_state_t)); 140 zeromem(dev_info, sizeof(io_dev_info_t)); 141 --block_dev_count; 142 } 143 144 return result; 145 } 146 147 static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 148 io_entity_t *entity) 149 { 150 block_dev_state_t *cur; 151 io_block_spec_t *region; 152 153 assert((dev_info->info != (uintptr_t)NULL) && 154 (spec != (uintptr_t)NULL) && 155 (entity->info == (uintptr_t)NULL)); 156 157 region = (io_block_spec_t *)spec; 158 cur = (block_dev_state_t *)dev_info->info; 159 assert(((region->offset % cur->dev_spec->block_size) == 0) && 160 ((region->length % cur->dev_spec->block_size) == 0)); 161 162 cur->base = region->offset; 163 cur->size = region->length; 164 cur->file_pos = 0; 165 166 entity->info = (uintptr_t)cur; 167 return 0; 168 } 169 170 /* parameter offset is relative address at here */ 171 static int block_seek(io_entity_t *entity, int mode, ssize_t offset) 172 { 173 block_dev_state_t *cur; 174 175 assert(entity->info != (uintptr_t)NULL); 176 177 cur = (block_dev_state_t *)entity->info; 178 assert((offset >= 0) && (offset < cur->size)); 179 180 switch (mode) { 181 case IO_SEEK_SET: 182 cur->file_pos = offset; 183 break; 184 case IO_SEEK_CUR: 185 cur->file_pos += offset; 186 break; 187 default: 188 return -EINVAL; 189 } 190 assert(cur->file_pos < cur->size); 191 return 0; 192 } 193 194 static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 195 size_t *length_read) 196 { 197 block_dev_state_t *cur; 198 io_block_spec_t *buf; 199 io_block_ops_t *ops; 200 size_t aligned_length, skip, count, left, padding, block_size; 201 int lba; 202 int buffer_not_aligned; 203 204 assert(entity->info != (uintptr_t)NULL); 205 cur = (block_dev_state_t *)entity->info; 206 ops = &(cur->dev_spec->ops); 207 buf = &(cur->dev_spec->buffer); 208 block_size = cur->dev_spec->block_size; 209 assert((length <= cur->size) && 210 (length > 0) && 211 (ops->read != 0)); 212 213 if ((buffer & (block_size - 1)) != 0) { 214 /* 215 * buffer isn't aligned with block size. 216 * Block device always relies on DMA operation. 217 * It's better to make the buffer as block size aligned. 218 */ 219 buffer_not_aligned = 1; 220 } else { 221 buffer_not_aligned = 0; 222 } 223 224 skip = cur->file_pos % block_size; 225 aligned_length = ((skip + length) + (block_size - 1)) & 226 ~(block_size - 1); 227 padding = aligned_length - (skip + length); 228 left = aligned_length; 229 do { 230 lba = (cur->file_pos + cur->base) / block_size; 231 if (left >= buf->length) { 232 /* 233 * Since left is larger, it's impossible to padding. 234 * 235 * If buffer isn't aligned, we need to use aligned 236 * buffer instead. 237 */ 238 if (skip || buffer_not_aligned) { 239 /* 240 * The beginning address (file_pos) isn't 241 * aligned with block size, we need to use 242 * block buffer to read block. Since block 243 * device is always relied on DMA operation. 244 */ 245 count = ops->read(lba, buf->offset, 246 buf->length); 247 } else { 248 count = ops->read(lba, buffer, buf->length); 249 } 250 assert(count == buf->length); 251 cur->file_pos += count - skip; 252 if (skip || buffer_not_aligned) { 253 /* 254 * Since there's not aligned block size caused 255 * by skip or not aligned buffer, block buffer 256 * is used to store data. 257 */ 258 memcpy((void *)buffer, 259 (void *)(buf->offset + skip), 260 count - skip); 261 } 262 left = left - (count - skip); 263 } else { 264 if (skip || padding || buffer_not_aligned) { 265 /* 266 * The beginning address (file_pos) isn't 267 * aligned with block size, we have to read 268 * full block by block buffer instead. 269 * The size isn't aligned with block size. 270 * Use block buffer to avoid overflow. 271 * 272 * If buffer isn't aligned, use block buffer 273 * to avoid DMA error. 274 */ 275 count = ops->read(lba, buf->offset, left); 276 } else 277 count = ops->read(lba, buffer, left); 278 assert(count == left); 279 left = left - (skip + padding); 280 cur->file_pos += left; 281 if (skip || padding || buffer_not_aligned) { 282 /* 283 * Since there's not aligned block size or 284 * buffer, block buffer is used to store data. 285 */ 286 memcpy((void *)buffer, 287 (void *)(buf->offset + skip), 288 left); 289 } 290 /* It's already the last block operation */ 291 left = 0; 292 } 293 skip = cur->file_pos % block_size; 294 } while (left > 0); 295 *length_read = length; 296 297 return 0; 298 } 299 300 static int block_write(io_entity_t *entity, const uintptr_t buffer, 301 size_t length, size_t *length_written) 302 { 303 block_dev_state_t *cur; 304 io_block_spec_t *buf; 305 io_block_ops_t *ops; 306 size_t aligned_length, skip, count, left, padding, block_size; 307 int lba; 308 int buffer_not_aligned; 309 310 assert(entity->info != (uintptr_t)NULL); 311 cur = (block_dev_state_t *)entity->info; 312 ops = &(cur->dev_spec->ops); 313 buf = &(cur->dev_spec->buffer); 314 block_size = cur->dev_spec->block_size; 315 assert((length <= cur->size) && 316 (length > 0) && 317 (ops->read != 0) && 318 (ops->write != 0)); 319 320 if ((buffer & (block_size - 1)) != 0) { 321 /* 322 * buffer isn't aligned with block size. 323 * Block device always relies on DMA operation. 324 * It's better to make the buffer as block size aligned. 325 */ 326 buffer_not_aligned = 1; 327 } else { 328 buffer_not_aligned = 0; 329 } 330 331 skip = cur->file_pos % block_size; 332 aligned_length = ((skip + length) + (block_size - 1)) & 333 ~(block_size - 1); 334 padding = aligned_length - (skip + length); 335 left = aligned_length; 336 do { 337 lba = (cur->file_pos + cur->base) / block_size; 338 if (left >= buf->length) { 339 /* Since left is larger, it's impossible to padding. */ 340 if (skip || buffer_not_aligned) { 341 /* 342 * The beginning address (file_pos) isn't 343 * aligned with block size or buffer isn't 344 * aligned, we need to use block buffer to 345 * write block. 346 */ 347 count = ops->read(lba, buf->offset, 348 buf->length); 349 assert(count == buf->length); 350 memcpy((void *)(buf->offset + skip), 351 (void *)buffer, 352 count - skip); 353 count = ops->write(lba, buf->offset, 354 buf->length); 355 } else 356 count = ops->write(lba, buffer, buf->length); 357 assert(count == buf->length); 358 cur->file_pos += count - skip; 359 left = left - (count - skip); 360 } else { 361 if (skip || padding || buffer_not_aligned) { 362 /* 363 * The beginning address (file_pos) isn't 364 * aligned with block size, we need to avoid 365 * poluate data in the beginning. Reading and 366 * skipping the beginning is the only way. 367 * The size isn't aligned with block size. 368 * Use block buffer to avoid overflow. 369 * 370 * If buffer isn't aligned, use block buffer 371 * to avoid DMA error. 372 */ 373 count = ops->read(lba, buf->offset, left); 374 assert(count == left); 375 memcpy((void *)(buf->offset + skip), 376 (void *)buffer, 377 left - skip - padding); 378 count = ops->write(lba, buf->offset, left); 379 } else 380 count = ops->write(lba, buffer, left); 381 assert(count == left); 382 cur->file_pos += left - (skip + padding); 383 /* It's already the last block operation */ 384 left = 0; 385 } 386 skip = cur->file_pos % block_size; 387 } while (left > 0); 388 *length_written = length; 389 return 0; 390 } 391 392 static int block_close(io_entity_t *entity) 393 { 394 entity->info = (uintptr_t)NULL; 395 return 0; 396 } 397 398 static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) 399 { 400 block_dev_state_t *cur; 401 io_block_spec_t *buffer; 402 io_dev_info_t *info; 403 size_t block_size; 404 int result; 405 406 assert(dev_info != NULL); 407 result = allocate_dev_info(&info); 408 if (result) 409 return -ENOENT; 410 411 cur = (block_dev_state_t *)info->info; 412 /* dev_spec is type of io_block_dev_spec_t. */ 413 cur->dev_spec = (io_block_dev_spec_t *)dev_spec; 414 buffer = &(cur->dev_spec->buffer); 415 block_size = cur->dev_spec->block_size; 416 assert((block_size > 0) && 417 (is_power_of_2(block_size) != 0) && 418 ((buffer->offset % block_size) == 0) && 419 ((buffer->length % block_size) == 0)); 420 421 *dev_info = info; /* cast away const */ 422 (void)block_size; 423 (void)buffer; 424 return 0; 425 } 426 427 static int block_dev_close(io_dev_info_t *dev_info) 428 { 429 return free_dev_info(dev_info); 430 } 431 432 /* Exported functions */ 433 434 /* Register the Block driver with the IO abstraction */ 435 int register_io_dev_block(const io_dev_connector_t **dev_con) 436 { 437 int result; 438 439 assert(dev_con != NULL); 440 441 /* 442 * Since dev_info isn't really used in io_register_device, always 443 * use the same device info at here instead. 444 */ 445 result = io_register_device(&dev_info_pool[0]); 446 if (result == 0) 447 *dev_con = &block_dev_connector; 448 return result; 449 } 450