blob: eed50cc0861ee42e678ffc5ec136b953e5f8ac81 [file] [log] [blame]
Harry Liebel561cd332014-02-14 14:42:48 +00001/*
Roberto Vargas05712702018-02-12 12:36:17 +00002 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
Harry Liebel561cd332014-02-14 14:42:48 +00003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Harry Liebel561cd332014-02-14 14:42:48 +00005 */
6
7#include <assert.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01008#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <platform_def.h>
11
12#include <common/debug.h>
13#include <drivers/io/io_driver.h>
14#include <drivers/io/io_memmap.h>
15#include <drivers/io/io_storage.h>
16#include <lib/utils.h>
Harry Liebel561cd332014-02-14 14:42:48 +000017
18/* As we need to be able to keep state for seek, only one file can be open
19 * at a time. Make this a structure and point to the entity->info. When we
20 * can malloc memory we can change this to support more open files.
21 */
22typedef struct {
23 /* Use the 'in_use' flag as any value for base and file_pos could be
24 * valid.
25 */
Yann Gautierf30cddc2019-04-16 11:35:19 +020026 int in_use;
27 uintptr_t base;
28 unsigned long long file_pos;
29 unsigned long long size;
Dan Handleye2712bc2014-04-10 15:37:22 +010030} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000031
Dan Handleye2712bc2014-04-10 15:37:22 +010032static file_state_t current_file = {0};
Harry Liebel561cd332014-02-14 14:42:48 +000033
34/* Identify the device type as memmap */
Roberto Vargas05712702018-02-12 12:36:17 +000035static io_type_t device_type_memmap(void)
Harry Liebel561cd332014-02-14 14:42:48 +000036{
37 return IO_TYPE_MEMMAP;
38}
39
40/* Memmap device functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010041static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
42static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010043 io_entity_t *entity);
44static int memmap_block_seek(io_entity_t *entity, int mode,
Yann Gautierf30cddc2019-04-16 11:35:19 +020045 signed long long offset);
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010046static int memmap_block_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010047static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000048 size_t length, size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010049static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000050 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010051static int memmap_block_close(io_entity_t *entity);
52static int memmap_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000053
54
Dan Handleya4cb68e2014-04-23 13:47:06 +010055static const io_dev_connector_t memmap_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000056 .dev_open = memmap_dev_open
57};
58
59
Dan Handleya4cb68e2014-04-23 13:47:06 +010060static const io_dev_funcs_t memmap_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000061 .type = device_type_memmap,
62 .open = memmap_block_open,
63 .seek = memmap_block_seek,
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010064 .size = memmap_block_len,
Harry Liebel561cd332014-02-14 14:42:48 +000065 .read = memmap_block_read,
66 .write = memmap_block_write,
67 .close = memmap_block_close,
68 .dev_init = NULL,
69 .dev_close = memmap_dev_close,
70};
71
72
Dan Handleya4cb68e2014-04-23 13:47:06 +010073/* No state associated with this device so structure can be const */
74static const io_dev_info_t memmap_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000075 .funcs = &memmap_dev_funcs,
76 .info = (uintptr_t)NULL
77};
78
79
80/* Open a connection to the memmap device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080081static int memmap_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +010082 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000083{
84 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010085 *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +000086
Juan Castillo6e762062015-11-02 10:47:01 +000087 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000088}
89
90
91
92/* Close a connection to the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +010093static int memmap_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000094{
95 /* NOP */
96 /* TODO: Consider tracking open files and cleaning them up here */
Juan Castillo6e762062015-11-02 10:47:01 +000097 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000098}
99
100
101/* Open a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100102static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100103 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000104{
Juan Castillo6e762062015-11-02 10:47:01 +0000105 int result = -ENOMEM;
Dan Handleye2712bc2014-04-10 15:37:22 +0100106 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000107
108 /* Since we need to track open state for seek() we only allow one open
109 * spec at a time. When we have dynamic memory we can malloc and set
110 * entity->info.
111 */
112 if (current_file.in_use == 0) {
113 assert(block_spec != NULL);
114 assert(entity != NULL);
115
116 current_file.in_use = 1;
117 current_file.base = block_spec->offset;
118 /* File cursor offset for seek and incremental reads etc. */
119 current_file.file_pos = 0;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100120 current_file.size = block_spec->length;
Harry Liebel561cd332014-02-14 14:42:48 +0000121 entity->info = (uintptr_t)&current_file;
Juan Castillo6e762062015-11-02 10:47:01 +0000122 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000123 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000124 WARN("A Memmap device is already active. Close first.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000125 }
126
127 return result;
128}
129
130
131/* Seek to a particular file offset on the memmap device */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200132static int memmap_block_seek(io_entity_t *entity, int mode,
133 signed long long offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000134{
Juan Castillo6e762062015-11-02 10:47:01 +0000135 int result = -ENOENT;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000136 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000137
138 /* We only support IO_SEEK_SET for the moment. */
139 if (mode == IO_SEEK_SET) {
140 assert(entity != NULL);
141
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000142 fp = (file_state_t *) entity->info;
143
144 /* Assert that new file position is valid */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200145 assert((offset >= 0) &&
146 ((unsigned long long)offset < fp->size));
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000147
148 /* Reset file position */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200149 fp->file_pos = (unsigned long long)offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000150 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000151 }
152
153 return result;
154}
155
156
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100157/* Return the size of a file on the memmap device */
158static int memmap_block_len(io_entity_t *entity, size_t *length)
159{
160 assert(entity != NULL);
161 assert(length != NULL);
162
Yann Gautierf30cddc2019-04-16 11:35:19 +0200163 *length = (size_t)((file_state_t *)entity->info)->size;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100164
165 return 0;
166}
167
168
Harry Liebel561cd332014-02-14 14:42:48 +0000169/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100170static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000171 size_t length, size_t *length_read)
172{
Dan Handleye2712bc2014-04-10 15:37:22 +0100173 file_state_t *fp;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200174 unsigned long long pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000175
176 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000177 assert(length_read != NULL);
178
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000179 fp = (file_state_t *) entity->info;
180
181 /* Assert that file position is valid for this read operation */
182 pos_after = fp->file_pos + length;
183 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000184
Yann Gautierf30cddc2019-04-16 11:35:19 +0200185 memcpy((void *)buffer,
186 (void *)((uintptr_t)(fp->base + fp->file_pos)), length);
Harry Liebel561cd332014-02-14 14:42:48 +0000187
188 *length_read = length;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000189
190 /* Set file position after read */
191 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000192
Juan Castillo6e762062015-11-02 10:47:01 +0000193 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000194}
195
196
197/* Write data to a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100198static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000199 size_t length, size_t *length_written)
200{
Dan Handleye2712bc2014-04-10 15:37:22 +0100201 file_state_t *fp;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200202 unsigned long long pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000203
204 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000205 assert(length_written != NULL);
206
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000207 fp = (file_state_t *) entity->info;
208
209 /* Assert that file position is valid for this write operation */
210 pos_after = fp->file_pos + length;
211 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000212
Yann Gautierf30cddc2019-04-16 11:35:19 +0200213 memcpy((void *)((uintptr_t)(fp->base + fp->file_pos)),
214 (void *)buffer, length);
Harry Liebel561cd332014-02-14 14:42:48 +0000215
216 *length_written = length;
217
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000218 /* Set file position after write */
219 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000220
Juan Castillo6e762062015-11-02 10:47:01 +0000221 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000222}
223
224
225/* Close a file on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100226static int memmap_block_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000227{
228 assert(entity != NULL);
229
230 entity->info = 0;
231
232 /* This would be a mem free() if we had malloc.*/
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000233 zeromem((void *)&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000234
Juan Castillo6e762062015-11-02 10:47:01 +0000235 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000236}
237
238
239/* Exported functions */
240
241/* Register the memmap driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100242int register_io_dev_memmap(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000243{
Juan Castillo6e762062015-11-02 10:47:01 +0000244 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000245 assert(dev_con != NULL);
246
247 result = io_register_device(&memmap_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000248 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000249 *dev_con = &memmap_dev_connector;
250
251 return result;
252}