1561cd33eSHarry Liebel /* 232f0d3c6SDouglas Raillard * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. 3561cd33eSHarry Liebel * 4*82cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5561cd33eSHarry Liebel */ 6561cd33eSHarry Liebel 7561cd33eSHarry Liebel #include <assert.h> 835e98e55SDan Handley #include <debug.h> 997043ac9SDan Handley #include <io_driver.h> 1097043ac9SDan Handley #include <io_storage.h> 1197043ac9SDan Handley #include <string.h> 1232f0d3c6SDouglas Raillard #include <utils.h> 13561cd33eSHarry Liebel 14561cd33eSHarry Liebel /* As we need to be able to keep state for seek, only one file can be open 15561cd33eSHarry Liebel * at a time. Make this a structure and point to the entity->info. When we 16561cd33eSHarry Liebel * can malloc memory we can change this to support more open files. 17561cd33eSHarry Liebel */ 18561cd33eSHarry Liebel typedef struct { 19561cd33eSHarry Liebel /* Use the 'in_use' flag as any value for base and file_pos could be 20561cd33eSHarry Liebel * valid. 21561cd33eSHarry Liebel */ 22561cd33eSHarry Liebel int in_use; 23625de1d4SDan Handley uintptr_t base; 24561cd33eSHarry Liebel size_t file_pos; 256d70bfa1SGerald Lejeune size_t size; 26fb037bfbSDan Handley } file_state_t; 27561cd33eSHarry Liebel 28fb037bfbSDan Handley static file_state_t current_file = {0}; 29561cd33eSHarry Liebel 30561cd33eSHarry Liebel /* Identify the device type as memmap */ 31fb037bfbSDan Handley io_type_t device_type_memmap(void) 32561cd33eSHarry Liebel { 33561cd33eSHarry Liebel return IO_TYPE_MEMMAP; 34561cd33eSHarry Liebel } 35561cd33eSHarry Liebel 36561cd33eSHarry Liebel /* Memmap device functions */ 37625de1d4SDan Handley static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 38625de1d4SDan Handley static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 39fb037bfbSDan Handley io_entity_t *entity); 40fb037bfbSDan Handley static int memmap_block_seek(io_entity_t *entity, int mode, 41561cd33eSHarry Liebel ssize_t offset); 426d70bfa1SGerald Lejeune static int memmap_block_len(io_entity_t *entity, size_t *length); 43625de1d4SDan Handley static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 44561cd33eSHarry Liebel size_t length, size_t *length_read); 45625de1d4SDan Handley static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 46561cd33eSHarry Liebel size_t length, size_t *length_written); 47fb037bfbSDan Handley static int memmap_block_close(io_entity_t *entity); 48fb037bfbSDan Handley static int memmap_dev_close(io_dev_info_t *dev_info); 49561cd33eSHarry Liebel 50561cd33eSHarry Liebel 51625de1d4SDan Handley static const io_dev_connector_t memmap_dev_connector = { 52561cd33eSHarry Liebel .dev_open = memmap_dev_open 53561cd33eSHarry Liebel }; 54561cd33eSHarry Liebel 55561cd33eSHarry Liebel 56625de1d4SDan Handley static const io_dev_funcs_t memmap_dev_funcs = { 57561cd33eSHarry Liebel .type = device_type_memmap, 58561cd33eSHarry Liebel .open = memmap_block_open, 59561cd33eSHarry Liebel .seek = memmap_block_seek, 606d70bfa1SGerald Lejeune .size = memmap_block_len, 61561cd33eSHarry Liebel .read = memmap_block_read, 62561cd33eSHarry Liebel .write = memmap_block_write, 63561cd33eSHarry Liebel .close = memmap_block_close, 64561cd33eSHarry Liebel .dev_init = NULL, 65561cd33eSHarry Liebel .dev_close = memmap_dev_close, 66561cd33eSHarry Liebel }; 67561cd33eSHarry Liebel 68561cd33eSHarry Liebel 69625de1d4SDan Handley /* No state associated with this device so structure can be const */ 70625de1d4SDan Handley static const io_dev_info_t memmap_dev_info = { 71561cd33eSHarry Liebel .funcs = &memmap_dev_funcs, 72561cd33eSHarry Liebel .info = (uintptr_t)NULL 73561cd33eSHarry Liebel }; 74561cd33eSHarry Liebel 75561cd33eSHarry Liebel 76561cd33eSHarry Liebel /* Open a connection to the memmap device */ 7765cd299fSSoren Brinkmann static int memmap_dev_open(const uintptr_t dev_spec __unused, 78fb037bfbSDan Handley io_dev_info_t **dev_info) 79561cd33eSHarry Liebel { 80561cd33eSHarry Liebel assert(dev_info != NULL); 81625de1d4SDan Handley *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */ 82561cd33eSHarry Liebel 83e098e244SJuan Castillo return 0; 84561cd33eSHarry Liebel } 85561cd33eSHarry Liebel 86561cd33eSHarry Liebel 87561cd33eSHarry Liebel 88561cd33eSHarry Liebel /* Close a connection to the memmap device */ 89fb037bfbSDan Handley static int memmap_dev_close(io_dev_info_t *dev_info) 90561cd33eSHarry Liebel { 91561cd33eSHarry Liebel /* NOP */ 92561cd33eSHarry Liebel /* TODO: Consider tracking open files and cleaning them up here */ 93e098e244SJuan Castillo return 0; 94561cd33eSHarry Liebel } 95561cd33eSHarry Liebel 96561cd33eSHarry Liebel 97561cd33eSHarry Liebel /* Open a file on the memmap device */ 98625de1d4SDan Handley static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 99fb037bfbSDan Handley io_entity_t *entity) 100561cd33eSHarry Liebel { 101e098e244SJuan Castillo int result = -ENOMEM; 102fb037bfbSDan Handley const io_block_spec_t *block_spec = (io_block_spec_t *)spec; 103561cd33eSHarry Liebel 104561cd33eSHarry Liebel /* Since we need to track open state for seek() we only allow one open 105561cd33eSHarry Liebel * spec at a time. When we have dynamic memory we can malloc and set 106561cd33eSHarry Liebel * entity->info. 107561cd33eSHarry Liebel */ 108561cd33eSHarry Liebel if (current_file.in_use == 0) { 109561cd33eSHarry Liebel assert(block_spec != NULL); 110561cd33eSHarry Liebel assert(entity != NULL); 111561cd33eSHarry Liebel 112561cd33eSHarry Liebel current_file.in_use = 1; 113561cd33eSHarry Liebel current_file.base = block_spec->offset; 114561cd33eSHarry Liebel /* File cursor offset for seek and incremental reads etc. */ 115561cd33eSHarry Liebel current_file.file_pos = 0; 1166d70bfa1SGerald Lejeune current_file.size = block_spec->length; 117561cd33eSHarry Liebel entity->info = (uintptr_t)¤t_file; 118e098e244SJuan Castillo result = 0; 119561cd33eSHarry Liebel } else { 12008c28d53SJeenu Viswambharan WARN("A Memmap device is already active. Close first.\n"); 121561cd33eSHarry Liebel } 122561cd33eSHarry Liebel 123561cd33eSHarry Liebel return result; 124561cd33eSHarry Liebel } 125561cd33eSHarry Liebel 126561cd33eSHarry Liebel 127561cd33eSHarry Liebel /* Seek to a particular file offset on the memmap device */ 128fb037bfbSDan Handley static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset) 129561cd33eSHarry Liebel { 130e098e244SJuan Castillo int result = -ENOENT; 13169c043b2SJeenu Viswambharan file_state_t *fp; 132561cd33eSHarry Liebel 133561cd33eSHarry Liebel /* We only support IO_SEEK_SET for the moment. */ 134561cd33eSHarry Liebel if (mode == IO_SEEK_SET) { 135561cd33eSHarry Liebel assert(entity != NULL); 136561cd33eSHarry Liebel 13769c043b2SJeenu Viswambharan fp = (file_state_t *) entity->info; 13869c043b2SJeenu Viswambharan 13969c043b2SJeenu Viswambharan /* Assert that new file position is valid */ 14069c043b2SJeenu Viswambharan assert((offset >= 0) && (offset < fp->size)); 14169c043b2SJeenu Viswambharan 14269c043b2SJeenu Viswambharan /* Reset file position */ 14369c043b2SJeenu Viswambharan fp->file_pos = offset; 144e098e244SJuan Castillo result = 0; 145561cd33eSHarry Liebel } 146561cd33eSHarry Liebel 147561cd33eSHarry Liebel return result; 148561cd33eSHarry Liebel } 149561cd33eSHarry Liebel 150561cd33eSHarry Liebel 1516d70bfa1SGerald Lejeune /* Return the size of a file on the memmap device */ 1526d70bfa1SGerald Lejeune static int memmap_block_len(io_entity_t *entity, size_t *length) 1536d70bfa1SGerald Lejeune { 1546d70bfa1SGerald Lejeune assert(entity != NULL); 1556d70bfa1SGerald Lejeune assert(length != NULL); 1566d70bfa1SGerald Lejeune 1576d70bfa1SGerald Lejeune *length = ((file_state_t *)entity->info)->size; 1586d70bfa1SGerald Lejeune 1596d70bfa1SGerald Lejeune return 0; 1606d70bfa1SGerald Lejeune } 1616d70bfa1SGerald Lejeune 1626d70bfa1SGerald Lejeune 163561cd33eSHarry Liebel /* Read data from a file on the memmap device */ 164625de1d4SDan Handley static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 165561cd33eSHarry Liebel size_t length, size_t *length_read) 166561cd33eSHarry Liebel { 167fb037bfbSDan Handley file_state_t *fp; 16869c043b2SJeenu Viswambharan size_t pos_after; 169561cd33eSHarry Liebel 170561cd33eSHarry Liebel assert(entity != NULL); 171625de1d4SDan Handley assert(buffer != (uintptr_t)NULL); 172561cd33eSHarry Liebel assert(length_read != NULL); 173561cd33eSHarry Liebel 174fb037bfbSDan Handley fp = (file_state_t *) entity->info; 175561cd33eSHarry Liebel 17669c043b2SJeenu Viswambharan /* Assert that file position is valid for this read operation */ 17769c043b2SJeenu Viswambharan pos_after = fp->file_pos + length; 17869c043b2SJeenu Viswambharan assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 17969c043b2SJeenu Viswambharan 180625de1d4SDan Handley memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length); 181561cd33eSHarry Liebel 182561cd33eSHarry Liebel *length_read = length; 18369c043b2SJeenu Viswambharan 18469c043b2SJeenu Viswambharan /* Set file position after read */ 18569c043b2SJeenu Viswambharan fp->file_pos = pos_after; 186561cd33eSHarry Liebel 187e098e244SJuan Castillo return 0; 188561cd33eSHarry Liebel } 189561cd33eSHarry Liebel 190561cd33eSHarry Liebel 191561cd33eSHarry Liebel /* Write data to a file on the memmap device */ 192625de1d4SDan Handley static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 193561cd33eSHarry Liebel size_t length, size_t *length_written) 194561cd33eSHarry Liebel { 195fb037bfbSDan Handley file_state_t *fp; 19669c043b2SJeenu Viswambharan size_t pos_after; 197561cd33eSHarry Liebel 198561cd33eSHarry Liebel assert(entity != NULL); 199625de1d4SDan Handley assert(buffer != (uintptr_t)NULL); 200561cd33eSHarry Liebel assert(length_written != NULL); 201561cd33eSHarry Liebel 202fb037bfbSDan Handley fp = (file_state_t *) entity->info; 203561cd33eSHarry Liebel 20469c043b2SJeenu Viswambharan /* Assert that file position is valid for this write operation */ 20569c043b2SJeenu Viswambharan pos_after = fp->file_pos + length; 20669c043b2SJeenu Viswambharan assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 20769c043b2SJeenu Viswambharan 208625de1d4SDan Handley memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length); 209561cd33eSHarry Liebel 210561cd33eSHarry Liebel *length_written = length; 211561cd33eSHarry Liebel 21269c043b2SJeenu Viswambharan /* Set file position after write */ 21369c043b2SJeenu Viswambharan fp->file_pos = pos_after; 214561cd33eSHarry Liebel 215e098e244SJuan Castillo return 0; 216561cd33eSHarry Liebel } 217561cd33eSHarry Liebel 218561cd33eSHarry Liebel 219561cd33eSHarry Liebel /* Close a file on the memmap device */ 220fb037bfbSDan Handley static int memmap_block_close(io_entity_t *entity) 221561cd33eSHarry Liebel { 222561cd33eSHarry Liebel assert(entity != NULL); 223561cd33eSHarry Liebel 224561cd33eSHarry Liebel entity->info = 0; 225561cd33eSHarry Liebel 226561cd33eSHarry Liebel /* This would be a mem free() if we had malloc.*/ 22732f0d3c6SDouglas Raillard zeromem((void *)¤t_file, sizeof(current_file)); 228561cd33eSHarry Liebel 229e098e244SJuan Castillo return 0; 230561cd33eSHarry Liebel } 231561cd33eSHarry Liebel 232561cd33eSHarry Liebel 233561cd33eSHarry Liebel /* Exported functions */ 234561cd33eSHarry Liebel 235561cd33eSHarry Liebel /* Register the memmap driver with the IO abstraction */ 236625de1d4SDan Handley int register_io_dev_memmap(const io_dev_connector_t **dev_con) 237561cd33eSHarry Liebel { 238e098e244SJuan Castillo int result; 239561cd33eSHarry Liebel assert(dev_con != NULL); 240561cd33eSHarry Liebel 241561cd33eSHarry Liebel result = io_register_device(&memmap_dev_info); 242e098e244SJuan Castillo if (result == 0) 243561cd33eSHarry Liebel *dev_con = &memmap_dev_connector; 244561cd33eSHarry Liebel 245561cd33eSHarry Liebel return result; 246561cd33eSHarry Liebel } 247