blob: 231040bfb6d399df4a5e162b9d828a466c849528 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +00009#include <drivers/io/io_driver.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020010#include <io_storage.h>
11#include <string.h>
12
13/* As we need to be able to keep state for seek, only one file can be open
14 * at a time. Make this a structure and point to the entity->info. When we
15 * can malloc memory we can change this to support more open files.
16 */
17typedef struct {
18 /* Use the 'in_use' flag as any value for base and file_pos could be
19 * valid.
20 */
21 int in_use;
22 uintptr_t base;
23 size_t file_pos;
24} file_state_t;
25
26static file_state_t current_file = {0};
27
28/* Identify the device type as memmap */
29io_type_t device_type_memmap(void)
30{
31 return IO_TYPE_MEMMAP;
32}
33
34/* Memmap device functions */
35static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
36static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
37 io_entity_t *entity);
38static int memmap_block_seek(io_entity_t *entity, int mode,
39 ssize_t offset);
40static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
41 size_t length, size_t *length_read);
42static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
43 size_t length, size_t *length_written);
44static int memmap_block_close(io_entity_t *entity);
45static int memmap_dev_close(io_dev_info_t *dev_info);
46
47
48static const io_dev_connector_t memmap_dev_connector = {
49 .dev_open = memmap_dev_open
50};
51
52
53static const io_dev_funcs_t memmap_dev_funcs = {
54 .type = device_type_memmap,
55 .open = memmap_block_open,
56 .seek = memmap_block_seek,
57 .size = NULL,
58 .read = memmap_block_read,
59 .write = memmap_block_write,
60 .close = memmap_block_close,
61 .dev_init = NULL,
62 .dev_close = memmap_dev_close,
63};
64
65
66/* No state associated with this device so structure can be const */
67static const io_dev_info_t memmap_dev_info = {
68 .funcs = &memmap_dev_funcs,
69 .info = (uintptr_t)NULL
70};
71
72
73/* Open a connection to the memmap device */
74static int memmap_dev_open(const uintptr_t dev_spec __attribute__((unused)),
75 io_dev_info_t **dev_info)
76{
77 assert(dev_info != NULL);
78 *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
79
80 return IO_SUCCESS;
81}
82
83
84
85/* Close a connection to the memmap device */
86static int memmap_dev_close(io_dev_info_t *dev_info)
87{
88 /* NOP */
89 /* TODO: Consider tracking open files and cleaning them up here */
90 return IO_SUCCESS;
91}
92
93
94/* Open a file on the memmap device */
95/* TODO: Can we do any sensible limit checks on requested memory */
96static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
97 io_entity_t *entity)
98{
99 int result = IO_FAIL;
100 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
101
102 /* Since we need to track open state for seek() we only allow one open
103 * spec at a time. When we have dynamic memory we can malloc and set
104 * entity->info.
105 */
106 if (current_file.in_use == 0) {
107 assert(block_spec != NULL);
108 assert(entity != NULL);
109
110 current_file.in_use = 1;
111 current_file.base = block_spec->offset;
112 /* File cursor offset for seek and incremental reads etc. */
113 current_file.file_pos = 0;
114 entity->info = (uintptr_t)&current_file;
115 result = IO_SUCCESS;
116 } else {
117 WARN("A Memmap device is already active. Close first.\n");
118 result = IO_RESOURCES_EXHAUSTED;
119 }
120
121 return result;
122}
123
124
125/* Seek to a particular file offset on the memmap device */
126static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
127{
128 int result = IO_FAIL;
129
130 /* We only support IO_SEEK_SET for the moment. */
131 if (mode == IO_SEEK_SET) {
132 assert(entity != NULL);
133
134 /* TODO: can we do some basic limit checks on seek? */
135 ((file_state_t *)entity->info)->file_pos = offset;
136 result = IO_SUCCESS;
137 } else {
138 result = IO_FAIL;
139 }
140
141 return result;
142}
143
144
145/* Read data from a file on the memmap device */
146static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
147 size_t length, size_t *length_read)
148{
149 file_state_t *fp;
150
151 assert(entity != NULL);
152 assert(buffer != (uintptr_t)NULL);
153 assert(length_read != NULL);
154
155 fp = (file_state_t *)entity->info;
156
157 memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
158
159 *length_read = length;
160 /* advance the file 'cursor' for incremental reads */
161 fp->file_pos += length;
162
163 return IO_SUCCESS;
164}
165
166
167/* Write data to a file on the memmap device */
168static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
169 size_t length, size_t *length_written)
170{
171 file_state_t *fp;
172
173 assert(entity != NULL);
174 assert(buffer != (uintptr_t)NULL);
175 assert(length_written != NULL);
176
177 fp = (file_state_t *)entity->info;
178
179 memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
180
181 *length_written = length;
182
183 /* advance the file 'cursor' for incremental writes */
184 fp->file_pos += length;
185
186 return IO_SUCCESS;
187}
188
189
190/* Close a file on the memmap device */
191static int memmap_block_close(io_entity_t *entity)
192{
193 assert(entity != NULL);
194
195 entity->info = 0;
196
197 /* This would be a mem free() if we had malloc.*/
198 memset((void *)&current_file, 0, sizeof(current_file));
199
200 return IO_SUCCESS;
201}
202
203
204/* Exported functions */
205
206/* Register the memmap driver with the IO abstraction */
207int register_io_dev_memmap(const io_dev_connector_t **dev_con)
208{
209 int result = IO_FAIL;
210 assert(dev_con != NULL);
211
212 result = io_register_device(&memmap_dev_info);
213 if (result == IO_SUCCESS)
214 *dev_con = &memmap_dev_connector;
215
216 return result;
217}