blob: b7e26bd4a889c7c301a987dbe5a9faf4e07ea679 [file] [log] [blame]
Harry Liebel561cd332014-02-14 14:42:48 +00001/*
Douglas Raillarda8954fc2017-01-26 15:54:44 +00002 * Copyright (c) 2014-2017, 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 Handley714a0d22014-04-09 13:13:04 +01008#include <debug.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01009#include <io_driver.h>
10#include <io_storage.h>
11#include <string.h>
Douglas Raillarda8954fc2017-01-26 15:54:44 +000012#include <utils.h>
Harry Liebel561cd332014-02-14 14:42:48 +000013
14/* As we need to be able to keep state for seek, only one file can be open
15 * at a time. Make this a structure and point to the entity->info. When we
16 * can malloc memory we can change this to support more open files.
17 */
18typedef struct {
19 /* Use the 'in_use' flag as any value for base and file_pos could be
20 * valid.
21 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010022 int in_use;
23 uintptr_t base;
24 size_t file_pos;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010025 size_t size;
Dan Handleye2712bc2014-04-10 15:37:22 +010026} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000027
Dan Handleye2712bc2014-04-10 15:37:22 +010028static file_state_t current_file = {0};
Harry Liebel561cd332014-02-14 14:42:48 +000029
30/* Identify the device type as memmap */
Dan Handleye2712bc2014-04-10 15:37:22 +010031io_type_t device_type_memmap(void)
Harry Liebel561cd332014-02-14 14:42:48 +000032{
33 return IO_TYPE_MEMMAP;
34}
35
36/* Memmap device functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010037static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
38static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010039 io_entity_t *entity);
40static int memmap_block_seek(io_entity_t *entity, int mode,
Harry Liebel561cd332014-02-14 14:42:48 +000041 ssize_t offset);
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010042static int memmap_block_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010043static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000044 size_t length, size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010045static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000046 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010047static int memmap_block_close(io_entity_t *entity);
48static int memmap_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000049
50
Dan Handleya4cb68e2014-04-23 13:47:06 +010051static const io_dev_connector_t memmap_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000052 .dev_open = memmap_dev_open
53};
54
55
Dan Handleya4cb68e2014-04-23 13:47:06 +010056static const io_dev_funcs_t memmap_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000057 .type = device_type_memmap,
58 .open = memmap_block_open,
59 .seek = memmap_block_seek,
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010060 .size = memmap_block_len,
Harry Liebel561cd332014-02-14 14:42:48 +000061 .read = memmap_block_read,
62 .write = memmap_block_write,
63 .close = memmap_block_close,
64 .dev_init = NULL,
65 .dev_close = memmap_dev_close,
66};
67
68
Dan Handleya4cb68e2014-04-23 13:47:06 +010069/* No state associated with this device so structure can be const */
70static const io_dev_info_t memmap_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000071 .funcs = &memmap_dev_funcs,
72 .info = (uintptr_t)NULL
73};
74
75
76/* Open a connection to the memmap device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080077static int memmap_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +010078 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000079{
80 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010081 *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +000082
Juan Castillo6e762062015-11-02 10:47:01 +000083 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000084}
85
86
87
88/* Close a connection to the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +010089static int memmap_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000090{
91 /* NOP */
92 /* TODO: Consider tracking open files and cleaning them up here */
Juan Castillo6e762062015-11-02 10:47:01 +000093 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000094}
95
96
97/* Open a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010098static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010099 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000100{
Juan Castillo6e762062015-11-02 10:47:01 +0000101 int result = -ENOMEM;
Dan Handleye2712bc2014-04-10 15:37:22 +0100102 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000103
104 /* Since we need to track open state for seek() we only allow one open
105 * spec at a time. When we have dynamic memory we can malloc and set
106 * entity->info.
107 */
108 if (current_file.in_use == 0) {
109 assert(block_spec != NULL);
110 assert(entity != NULL);
111
112 current_file.in_use = 1;
113 current_file.base = block_spec->offset;
114 /* File cursor offset for seek and incremental reads etc. */
115 current_file.file_pos = 0;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100116 current_file.size = block_spec->length;
Harry Liebel561cd332014-02-14 14:42:48 +0000117 entity->info = (uintptr_t)&current_file;
Juan Castillo6e762062015-11-02 10:47:01 +0000118 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000119 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000120 WARN("A Memmap device is already active. Close first.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000121 }
122
123 return result;
124}
125
126
127/* Seek to a particular file offset on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100128static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000129{
Juan Castillo6e762062015-11-02 10:47:01 +0000130 int result = -ENOENT;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000131 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000132
133 /* We only support IO_SEEK_SET for the moment. */
134 if (mode == IO_SEEK_SET) {
135 assert(entity != NULL);
136
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000137 fp = (file_state_t *) entity->info;
138
139 /* Assert that new file position is valid */
140 assert((offset >= 0) && (offset < fp->size));
141
142 /* Reset file position */
143 fp->file_pos = offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000144 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000145 }
146
147 return result;
148}
149
150
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100151/* Return the size of a file on the memmap device */
152static int memmap_block_len(io_entity_t *entity, size_t *length)
153{
154 assert(entity != NULL);
155 assert(length != NULL);
156
157 *length = ((file_state_t *)entity->info)->size;
158
159 return 0;
160}
161
162
Harry Liebel561cd332014-02-14 14:42:48 +0000163/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100164static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000165 size_t length, size_t *length_read)
166{
Dan Handleye2712bc2014-04-10 15:37:22 +0100167 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000168 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000169
170 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100171 assert(buffer != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000172 assert(length_read != NULL);
173
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000174 fp = (file_state_t *) entity->info;
175
176 /* Assert that file position is valid for this read operation */
177 pos_after = fp->file_pos + length;
178 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000179
Dan Handleya4cb68e2014-04-23 13:47:06 +0100180 memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
Harry Liebel561cd332014-02-14 14:42:48 +0000181
182 *length_read = length;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000183
184 /* Set file position after read */
185 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000186
Juan Castillo6e762062015-11-02 10:47:01 +0000187 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000188}
189
190
191/* Write data to a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100192static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000193 size_t length, size_t *length_written)
194{
Dan Handleye2712bc2014-04-10 15:37:22 +0100195 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000196 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000197
198 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100199 assert(buffer != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000200 assert(length_written != NULL);
201
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000202 fp = (file_state_t *) entity->info;
203
204 /* Assert that file position is valid for this write operation */
205 pos_after = fp->file_pos + length;
206 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000207
Dan Handleya4cb68e2014-04-23 13:47:06 +0100208 memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
Harry Liebel561cd332014-02-14 14:42:48 +0000209
210 *length_written = length;
211
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000212 /* Set file position after write */
213 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000214
Juan Castillo6e762062015-11-02 10:47:01 +0000215 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000216}
217
218
219/* Close a file on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100220static int memmap_block_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000221{
222 assert(entity != NULL);
223
224 entity->info = 0;
225
226 /* This would be a mem free() if we had malloc.*/
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000227 zeromem((void *)&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000228
Juan Castillo6e762062015-11-02 10:47:01 +0000229 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000230}
231
232
233/* Exported functions */
234
235/* Register the memmap driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100236int register_io_dev_memmap(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000237{
Juan Castillo6e762062015-11-02 10:47:01 +0000238 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000239 assert(dev_con != NULL);
240
241 result = io_register_device(&memmap_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000242 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000243 *dev_con = &memmap_dev_connector;
244
245 return result;
246}