• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <debug.h>
9 #include <io_driver.h>
10 #include <io_storage.h>
11 #include <string.h>
12 #include <utils.h>
13 
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  */
18 typedef struct {
19 	/* Use the 'in_use' flag as any value for base and file_pos could be
20 	 * valid.
21 	 */
22 	int		in_use;
23 	uintptr_t	base;
24 	size_t		file_pos;
25 	size_t		size;
26 } file_state_t;
27 
28 static file_state_t current_file = {0};
29 
30 /* Identify the device type as memmap */
device_type_memmap(void)31 io_type_t device_type_memmap(void)
32 {
33 	return IO_TYPE_MEMMAP;
34 }
35 
36 /* Memmap device functions */
37 static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
38 static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
39 			     io_entity_t *entity);
40 static int memmap_block_seek(io_entity_t *entity, int mode,
41 			     ssize_t offset);
42 static int memmap_block_len(io_entity_t *entity, size_t *length);
43 static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
44 			     size_t length, size_t *length_read);
45 static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
46 			      size_t length, size_t *length_written);
47 static int memmap_block_close(io_entity_t *entity);
48 static int memmap_dev_close(io_dev_info_t *dev_info);
49 
50 
51 static const io_dev_connector_t memmap_dev_connector = {
52 	.dev_open = memmap_dev_open
53 };
54 
55 
56 static const io_dev_funcs_t memmap_dev_funcs = {
57 	.type = device_type_memmap,
58 	.open = memmap_block_open,
59 	.seek = memmap_block_seek,
60 	.size = memmap_block_len,
61 	.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 
69 /* No state associated with this device so structure can be const */
70 static const io_dev_info_t memmap_dev_info = {
71 	.funcs = &memmap_dev_funcs,
72 	.info = (uintptr_t)NULL
73 };
74 
75 
76 /* Open a connection to the memmap device */
memmap_dev_open(const uintptr_t dev_spec __unused,io_dev_info_t ** dev_info)77 static int memmap_dev_open(const uintptr_t dev_spec __unused,
78 			   io_dev_info_t **dev_info)
79 {
80 	assert(dev_info != NULL);
81 	*dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
82 
83 	return 0;
84 }
85 
86 
87 
88 /* Close a connection to the memmap device */
memmap_dev_close(io_dev_info_t * dev_info)89 static int memmap_dev_close(io_dev_info_t *dev_info)
90 {
91 	/* NOP */
92 	/* TODO: Consider tracking open files and cleaning them up here */
93 	return 0;
94 }
95 
96 
97 /* Open a file on the memmap device */
memmap_block_open(io_dev_info_t * dev_info,const uintptr_t spec,io_entity_t * entity)98 static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
99 			     io_entity_t *entity)
100 {
101 	int result = -ENOMEM;
102 	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
103 
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;
116 		current_file.size = block_spec->length;
117 		entity->info = (uintptr_t)&current_file;
118 		result = 0;
119 	} else {
120 		WARN("A Memmap device is already active. Close first.\n");
121 	}
122 
123 	return result;
124 }
125 
126 
127 /* Seek to a particular file offset on the memmap device */
memmap_block_seek(io_entity_t * entity,int mode,ssize_t offset)128 static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
129 {
130 	int result = -ENOENT;
131 	file_state_t *fp;
132 
133 	/* We only support IO_SEEK_SET for the moment. */
134 	if (mode == IO_SEEK_SET) {
135 		assert(entity != NULL);
136 
137 		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;
144 		result = 0;
145 	}
146 
147 	return result;
148 }
149 
150 
151 /* Return the size of a file on the memmap device */
memmap_block_len(io_entity_t * entity,size_t * length)152 static 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 
163 /* Read data from a file on the memmap device */
memmap_block_read(io_entity_t * entity,uintptr_t buffer,size_t length,size_t * length_read)164 static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
165 			     size_t length, size_t *length_read)
166 {
167 	file_state_t *fp;
168 	size_t pos_after;
169 
170 	assert(entity != NULL);
171 	assert(buffer != (uintptr_t)NULL);
172 	assert(length_read != NULL);
173 
174 	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));
179 
180 	memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
181 
182 	*length_read = length;
183 
184 	/* Set file position after read */
185 	fp->file_pos = pos_after;
186 
187 	return 0;
188 }
189 
190 
191 /* Write data to a file on the memmap device */
memmap_block_write(io_entity_t * entity,const uintptr_t buffer,size_t length,size_t * length_written)192 static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
193 			      size_t length, size_t *length_written)
194 {
195 	file_state_t *fp;
196 	size_t pos_after;
197 
198 	assert(entity != NULL);
199 	assert(buffer != (uintptr_t)NULL);
200 	assert(length_written != NULL);
201 
202 	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));
207 
208 	memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
209 
210 	*length_written = length;
211 
212 	/* Set file position after write */
213 	fp->file_pos = pos_after;
214 
215 	return 0;
216 }
217 
218 
219 /* Close a file on the memmap device */
memmap_block_close(io_entity_t * entity)220 static int memmap_block_close(io_entity_t *entity)
221 {
222 	assert(entity != NULL);
223 
224 	entity->info = 0;
225 
226 	/* This would be a mem free() if we had malloc.*/
227 	zeromem((void *)&current_file, sizeof(current_file));
228 
229 	return 0;
230 }
231 
232 
233 /* Exported functions */
234 
235 /* Register the memmap driver with the IO abstraction */
register_io_dev_memmap(const io_dev_connector_t ** dev_con)236 int register_io_dev_memmap(const io_dev_connector_t **dev_con)
237 {
238 	int result;
239 	assert(dev_con != NULL);
240 
241 	result = io_register_device(&memmap_dev_info);
242 	if (result == 0)
243 		*dev_con = &memmap_dev_connector;
244 
245 	return result;
246 }
247