blob: 5595e60a424909a8a7b295b0bbbdaa17c98ddcc4 [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 Handley714a0d22014-04-09 13:13:04 +01008#include <debug.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01009#include <io_driver.h>
Roberto Vargas05712702018-02-12 12:36:17 +000010#include <io_memmap.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010011#include <io_storage.h>
Konstantin Porotchkinbfd04122018-05-07 12:52:48 +030012#include <platform_def.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010013#include <string.h>
Douglas Raillarda8954fc2017-01-26 15:54:44 +000014#include <utils.h>
Harry Liebel561cd332014-02-14 14:42:48 +000015
16/* As we need to be able to keep state for seek, only one file can be open
17 * at a time. Make this a structure and point to the entity->info. When we
18 * can malloc memory we can change this to support more open files.
19 */
20typedef struct {
21 /* Use the 'in_use' flag as any value for base and file_pos could be
22 * valid.
23 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010024 int in_use;
25 uintptr_t base;
26 size_t file_pos;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010027 size_t size;
Dan Handleye2712bc2014-04-10 15:37:22 +010028} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000029
Dan Handleye2712bc2014-04-10 15:37:22 +010030static file_state_t current_file = {0};
Harry Liebel561cd332014-02-14 14:42:48 +000031
32/* Identify the device type as memmap */
Roberto Vargas05712702018-02-12 12:36:17 +000033static io_type_t device_type_memmap(void)
Harry Liebel561cd332014-02-14 14:42:48 +000034{
35 return IO_TYPE_MEMMAP;
36}
37
38/* Memmap device functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010039static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
40static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010041 io_entity_t *entity);
42static int memmap_block_seek(io_entity_t *entity, int mode,
Harry Liebel561cd332014-02-14 14:42:48 +000043 ssize_t offset);
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010044static int memmap_block_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010045static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000046 size_t length, size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010047static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000048 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010049static int memmap_block_close(io_entity_t *entity);
50static int memmap_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000051
52
Dan Handleya4cb68e2014-04-23 13:47:06 +010053static const io_dev_connector_t memmap_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000054 .dev_open = memmap_dev_open
55};
56
57
Dan Handleya4cb68e2014-04-23 13:47:06 +010058static const io_dev_funcs_t memmap_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000059 .type = device_type_memmap,
60 .open = memmap_block_open,
61 .seek = memmap_block_seek,
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010062 .size = memmap_block_len,
Harry Liebel561cd332014-02-14 14:42:48 +000063 .read = memmap_block_read,
64 .write = memmap_block_write,
65 .close = memmap_block_close,
66 .dev_init = NULL,
67 .dev_close = memmap_dev_close,
68};
69
70
Dan Handleya4cb68e2014-04-23 13:47:06 +010071/* No state associated with this device so structure can be const */
72static const io_dev_info_t memmap_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000073 .funcs = &memmap_dev_funcs,
74 .info = (uintptr_t)NULL
75};
76
77
78/* Open a connection to the memmap device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080079static int memmap_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +010080 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000081{
82 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010083 *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +000084
Juan Castillo6e762062015-11-02 10:47:01 +000085 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000086}
87
88
89
90/* Close a connection to the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +010091static int memmap_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000092{
93 /* NOP */
94 /* TODO: Consider tracking open files and cleaning them up here */
Juan Castillo6e762062015-11-02 10:47:01 +000095 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000096}
97
98
99/* Open a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100100static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100101 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000102{
Juan Castillo6e762062015-11-02 10:47:01 +0000103 int result = -ENOMEM;
Dan Handleye2712bc2014-04-10 15:37:22 +0100104 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000105
106 /* Since we need to track open state for seek() we only allow one open
107 * spec at a time. When we have dynamic memory we can malloc and set
108 * entity->info.
109 */
110 if (current_file.in_use == 0) {
111 assert(block_spec != NULL);
112 assert(entity != NULL);
113
114 current_file.in_use = 1;
115 current_file.base = block_spec->offset;
116 /* File cursor offset for seek and incremental reads etc. */
117 current_file.file_pos = 0;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100118 current_file.size = block_spec->length;
Harry Liebel561cd332014-02-14 14:42:48 +0000119 entity->info = (uintptr_t)&current_file;
Juan Castillo6e762062015-11-02 10:47:01 +0000120 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000121 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000122 WARN("A Memmap device is already active. Close first.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000123 }
124
125 return result;
126}
127
128
129/* Seek to a particular file offset on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100130static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000131{
Juan Castillo6e762062015-11-02 10:47:01 +0000132 int result = -ENOENT;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000133 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000134
135 /* We only support IO_SEEK_SET for the moment. */
136 if (mode == IO_SEEK_SET) {
137 assert(entity != NULL);
138
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000139 fp = (file_state_t *) entity->info;
140
141 /* Assert that new file position is valid */
142 assert((offset >= 0) && (offset < fp->size));
143
144 /* Reset file position */
145 fp->file_pos = offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000146 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000147 }
148
149 return result;
150}
151
152
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100153/* Return the size of a file on the memmap device */
154static int memmap_block_len(io_entity_t *entity, size_t *length)
155{
156 assert(entity != NULL);
157 assert(length != NULL);
158
159 *length = ((file_state_t *)entity->info)->size;
160
161 return 0;
162}
163
164
Harry Liebel561cd332014-02-14 14:42:48 +0000165/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100166static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000167 size_t length, size_t *length_read)
168{
Dan Handleye2712bc2014-04-10 15:37:22 +0100169 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000170 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000171
172 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000173 assert(length_read != NULL);
174
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000175 fp = (file_state_t *) entity->info;
176
177 /* Assert that file position is valid for this read operation */
178 pos_after = fp->file_pos + length;
179 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000180
Dan Handleya4cb68e2014-04-23 13:47:06 +0100181 memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
Harry Liebel561cd332014-02-14 14:42:48 +0000182
183 *length_read = length;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000184
185 /* Set file position after read */
186 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000187
Juan Castillo6e762062015-11-02 10:47:01 +0000188 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000189}
190
191
192/* Write data to a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100193static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000194 size_t length, size_t *length_written)
195{
Dan Handleye2712bc2014-04-10 15:37:22 +0100196 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000197 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000198
199 assert(entity != 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}