blob: eb69163b70f990cd4dbddd43f1eb6d067a083d4b [file] [log] [blame]
Harry Liebel561cd332014-02-14 14:42:48 +00001/*
johpow0121031282020-07-01 17:09:57 -05002 * Copyright (c) 2014-2020, 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 Handley2bd4ef22014-04-09 13:14:54 +01008#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <platform_def.h>
11
12#include <common/debug.h>
13#include <drivers/io/io_driver.h>
14#include <drivers/io/io_memmap.h>
15#include <drivers/io/io_storage.h>
16#include <lib/utils.h>
Harry Liebel561cd332014-02-14 14:42:48 +000017
18/* As we need to be able to keep state for seek, only one file can be open
19 * at a time. Make this a structure and point to the entity->info. When we
20 * can malloc memory we can change this to support more open files.
21 */
22typedef struct {
23 /* Use the 'in_use' flag as any value for base and file_pos could be
24 * valid.
25 */
Yann Gautierf30cddc2019-04-16 11:35:19 +020026 int in_use;
27 uintptr_t base;
28 unsigned long long file_pos;
29 unsigned long long size;
johpow0121031282020-07-01 17:09:57 -050030} memmap_file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000031
johpow0121031282020-07-01 17:09:57 -050032static memmap_file_state_t current_memmap_file = {0};
Harry Liebel561cd332014-02-14 14:42:48 +000033
34/* Identify the device type as memmap */
Roberto Vargas05712702018-02-12 12:36:17 +000035static io_type_t device_type_memmap(void)
Harry Liebel561cd332014-02-14 14:42:48 +000036{
37 return IO_TYPE_MEMMAP;
38}
39
40/* Memmap device functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010041static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
42static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010043 io_entity_t *entity);
44static int memmap_block_seek(io_entity_t *entity, int mode,
Yann Gautierf30cddc2019-04-16 11:35:19 +020045 signed long long offset);
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010046static int memmap_block_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010047static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000048 size_t length, size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010049static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +000050 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010051static int memmap_block_close(io_entity_t *entity);
52static int memmap_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000053
54
Dan Handleya4cb68e2014-04-23 13:47:06 +010055static const io_dev_connector_t memmap_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000056 .dev_open = memmap_dev_open
57};
58
59
Dan Handleya4cb68e2014-04-23 13:47:06 +010060static const io_dev_funcs_t memmap_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000061 .type = device_type_memmap,
62 .open = memmap_block_open,
63 .seek = memmap_block_seek,
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +010064 .size = memmap_block_len,
Harry Liebel561cd332014-02-14 14:42:48 +000065 .read = memmap_block_read,
66 .write = memmap_block_write,
67 .close = memmap_block_close,
68 .dev_init = NULL,
69 .dev_close = memmap_dev_close,
70};
71
72
Dan Handleya4cb68e2014-04-23 13:47:06 +010073/* No state associated with this device so structure can be const */
johpow0121031282020-07-01 17:09:57 -050074static io_dev_info_t memmap_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000075 .funcs = &memmap_dev_funcs,
76 .info = (uintptr_t)NULL
77};
78
79
80/* Open a connection to the memmap device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080081static int memmap_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +010082 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000083{
84 assert(dev_info != NULL);
johpow0121031282020-07-01 17:09:57 -050085 *dev_info = &memmap_dev_info;
Juan Castillo6e762062015-11-02 10:47:01 +000086 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000087}
88
89
90
91/* Close a connection to the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +010092static int memmap_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +000093{
94 /* NOP */
95 /* TODO: Consider tracking open files and cleaning them up here */
Juan Castillo6e762062015-11-02 10:47:01 +000096 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +000097}
98
99
100/* Open a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100101static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100102 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000103{
Juan Castillo6e762062015-11-02 10:47:01 +0000104 int result = -ENOMEM;
Dan Handleye2712bc2014-04-10 15:37:22 +0100105 const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000106
107 /* Since we need to track open state for seek() we only allow one open
108 * spec at a time. When we have dynamic memory we can malloc and set
109 * entity->info.
110 */
johpow0121031282020-07-01 17:09:57 -0500111 if (current_memmap_file.in_use == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000112 assert(block_spec != NULL);
113 assert(entity != NULL);
114
johpow0121031282020-07-01 17:09:57 -0500115 current_memmap_file.in_use = 1;
116 current_memmap_file.base = block_spec->offset;
Harry Liebel561cd332014-02-14 14:42:48 +0000117 /* File cursor offset for seek and incremental reads etc. */
johpow0121031282020-07-01 17:09:57 -0500118 current_memmap_file.file_pos = 0;
119 current_memmap_file.size = block_spec->length;
120 entity->info = (uintptr_t)&current_memmap_file;
Juan Castillo6e762062015-11-02 10:47:01 +0000121 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000122 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000123 WARN("A Memmap device is already active. Close first.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000124 }
125
126 return result;
127}
128
129
130/* Seek to a particular file offset on the memmap device */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200131static int memmap_block_seek(io_entity_t *entity, int mode,
132 signed long long offset)
Harry Liebel561cd332014-02-14 14:42:48 +0000133{
Juan Castillo6e762062015-11-02 10:47:01 +0000134 int result = -ENOENT;
johpow0121031282020-07-01 17:09:57 -0500135 memmap_file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000136
137 /* We only support IO_SEEK_SET for the moment. */
138 if (mode == IO_SEEK_SET) {
139 assert(entity != NULL);
140
johpow0121031282020-07-01 17:09:57 -0500141 fp = (memmap_file_state_t *) entity->info;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000142
143 /* Assert that new file position is valid */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200144 assert((offset >= 0) &&
145 ((unsigned long long)offset < fp->size));
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000146
147 /* Reset file position */
Yann Gautierf30cddc2019-04-16 11:35:19 +0200148 fp->file_pos = (unsigned long long)offset;
Juan Castillo6e762062015-11-02 10:47:01 +0000149 result = 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000150 }
151
152 return result;
153}
154
155
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100156/* Return the size of a file on the memmap device */
157static int memmap_block_len(io_entity_t *entity, size_t *length)
158{
159 assert(entity != NULL);
160 assert(length != NULL);
161
johpow0121031282020-07-01 17:09:57 -0500162 *length = (size_t)((memmap_file_state_t *)entity->info)->size;
Gerald Lejeune2a1f2d12015-03-18 14:41:42 +0100163
164 return 0;
165}
166
167
Harry Liebel561cd332014-02-14 14:42:48 +0000168/* Read data from a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100169static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000170 size_t length, size_t *length_read)
171{
johpow0121031282020-07-01 17:09:57 -0500172 memmap_file_state_t *fp;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200173 unsigned long long pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000174
175 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000176 assert(length_read != NULL);
177
johpow0121031282020-07-01 17:09:57 -0500178 fp = (memmap_file_state_t *) entity->info;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000179
180 /* Assert that file position is valid for this read operation */
181 pos_after = fp->file_pos + length;
182 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000183
Yann Gautierf30cddc2019-04-16 11:35:19 +0200184 memcpy((void *)buffer,
185 (void *)((uintptr_t)(fp->base + fp->file_pos)), length);
Harry Liebel561cd332014-02-14 14:42:48 +0000186
187 *length_read = length;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000188
189 /* Set file position after read */
190 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000191
Juan Castillo6e762062015-11-02 10:47:01 +0000192 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000193}
194
195
196/* Write data to a file on the memmap device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100197static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
Harry Liebel561cd332014-02-14 14:42:48 +0000198 size_t length, size_t *length_written)
199{
johpow0121031282020-07-01 17:09:57 -0500200 memmap_file_state_t *fp;
Yann Gautierf30cddc2019-04-16 11:35:19 +0200201 unsigned long long pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000202
203 assert(entity != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000204 assert(length_written != NULL);
205
johpow0121031282020-07-01 17:09:57 -0500206 fp = (memmap_file_state_t *) entity->info;
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000207
208 /* Assert that file position is valid for this write operation */
209 pos_after = fp->file_pos + length;
210 assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
Harry Liebel561cd332014-02-14 14:42:48 +0000211
Yann Gautierf30cddc2019-04-16 11:35:19 +0200212 memcpy((void *)((uintptr_t)(fp->base + fp->file_pos)),
213 (void *)buffer, length);
Harry Liebel561cd332014-02-14 14:42:48 +0000214
215 *length_written = length;
216
Jeenu Viswambharane6bae8c2017-02-13 13:06:18 +0000217 /* Set file position after write */
218 fp->file_pos = pos_after;
Harry Liebel561cd332014-02-14 14:42:48 +0000219
Juan Castillo6e762062015-11-02 10:47:01 +0000220 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000221}
222
223
224/* Close a file on the memmap device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100225static int memmap_block_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000226{
227 assert(entity != NULL);
228
229 entity->info = 0;
230
231 /* This would be a mem free() if we had malloc.*/
johpow0121031282020-07-01 17:09:57 -0500232 zeromem((void *)&current_memmap_file, sizeof(current_memmap_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000233
Juan Castillo6e762062015-11-02 10:47:01 +0000234 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000235}
236
237
238/* Exported functions */
239
240/* Register the memmap driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100241int register_io_dev_memmap(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000242{
Juan Castillo6e762062015-11-02 10:47:01 +0000243 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000244 assert(dev_con != NULL);
245
246 result = io_register_device(&memmap_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000247 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000248 *dev_con = &memmap_dev_connector;
249
250 return result;
251}