blob: b5e0e5f722860245f5ecf443c04efa625e678e73 [file] [log] [blame]
Haojian Zhuang12ade162016-03-18 15:14:19 +08001/*
Yann Gautier0cfeac02022-12-09 14:35:05 +01002 * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
Haojian Zhuang12ade162016-03-18 15:14:19 +08003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Haojian Zhuang12ade162016-03-18 15:14:19 +08005 */
6
7#include <assert.h>
Haojian Zhuang12ade162016-03-18 15:14:19 +08008#include <errno.h>
Haojian Zhuang12ade162016-03-18 15:14:19 +08009#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
11#include <platform_def.h>
12
13#include <common/debug.h>
14#include <drivers/io/io_block.h>
15#include <drivers/io/io_driver.h>
16#include <drivers/io/io_storage.h>
17#include <lib/utils.h>
Haojian Zhuang12ade162016-03-18 15:14:19 +080018
19typedef struct {
20 io_block_dev_spec_t *dev_spec;
21 uintptr_t base;
Yann Gautierf30cddc2019-04-16 11:35:19 +020022 unsigned long long file_pos;
23 unsigned long long size;
Haojian Zhuang12ade162016-03-18 15:14:19 +080024} block_dev_state_t;
25
Yann Gautierf30cddc2019-04-16 11:35:19 +020026#define is_power_of_2(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
Haojian Zhuang12ade162016-03-18 15:14:19 +080027
28io_type_t device_type_block(void);
29
30static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
31 io_entity_t *entity);
Yann Gautierf30cddc2019-04-16 11:35:19 +020032static int block_seek(io_entity_t *entity, int mode, signed long long offset);
Haojian Zhuang12ade162016-03-18 15:14:19 +080033static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
34 size_t *length_read);
35static int block_write(io_entity_t *entity, const uintptr_t buffer,
36 size_t length, size_t *length_written);
37static int block_close(io_entity_t *entity);
38static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
39static int block_dev_close(io_dev_info_t *dev_info);
40
41static const io_dev_connector_t block_dev_connector = {
42 .dev_open = block_dev_open
43};
44
45static const io_dev_funcs_t block_dev_funcs = {
46 .type = device_type_block,
47 .open = block_open,
48 .seek = block_seek,
49 .size = NULL,
50 .read = block_read,
51 .write = block_write,
52 .close = block_close,
53 .dev_init = NULL,
54 .dev_close = block_dev_close,
55};
56
57static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES];
58static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES];
59
60/* Track number of allocated block state */
61static unsigned int block_dev_count;
62
63io_type_t device_type_block(void)
64{
65 return IO_TYPE_BLOCK;
66}
67
68/* Locate a block state in the pool, specified by address */
69static int find_first_block_state(const io_block_dev_spec_t *dev_spec,
70 unsigned int *index_out)
71{
Yann Gautier37966212018-12-03 13:38:06 +010072 unsigned int index;
Haojian Zhuang12ade162016-03-18 15:14:19 +080073 int result = -ENOENT;
Yann Gautier37966212018-12-03 13:38:06 +010074
75 for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) {
Haojian Zhuang12ade162016-03-18 15:14:19 +080076 /* dev_spec is used as identifier since it's unique */
77 if (state_pool[index].dev_spec == dev_spec) {
78 result = 0;
79 *index_out = index;
80 break;
81 }
82 }
83 return result;
84}
85
86/* Allocate a device info from the pool and return a pointer to it */
87static int allocate_dev_info(io_dev_info_t **dev_info)
88{
89 int result = -ENOMEM;
90 assert(dev_info != NULL);
91
92 if (block_dev_count < MAX_IO_BLOCK_DEVICES) {
93 unsigned int index = 0;
94 result = find_first_block_state(NULL, &index);
95 assert(result == 0);
96 /* initialize dev_info */
97 dev_info_pool[index].funcs = &block_dev_funcs;
98 dev_info_pool[index].info = (uintptr_t)&state_pool[index];
99 *dev_info = &dev_info_pool[index];
100 ++block_dev_count;
101 }
102
103 return result;
104}
105
106
107/* Release a device info to the pool */
108static int free_dev_info(io_dev_info_t *dev_info)
109{
110 int result;
111 unsigned int index = 0;
112 block_dev_state_t *state;
113 assert(dev_info != NULL);
114
115 state = (block_dev_state_t *)dev_info->info;
116 result = find_first_block_state(state->dev_spec, &index);
117 if (result == 0) {
118 /* free if device info is valid */
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000119 zeromem(state, sizeof(block_dev_state_t));
120 zeromem(dev_info, sizeof(io_dev_info_t));
Haojian Zhuang12ade162016-03-18 15:14:19 +0800121 --block_dev_count;
122 }
123
124 return result;
125}
126
127static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
128 io_entity_t *entity)
129{
130 block_dev_state_t *cur;
131 io_block_spec_t *region;
132
133 assert((dev_info->info != (uintptr_t)NULL) &&
134 (spec != (uintptr_t)NULL) &&
135 (entity->info == (uintptr_t)NULL));
136
137 region = (io_block_spec_t *)spec;
138 cur = (block_dev_state_t *)dev_info->info;
139 assert(((region->offset % cur->dev_spec->block_size) == 0) &&
140 ((region->length % cur->dev_spec->block_size) == 0));
141
142 cur->base = region->offset;
143 cur->size = region->length;
144 cur->file_pos = 0;
145
146 entity->info = (uintptr_t)cur;
147 return 0;
148}
149
150/* parameter offset is relative address at here */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200151static int block_seek(io_entity_t *entity, int mode, signed long long offset)
Haojian Zhuang12ade162016-03-18 15:14:19 +0800152{
153 block_dev_state_t *cur;
154
155 assert(entity->info != (uintptr_t)NULL);
156
157 cur = (block_dev_state_t *)entity->info;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200158 assert((offset >= 0) && ((unsigned long long)offset < cur->size));
Haojian Zhuang12ade162016-03-18 15:14:19 +0800159
160 switch (mode) {
161 case IO_SEEK_SET:
Yann Gautierf30cddc2019-04-16 11:35:19 +0200162 cur->file_pos = (unsigned long long)offset;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800163 break;
164 case IO_SEEK_CUR:
Yann Gautierf30cddc2019-04-16 11:35:19 +0200165 cur->file_pos += (unsigned long long)offset;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800166 break;
167 default:
168 return -EINVAL;
169 }
170 assert(cur->file_pos < cur->size);
171 return 0;
172}
173
Roberto Vargas034c9f82017-11-23 12:03:46 +0000174/*
175 * This function allows the caller to read any number of bytes
176 * from any position. It hides from the caller that the low level
177 * driver only can read aligned blocks of data. For this reason
178 * we need to handle the use case where the first byte to be read is not
179 * aligned to start of the block, the last byte to be read is also not
180 * aligned to the end of a block, and there are zero or more blocks-worth
181 * of data in between.
182 *
183 * In such a case we need to read more bytes than requested (i.e. full
184 * blocks) and strip-out the leading bytes (aka skip) and the trailing
185 * bytes (aka padding). See diagram below
186 *
187 * cur->file_pos ------------
188 * |
189 * cur->base |
190 * | |
191 * v v<---- length ---->
192 * --------------------------------------------------------------
193 * | | block#1 | | block#n |
194 * | block#0 | + | ... | + |
195 * | | <- skip -> + | | + <- padding ->|
196 * ------------------------+----------------------+--------------
197 * ^ ^
198 * | |
199 * v iteration#1 iteration#n v
200 * --------------------------------------------------
201 * | | | |
202 * |<---- request ---->| ... |<----- request ---->|
203 * | | | |
204 * --------------------------------------------------
205 * / / | |
206 * / / | |
207 * / / | |
208 * / / | |
209 * / / | |
210 * / / | |
211 * / / | |
212 * / / | |
213 * / / | |
214 * / / | |
215 * <---- request ------> <------ request ----->
216 * --------------------- -----------------------
217 * | | | | | |
218 * |<-skip->|<-nbytes->| -------->|<-nbytes->|<-padding->|
219 * | | | | | | |
220 * --------------------- | -----------------------
221 * ^ \ \ | | |
222 * | \ \ | | |
223 * | \ \ | | |
224 * buf->offset \ \ buf->offset | |
225 * \ \ | |
226 * \ \ | |
227 * \ \ | |
228 * \ \ | |
229 * \ \ | |
230 * \ \ | |
231 * \ \ | |
232 * --------------------------------
233 * | | | |
234 * buffer-------------->| | ... | |
235 * | | | |
236 * --------------------------------
237 * <-count#1->| |
238 * <---------- count#n -------->
239 * <---------- length ---------->
240 *
241 * Additionally, the IO driver has an underlying buffer that is at least
242 * one block-size and may be big enough to allow.
243 */
Haojian Zhuang12ade162016-03-18 15:14:19 +0800244static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
245 size_t *length_read)
246{
247 block_dev_state_t *cur;
248 io_block_spec_t *buf;
249 io_block_ops_t *ops;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800250 int lba;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000251 size_t block_size, left;
252 size_t nbytes; /* number of bytes read in one iteration */
253 size_t request; /* number of requested bytes in one iteration */
254 size_t count; /* number of bytes already read */
255 /*
256 * number of leading bytes from start of the block
257 * to the first byte to be read
258 */
259 size_t skip;
260
261 /*
262 * number of trailing bytes between the last byte
263 * to be read and the end of the block
264 */
265 size_t padding;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800266
267 assert(entity->info != (uintptr_t)NULL);
268 cur = (block_dev_state_t *)entity->info;
269 ops = &(cur->dev_spec->ops);
270 buf = &(cur->dev_spec->buffer);
271 block_size = cur->dev_spec->block_size;
272 assert((length <= cur->size) &&
Yann Gautierf30cddc2019-04-16 11:35:19 +0200273 (length > 0U) &&
Yann Gautier0cfeac02022-12-09 14:35:05 +0100274 (ops->read != NULL));
Haojian Zhuang12ade162016-03-18 15:14:19 +0800275
Roberto Vargas034c9f82017-11-23 12:03:46 +0000276 /*
277 * We don't know the number of bytes that we are going
278 * to read in every iteration, because it will depend
279 * on the low level driver.
280 */
281 count = 0;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200282 for (left = length; left > 0U; left -= nbytes) {
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800283 /*
Roberto Vargas034c9f82017-11-23 12:03:46 +0000284 * We must only request operations aligned to the block
285 * size. Therefore if file_pos is not block-aligned,
286 * we have to request the operation to start at the
287 * previous block boundary and skip the leading bytes. And
288 * similarly, the number of bytes requested must be a
289 * block size multiple
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800290 */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200291 skip = cur->file_pos & (block_size - 1U);
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800292
Roberto Vargas034c9f82017-11-23 12:03:46 +0000293 /*
294 * Calculate the block number containing file_pos
295 * - e.g. block 3.
296 */
Haojian Zhuang12ade162016-03-18 15:14:19 +0800297 lba = (cur->file_pos + cur->base) / block_size;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000298
Yann Gautierf30cddc2019-04-16 11:35:19 +0200299 if ((skip + left) > buf->length) {
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800300 /*
Roberto Vargas034c9f82017-11-23 12:03:46 +0000301 * The underlying read buffer is too small to
302 * read all the required data - limit to just
303 * fill the buffer, and then read again.
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800304 */
Roberto Vargas034c9f82017-11-23 12:03:46 +0000305 request = buf->length;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800306 } else {
Roberto Vargas034c9f82017-11-23 12:03:46 +0000307 /*
308 * The underlying read buffer is big enough to
309 * read all the required data. Calculate the
310 * number of bytes to read to align with the
311 * block size.
312 */
313 request = skip + left;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200314 request = (request + (block_size - 1U)) &
315 ~(block_size - 1U);
Roberto Vargas034c9f82017-11-23 12:03:46 +0000316 }
317 request = ops->read(lba, buf->offset, request);
318
319 if (request <= skip) {
320 /*
321 * We couldn't read enough bytes to jump over
322 * the skip bytes, so we should have to read
323 * again the same block, thus generating
324 * the same error.
325 */
326 return -EIO;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800327 }
Roberto Vargas034c9f82017-11-23 12:03:46 +0000328
329 /*
330 * Need to remove skip and padding bytes,if any, from
331 * the read data when copying to the user buffer.
332 */
333 nbytes = request - skip;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200334 padding = (nbytes > left) ? nbytes - left : 0U;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000335 nbytes -= padding;
336
337 memcpy((void *)(buffer + count),
338 (void *)(buf->offset + skip),
339 nbytes);
340
341 cur->file_pos += nbytes;
342 count += nbytes;
343 }
344 assert(count == length);
345 *length_read = count;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800346
347 return 0;
348}
349
Roberto Vargas034c9f82017-11-23 12:03:46 +0000350/*
351 * This function allows the caller to write any number of bytes
352 * from any position. It hides from the caller that the low level
353 * driver only can write aligned blocks of data.
354 * See comments for block_read for more details.
355 */
Haojian Zhuang12ade162016-03-18 15:14:19 +0800356static int block_write(io_entity_t *entity, const uintptr_t buffer,
357 size_t length, size_t *length_written)
358{
359 block_dev_state_t *cur;
360 io_block_spec_t *buf;
361 io_block_ops_t *ops;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800362 int lba;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000363 size_t block_size, left;
364 size_t nbytes; /* number of bytes read in one iteration */
365 size_t request; /* number of requested bytes in one iteration */
366 size_t count; /* number of bytes already read */
367 /*
368 * number of leading bytes from start of the block
369 * to the first byte to be read
370 */
371 size_t skip;
372
373 /*
374 * number of trailing bytes between the last byte
375 * to be read and the end of the block
376 */
377 size_t padding;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800378
379 assert(entity->info != (uintptr_t)NULL);
380 cur = (block_dev_state_t *)entity->info;
381 ops = &(cur->dev_spec->ops);
382 buf = &(cur->dev_spec->buffer);
383 block_size = cur->dev_spec->block_size;
384 assert((length <= cur->size) &&
Yann Gautierf30cddc2019-04-16 11:35:19 +0200385 (length > 0U) &&
Yann Gautier0cfeac02022-12-09 14:35:05 +0100386 (ops->read != NULL) &&
387 (ops->write != NULL));
Haojian Zhuang12ade162016-03-18 15:14:19 +0800388
Roberto Vargas034c9f82017-11-23 12:03:46 +0000389 /*
390 * We don't know the number of bytes that we are going
391 * to write in every iteration, because it will depend
392 * on the low level driver.
393 */
394 count = 0;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200395 for (left = length; left > 0U; left -= nbytes) {
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800396 /*
Roberto Vargas034c9f82017-11-23 12:03:46 +0000397 * We must only request operations aligned to the block
398 * size. Therefore if file_pos is not block-aligned,
399 * we have to request the operation to start at the
400 * previous block boundary and skip the leading bytes. And
401 * similarly, the number of bytes requested must be a
402 * block size multiple
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800403 */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200404 skip = cur->file_pos & (block_size - 1U);
Haojian Zhuangf800ccf2016-07-28 10:15:32 +0800405
Roberto Vargas034c9f82017-11-23 12:03:46 +0000406 /*
407 * Calculate the block number containing file_pos
408 * - e.g. block 3.
409 */
Haojian Zhuang12ade162016-03-18 15:14:19 +0800410 lba = (cur->file_pos + cur->base) / block_size;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000411
Yann Gautierf30cddc2019-04-16 11:35:19 +0200412 if ((skip + left) > buf->length) {
Roberto Vargas034c9f82017-11-23 12:03:46 +0000413 /*
414 * The underlying read buffer is too small to
415 * read all the required data - limit to just
416 * fill the buffer, and then read again.
417 */
418 request = buf->length;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800419 } else {
Roberto Vargas034c9f82017-11-23 12:03:46 +0000420 /*
421 * The underlying read buffer is big enough to
422 * read all the required data. Calculate the
423 * number of bytes to read to align with the
424 * block size.
425 */
426 request = skip + left;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200427 request = (request + (block_size - 1U)) &
428 ~(block_size - 1U);
Roberto Vargas034c9f82017-11-23 12:03:46 +0000429 }
430
431 /*
432 * The number of bytes that we are going to write
433 * from the user buffer will depend of the size
434 * of the current request.
435 */
436 nbytes = request - skip;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200437 padding = (nbytes > left) ? nbytes - left : 0U;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000438 nbytes -= padding;
439
440 /*
441 * If we have skip or padding bytes then we have to preserve
442 * some content and it means that we have to read before
443 * writing
444 */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200445 if ((skip > 0U) || (padding > 0U)) {
Roberto Vargas034c9f82017-11-23 12:03:46 +0000446 request = ops->read(lba, buf->offset, request);
447 /*
448 * The read may return size less than
449 * requested. Round down to the nearest block
450 * boundary
451 */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200452 request &= ~(block_size - 1U);
Roberto Vargas034c9f82017-11-23 12:03:46 +0000453 if (request <= skip) {
Haojian Zhuang12ade162016-03-18 15:14:19 +0800454 /*
Roberto Vargas034c9f82017-11-23 12:03:46 +0000455 * We couldn't read enough bytes to jump over
456 * the skip bytes, so we should have to read
457 * again the same block, thus generating
458 * the same error.
Haojian Zhuang12ade162016-03-18 15:14:19 +0800459 */
Roberto Vargas034c9f82017-11-23 12:03:46 +0000460 return -EIO;
461 }
462 nbytes = request - skip;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200463 padding = (nbytes > left) ? nbytes - left : 0U;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000464 nbytes -= padding;
Haojian Zhuang12ade162016-03-18 15:14:19 +0800465 }
Roberto Vargas034c9f82017-11-23 12:03:46 +0000466
467 memcpy((void *)(buf->offset + skip),
468 (void *)(buffer + count),
469 nbytes);
470
471 request = ops->write(lba, buf->offset, request);
472 if (request <= skip)
473 return -EIO;
474
475 /*
476 * And the previous write operation may modify the size
477 * of the request, so again, we have to calculate the
478 * number of bytes that we consumed from the user
479 * buffer
480 */
481 nbytes = request - skip;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200482 padding = (nbytes > left) ? nbytes - left : 0U;
Roberto Vargas034c9f82017-11-23 12:03:46 +0000483 nbytes -= padding;
484
485 cur->file_pos += nbytes;
486 count += nbytes;
487 }
488 assert(count == length);
489 *length_written = count;
490
Haojian Zhuang12ade162016-03-18 15:14:19 +0800491 return 0;
492}
493
494static int block_close(io_entity_t *entity)
495{
496 entity->info = (uintptr_t)NULL;
497 return 0;
498}
499
500static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
501{
502 block_dev_state_t *cur;
503 io_block_spec_t *buffer;
504 io_dev_info_t *info;
505 size_t block_size;
506 int result;
507
508 assert(dev_info != NULL);
509 result = allocate_dev_info(&info);
Yann Gautierf30cddc2019-04-16 11:35:19 +0200510 if (result != 0)
Haojian Zhuang12ade162016-03-18 15:14:19 +0800511 return -ENOENT;
512
513 cur = (block_dev_state_t *)info->info;
514 /* dev_spec is type of io_block_dev_spec_t. */
515 cur->dev_spec = (io_block_dev_spec_t *)dev_spec;
516 buffer = &(cur->dev_spec->buffer);
517 block_size = cur->dev_spec->block_size;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200518 assert((block_size > 0U) &&
519 (is_power_of_2(block_size) != 0U) &&
520 ((buffer->offset % block_size) == 0U) &&
521 ((buffer->length % block_size) == 0U));
Haojian Zhuang12ade162016-03-18 15:14:19 +0800522
523 *dev_info = info; /* cast away const */
524 (void)block_size;
525 (void)buffer;
526 return 0;
527}
528
529static int block_dev_close(io_dev_info_t *dev_info)
530{
531 return free_dev_info(dev_info);
532}
533
534/* Exported functions */
535
536/* Register the Block driver with the IO abstraction */
537int register_io_dev_block(const io_dev_connector_t **dev_con)
538{
539 int result;
540
541 assert(dev_con != NULL);
542
543 /*
544 * Since dev_info isn't really used in io_register_device, always
545 * use the same device info at here instead.
546 */
547 result = io_register_device(&dev_info_pool[0]);
548 if (result == 0)
549 *dev_con = &block_dev_connector;
550 return result;
551}