1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <string.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <platform_def.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <common/debug.h> 13*91f16700Schasinglulu #include <drivers/io/io_driver.h> 14*91f16700Schasinglulu #include <drivers/io/io_memmap.h> 15*91f16700Schasinglulu #include <drivers/io/io_storage.h> 16*91f16700Schasinglulu #include <lib/utils.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu /* As we need to be able to keep state for seek, only one file can be open 19*91f16700Schasinglulu * at a time. Make this a structure and point to the entity->info. When we 20*91f16700Schasinglulu * can malloc memory we can change this to support more open files. 21*91f16700Schasinglulu */ 22*91f16700Schasinglulu typedef struct { 23*91f16700Schasinglulu /* Use the 'in_use' flag as any value for base and file_pos could be 24*91f16700Schasinglulu * valid. 25*91f16700Schasinglulu */ 26*91f16700Schasinglulu int in_use; 27*91f16700Schasinglulu uintptr_t base; 28*91f16700Schasinglulu unsigned long long file_pos; 29*91f16700Schasinglulu unsigned long long size; 30*91f16700Schasinglulu } memmap_file_state_t; 31*91f16700Schasinglulu 32*91f16700Schasinglulu static memmap_file_state_t current_memmap_file = {0}; 33*91f16700Schasinglulu 34*91f16700Schasinglulu /* Identify the device type as memmap */ 35*91f16700Schasinglulu static io_type_t device_type_memmap(void) 36*91f16700Schasinglulu { 37*91f16700Schasinglulu return IO_TYPE_MEMMAP; 38*91f16700Schasinglulu } 39*91f16700Schasinglulu 40*91f16700Schasinglulu /* Memmap device functions */ 41*91f16700Schasinglulu static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 42*91f16700Schasinglulu static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 43*91f16700Schasinglulu io_entity_t *entity); 44*91f16700Schasinglulu static int memmap_block_seek(io_entity_t *entity, int mode, 45*91f16700Schasinglulu signed long long offset); 46*91f16700Schasinglulu static int memmap_block_len(io_entity_t *entity, size_t *length); 47*91f16700Schasinglulu static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 48*91f16700Schasinglulu size_t length, size_t *length_read); 49*91f16700Schasinglulu static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 50*91f16700Schasinglulu size_t length, size_t *length_written); 51*91f16700Schasinglulu static int memmap_block_close(io_entity_t *entity); 52*91f16700Schasinglulu static int memmap_dev_close(io_dev_info_t *dev_info); 53*91f16700Schasinglulu 54*91f16700Schasinglulu 55*91f16700Schasinglulu static const io_dev_connector_t memmap_dev_connector = { 56*91f16700Schasinglulu .dev_open = memmap_dev_open 57*91f16700Schasinglulu }; 58*91f16700Schasinglulu 59*91f16700Schasinglulu 60*91f16700Schasinglulu static const io_dev_funcs_t memmap_dev_funcs = { 61*91f16700Schasinglulu .type = device_type_memmap, 62*91f16700Schasinglulu .open = memmap_block_open, 63*91f16700Schasinglulu .seek = memmap_block_seek, 64*91f16700Schasinglulu .size = memmap_block_len, 65*91f16700Schasinglulu .read = memmap_block_read, 66*91f16700Schasinglulu .write = memmap_block_write, 67*91f16700Schasinglulu .close = memmap_block_close, 68*91f16700Schasinglulu .dev_init = NULL, 69*91f16700Schasinglulu .dev_close = memmap_dev_close, 70*91f16700Schasinglulu }; 71*91f16700Schasinglulu 72*91f16700Schasinglulu 73*91f16700Schasinglulu /* No state associated with this device so structure can be const */ 74*91f16700Schasinglulu static io_dev_info_t memmap_dev_info = { 75*91f16700Schasinglulu .funcs = &memmap_dev_funcs, 76*91f16700Schasinglulu .info = (uintptr_t)NULL 77*91f16700Schasinglulu }; 78*91f16700Schasinglulu 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* Open a connection to the memmap device */ 81*91f16700Schasinglulu static int memmap_dev_open(const uintptr_t dev_spec __unused, 82*91f16700Schasinglulu io_dev_info_t **dev_info) 83*91f16700Schasinglulu { 84*91f16700Schasinglulu assert(dev_info != NULL); 85*91f16700Schasinglulu *dev_info = &memmap_dev_info; 86*91f16700Schasinglulu return 0; 87*91f16700Schasinglulu } 88*91f16700Schasinglulu 89*91f16700Schasinglulu 90*91f16700Schasinglulu 91*91f16700Schasinglulu /* Close a connection to the memmap device */ 92*91f16700Schasinglulu static int memmap_dev_close(io_dev_info_t *dev_info) 93*91f16700Schasinglulu { 94*91f16700Schasinglulu /* NOP */ 95*91f16700Schasinglulu /* TODO: Consider tracking open files and cleaning them up here */ 96*91f16700Schasinglulu return 0; 97*91f16700Schasinglulu } 98*91f16700Schasinglulu 99*91f16700Schasinglulu 100*91f16700Schasinglulu /* Open a file on the memmap device */ 101*91f16700Schasinglulu static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 102*91f16700Schasinglulu io_entity_t *entity) 103*91f16700Schasinglulu { 104*91f16700Schasinglulu int result = -ENOMEM; 105*91f16700Schasinglulu const io_block_spec_t *block_spec = (io_block_spec_t *)spec; 106*91f16700Schasinglulu 107*91f16700Schasinglulu /* Since we need to track open state for seek() we only allow one open 108*91f16700Schasinglulu * spec at a time. When we have dynamic memory we can malloc and set 109*91f16700Schasinglulu * entity->info. 110*91f16700Schasinglulu */ 111*91f16700Schasinglulu if (current_memmap_file.in_use == 0) { 112*91f16700Schasinglulu assert(block_spec != NULL); 113*91f16700Schasinglulu assert(entity != NULL); 114*91f16700Schasinglulu 115*91f16700Schasinglulu current_memmap_file.in_use = 1; 116*91f16700Schasinglulu current_memmap_file.base = block_spec->offset; 117*91f16700Schasinglulu /* File cursor offset for seek and incremental reads etc. */ 118*91f16700Schasinglulu current_memmap_file.file_pos = 0; 119*91f16700Schasinglulu current_memmap_file.size = block_spec->length; 120*91f16700Schasinglulu entity->info = (uintptr_t)¤t_memmap_file; 121*91f16700Schasinglulu result = 0; 122*91f16700Schasinglulu } else { 123*91f16700Schasinglulu WARN("A Memmap device is already active. Close first.\n"); 124*91f16700Schasinglulu } 125*91f16700Schasinglulu 126*91f16700Schasinglulu return result; 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu 130*91f16700Schasinglulu /* Seek to a particular file offset on the memmap device */ 131*91f16700Schasinglulu static int memmap_block_seek(io_entity_t *entity, int mode, 132*91f16700Schasinglulu signed long long offset) 133*91f16700Schasinglulu { 134*91f16700Schasinglulu int result = -ENOENT; 135*91f16700Schasinglulu memmap_file_state_t *fp; 136*91f16700Schasinglulu 137*91f16700Schasinglulu /* We only support IO_SEEK_SET for the moment. */ 138*91f16700Schasinglulu if (mode == IO_SEEK_SET) { 139*91f16700Schasinglulu assert(entity != NULL); 140*91f16700Schasinglulu 141*91f16700Schasinglulu fp = (memmap_file_state_t *) entity->info; 142*91f16700Schasinglulu 143*91f16700Schasinglulu /* Assert that new file position is valid */ 144*91f16700Schasinglulu assert((offset >= 0) && 145*91f16700Schasinglulu ((unsigned long long)offset < fp->size)); 146*91f16700Schasinglulu 147*91f16700Schasinglulu /* Reset file position */ 148*91f16700Schasinglulu fp->file_pos = (unsigned long long)offset; 149*91f16700Schasinglulu result = 0; 150*91f16700Schasinglulu } 151*91f16700Schasinglulu 152*91f16700Schasinglulu return result; 153*91f16700Schasinglulu } 154*91f16700Schasinglulu 155*91f16700Schasinglulu 156*91f16700Schasinglulu /* Return the size of a file on the memmap device */ 157*91f16700Schasinglulu static int memmap_block_len(io_entity_t *entity, size_t *length) 158*91f16700Schasinglulu { 159*91f16700Schasinglulu assert(entity != NULL); 160*91f16700Schasinglulu assert(length != NULL); 161*91f16700Schasinglulu 162*91f16700Schasinglulu *length = (size_t)((memmap_file_state_t *)entity->info)->size; 163*91f16700Schasinglulu 164*91f16700Schasinglulu return 0; 165*91f16700Schasinglulu } 166*91f16700Schasinglulu 167*91f16700Schasinglulu 168*91f16700Schasinglulu /* Read data from a file on the memmap device */ 169*91f16700Schasinglulu static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 170*91f16700Schasinglulu size_t length, size_t *length_read) 171*91f16700Schasinglulu { 172*91f16700Schasinglulu memmap_file_state_t *fp; 173*91f16700Schasinglulu unsigned long long pos_after; 174*91f16700Schasinglulu 175*91f16700Schasinglulu assert(entity != NULL); 176*91f16700Schasinglulu assert(length_read != NULL); 177*91f16700Schasinglulu 178*91f16700Schasinglulu fp = (memmap_file_state_t *) entity->info; 179*91f16700Schasinglulu 180*91f16700Schasinglulu /* Assert that file position is valid for this read operation */ 181*91f16700Schasinglulu pos_after = fp->file_pos + length; 182*91f16700Schasinglulu assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 183*91f16700Schasinglulu 184*91f16700Schasinglulu memcpy((void *)buffer, 185*91f16700Schasinglulu (void *)((uintptr_t)(fp->base + fp->file_pos)), length); 186*91f16700Schasinglulu 187*91f16700Schasinglulu *length_read = length; 188*91f16700Schasinglulu 189*91f16700Schasinglulu /* Set file position after read */ 190*91f16700Schasinglulu fp->file_pos = pos_after; 191*91f16700Schasinglulu 192*91f16700Schasinglulu return 0; 193*91f16700Schasinglulu } 194*91f16700Schasinglulu 195*91f16700Schasinglulu 196*91f16700Schasinglulu /* Write data to a file on the memmap device */ 197*91f16700Schasinglulu static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 198*91f16700Schasinglulu size_t length, size_t *length_written) 199*91f16700Schasinglulu { 200*91f16700Schasinglulu memmap_file_state_t *fp; 201*91f16700Schasinglulu unsigned long long pos_after; 202*91f16700Schasinglulu 203*91f16700Schasinglulu assert(entity != NULL); 204*91f16700Schasinglulu assert(length_written != NULL); 205*91f16700Schasinglulu 206*91f16700Schasinglulu fp = (memmap_file_state_t *) entity->info; 207*91f16700Schasinglulu 208*91f16700Schasinglulu /* Assert that file position is valid for this write operation */ 209*91f16700Schasinglulu pos_after = fp->file_pos + length; 210*91f16700Schasinglulu assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 211*91f16700Schasinglulu 212*91f16700Schasinglulu memcpy((void *)((uintptr_t)(fp->base + fp->file_pos)), 213*91f16700Schasinglulu (void *)buffer, length); 214*91f16700Schasinglulu 215*91f16700Schasinglulu *length_written = length; 216*91f16700Schasinglulu 217*91f16700Schasinglulu /* Set file position after write */ 218*91f16700Schasinglulu fp->file_pos = pos_after; 219*91f16700Schasinglulu 220*91f16700Schasinglulu return 0; 221*91f16700Schasinglulu } 222*91f16700Schasinglulu 223*91f16700Schasinglulu 224*91f16700Schasinglulu /* Close a file on the memmap device */ 225*91f16700Schasinglulu static int memmap_block_close(io_entity_t *entity) 226*91f16700Schasinglulu { 227*91f16700Schasinglulu assert(entity != NULL); 228*91f16700Schasinglulu 229*91f16700Schasinglulu entity->info = 0; 230*91f16700Schasinglulu 231*91f16700Schasinglulu /* This would be a mem free() if we had malloc.*/ 232*91f16700Schasinglulu zeromem((void *)¤t_memmap_file, sizeof(current_memmap_file)); 233*91f16700Schasinglulu 234*91f16700Schasinglulu return 0; 235*91f16700Schasinglulu } 236*91f16700Schasinglulu 237*91f16700Schasinglulu 238*91f16700Schasinglulu /* Exported functions */ 239*91f16700Schasinglulu 240*91f16700Schasinglulu /* Register the memmap driver with the IO abstraction */ 241*91f16700Schasinglulu int register_io_dev_memmap(const io_dev_connector_t **dev_con) 242*91f16700Schasinglulu { 243*91f16700Schasinglulu int result; 244*91f16700Schasinglulu assert(dev_con != NULL); 245*91f16700Schasinglulu 246*91f16700Schasinglulu result = io_register_device(&memmap_dev_info); 247*91f16700Schasinglulu if (result == 0) 248*91f16700Schasinglulu *dev_con = &memmap_dev_connector; 249*91f16700Schasinglulu 250*91f16700Schasinglulu return result; 251*91f16700Schasinglulu } 252