blob: bf59d6a5c742cdcf93afb5ff1ac3e00ac9e4030e [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>
12#include <string.h>
Douglas Raillarda8954fc2017-01-26 15:54:44 +000013#include <utils.h>
Harry Liebel561cd332014-02-14 14:42:48 +000014
15/* As we need to be able to keep state for seek, only one file can be open
16 * at a time. Make this a structure and point to the entity->info. When we
17 * can malloc memory we can change this to support more open files.
18 */
19typedef struct {
20 /* Use the 'in_use' flag as any value for base and file_pos could be
21 * valid.
22 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010023 int in_use;
24 uintptr_t base;
25 size_t file_pos;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010026 size_t size;
Dan Handleye2712bc2014-04-10 15:37:22 +010027} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000028
Dan Handleye2712bc2014-04-10 15:37:22 +010029static file_state_t current_file = {0};
Harry Liebel561cd332014-02-14 14:42:48 +000030
31/* Identify the device type as memmap */
Roberto Vargas05712702018-02-12 12:36:17 +000032static io_type_t device_type_memmap(void)
Harry Liebel561cd332014-02-14 14:42:48 +000033{
34 return IO_TYPE_MEMMAP;
35}
36
37/* Memmap device functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010038static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
39static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010040 io_entity_t *entity);
41static int memmap_block_seek(io_entity_t *entity, int mode,
Harry Liebel561cd332014-02-14 14:42:48 +000042 ssize_t offset);
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010043static int memmap_block_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010044static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000045 size_t length, size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010046static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000047 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010048static int memmap_block_close(io_entity_t *entity);
49static int memmap_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000050
51
Dan Handleya4cb68e2014-04-23 13:47:06 +010052static const io_dev_connector_t memmap_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000053 .dev_open = memmap_dev_open
54};
55
56
Dan Handleya4cb68e2014-04-23 13:47:06 +010057static const io_dev_funcs_t memmap_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000058 .type = device_type_memmap,
59 .open = memmap_block_open,
60 .seek = memmap_block_seek,
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010061 .size = memmap_block_len,
Harry Liebel561cd332014-02-14 14:42:48 +000062 .read = memmap_block_read,
63 .write = memmap_block_write,
64 .close = memmap_block_close,
65 .dev_init = NULL,
66 .dev_close = memmap_dev_close,
67};
68
69
Dan Handleya4cb68e2014-04-23 13:47:06 +010070/* No state associated with this device so structure can be const */
71static const io_dev_info_t memmap_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000072 .funcs = &memmap_dev_funcs,
73 .info = (uintptr_t)NULL
74};
75
76
77/* Open a connection to the memmap device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080078static int memmap_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +010079 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000080{
81 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010082 *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +000083
Juan Castillo6e762062015-11-02 10:47:01 +000084 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000085}
86
87
88
89/* Close a connection to the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +010090static int memmap_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000091{
92 /* NOP */
93 /* TODO: Consider tracking open files and cleaning them up here */
Juan Castillo6e762062015-11-02 10:47:01 +000094 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000095}
96
97
98/* Open a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010099static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100100 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000101{
Juan Castillo6e762062015-11-02 10:47:01 +0000102 int result = -ENOMEM;
Dan Handleye2712bc2014-04-10 15:37:22 +0100103 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000104
105 /* Since we need to track open state for seek() we only allow one open
106 * spec at a time. When we have dynamic memory we can malloc and set
107 * entity->info.
108 */
109 if (current_file.in_use == 0) {
110 assert(block_spec != NULL);
111 assert(entity != NULL);
112
113 current_file.in_use = 1;
114 current_file.base = block_spec->offset;
115 /* File cursor offset for seek and incremental reads etc. */
116 current_file.file_pos = 0;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100117 current_file.size = block_spec->length;
Harry Liebel561cd332014-02-14 14:42:48 +0000118 entity->info = (uintptr_t)&current_file;
Juan Castillo6e762062015-11-02 10:47:01 +0000119 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000120 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000121 WARN("A Memmap device is already active. Close first.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000122 }
123
124 return result;
125}
126
127
128/* Seek to a particular file offset on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100129static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000130{
Juan Castillo6e762062015-11-02 10:47:01 +0000131 int result = -ENOENT;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000132 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000133
134 /* We only support IO_SEEK_SET for the moment. */
135 if (mode == IO_SEEK_SET) {
136 assert(entity != NULL);
137
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000138 fp = (file_state_t *) entity->info;
139
140 /* Assert that new file position is valid */
141 assert((offset >= 0) && (offset < fp->size));
142
143 /* Reset file position */
144 fp->file_pos = offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000145 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000146 }
147
148 return result;
149}
150
151
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100152/* Return the size of a file on the memmap device */
153static int memmap_block_len(io_entity_t *entity, size_t *length)
154{
155 assert(entity != NULL);
156 assert(length != NULL);
157
158 *length = ((file_state_t *)entity->info)->size;
159
160 return 0;
161}
162
163
Harry Liebel561cd332014-02-14 14:42:48 +0000164/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100165static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000166 size_t length, size_t *length_read)
167{
Dan Handleye2712bc2014-04-10 15:37:22 +0100168 file_state_t *fp;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000169 size_t pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000170
171 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100172 assert(buffer != (uintptr_t)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);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100200 assert(buffer != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000201 assert(length_written != NULL);
202
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000203 fp = (file_state_t *) entity->info;
204
205 /* Assert that file position is valid for this write operation */
206 pos_after = fp->file_pos + length;
207 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000208
Dan Handleya4cb68e2014-04-23 13:47:06 +0100209 memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
Harry Liebel561cd332014-02-14 14:42:48 +0000210
211 *length_written = length;
212
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000213 /* Set file position after write */
214 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000215
Juan Castillo6e762062015-11-02 10:47:01 +0000216 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000217}
218
219
220/* Close a file on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100221static int memmap_block_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000222{
223 assert(entity != NULL);
224
225 entity->info = 0;
226
227 /* This would be a mem free() if we had malloc.*/
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000228 zeromem((void *)&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000229
Juan Castillo6e762062015-11-02 10:47:01 +0000230 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000231}
232
233
234/* Exported functions */
235
236/* Register the memmap driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100237int register_io_dev_memmap(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000238{
Juan Castillo6e762062015-11-02 10:47:01 +0000239 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000240 assert(dev_con != NULL);
241
242 result = io_register_device(&memmap_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000243 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000244 *dev_con = &memmap_dev_connector;
245
246 return result;
247}