blob: 96590b6c03a05486b8d4da6d8fee7d1dc0228ed2 [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 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010026 int in_use;
27 uintptr_t base;
28 size_t file_pos;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010029 size_t 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,
Harry Liebel561cd332014-02-14 14:42:48 +000045 ssize_t 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 */
Dan Handleye2712bc2014-04-10 15:37:22 +0100132static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000133{
Juan Castillo6e762062015-11-02 10:47:01 +0000134 int result = -ENOENT;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000135 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000136
137 /* We only support IO_SEEK_SET for the moment. */
138 if (mode == IO_SEEK_SET) {
139 assert(entity != NULL);
140
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000141 fp = (file_state_t *) entity->info;
142
143 /* Assert that new file position is valid */
144 assert((offset >= 0) && (offset < fp->size));
145
146 /* Reset file position */
147 fp->file_pos = offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000148 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000149 }
150
151 return result;
152}
153
154
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100155/* Return the size of a file on the memmap device */
156static int memmap_block_len(io_entity_t *entity, size_t *length)
157{
158 assert(entity != NULL);
159 assert(length != NULL);
160
161 *length = ((file_state_t *)entity->info)->size;
162
163 return 0;
164}
165
166
Harry Liebel561cd332014-02-14 14:42:48 +0000167/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100168static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000169 size_t length, size_t *length_read)
170{
Dan Handleye2712bc2014-04-10 15:37:22 +0100171 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000172 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000173
174 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000175 assert(length_read != NULL);
176
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000177 fp = (file_state_t *) entity->info;
178
179 /* Assert that file position is valid for this read operation */
180 pos_after = fp->file_pos + length;
181 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000182
Dan Handleya4cb68e2014-04-23 13:47:06 +0100183 memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
Harry Liebel561cd332014-02-14 14:42:48 +0000184
185 *length_read = length;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000186
187 /* Set file position after read */
188 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000189
Juan Castillo6e762062015-11-02 10:47:01 +0000190 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000191}
192
193
194/* Write data to a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100195static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000196 size_t length, size_t *length_written)
197{
Dan Handleye2712bc2014-04-10 15:37:22 +0100198 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000199 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000200
201 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000202 assert(length_written != NULL);
203
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000204 fp = (file_state_t *) entity->info;
205
206 /* Assert that file position is valid for this write operation */
207 pos_after = fp->file_pos + length;
208 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000209
Dan Handleya4cb68e2014-04-23 13:47:06 +0100210 memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
Harry Liebel561cd332014-02-14 14:42:48 +0000211
212 *length_written = length;
213
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000214 /* Set file position after write */
215 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000216
Juan Castillo6e762062015-11-02 10:47:01 +0000217 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000218}
219
220
221/* Close a file on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100222static int memmap_block_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000223{
224 assert(entity != NULL);
225
226 entity->info = 0;
227
228 /* This would be a mem free() if we had malloc.*/
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000229 zeromem((void *)&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000230
Juan Castillo6e762062015-11-02 10:47:01 +0000231 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000232}
233
234
235/* Exported functions */
236
237/* Register the memmap driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100238int register_io_dev_memmap(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000239{
Juan Castillo6e762062015-11-02 10:47:01 +0000240 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000241 assert(dev_con != NULL);
242
243 result = io_register_device(&memmap_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000244 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000245 *dev_con = &memmap_dev_connector;
246
247 return result;
248}