1 /* 2 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <platform_def.h> 10 11 #include <drivers/io/io_driver.h> 12 #include <drivers/io/io_semihosting.h> 13 #include <drivers/io/io_storage.h> 14 #include <lib/semihosting.h> 15 16 /* Identify the device type as semihosting */ 17 static io_type_t device_type_sh(void) 18 { 19 return IO_TYPE_SEMIHOSTING; 20 } 21 22 23 /* Semi-hosting functions, device info and handle */ 24 25 static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 26 static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, 27 io_entity_t *entity); 28 static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset); 29 static int sh_file_len(io_entity_t *entity, size_t *length); 30 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 31 size_t *length_read); 32 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 33 size_t length, size_t *length_written); 34 static int sh_file_close(io_entity_t *entity); 35 36 static const io_dev_connector_t sh_dev_connector = { 37 .dev_open = sh_dev_open 38 }; 39 40 41 static const io_dev_funcs_t sh_dev_funcs = { 42 .type = device_type_sh, 43 .open = sh_file_open, 44 .seek = sh_file_seek, 45 .size = sh_file_len, 46 .read = sh_file_read, 47 .write = sh_file_write, 48 .close = sh_file_close, 49 .dev_init = NULL, /* NOP */ 50 .dev_close = NULL, /* NOP */ 51 }; 52 53 54 /* No state associated with this device so structure can be const */ 55 static const io_dev_info_t sh_dev_info = { 56 .funcs = &sh_dev_funcs, 57 .info = (uintptr_t)NULL 58 }; 59 60 61 /* Open a connection to the semi-hosting device */ 62 static int sh_dev_open(const uintptr_t dev_spec __unused, 63 io_dev_info_t **dev_info) 64 { 65 assert(dev_info != NULL); 66 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ 67 return 0; 68 } 69 70 71 /* Open a file on the semi-hosting device */ 72 static int sh_file_open(io_dev_info_t *dev_info __unused, 73 const uintptr_t spec, io_entity_t *entity) 74 { 75 int result = -ENOENT; 76 long sh_result; 77 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; 78 79 assert(file_spec != NULL); 80 assert(entity != NULL); 81 82 sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 83 84 if (sh_result > 0) { 85 entity->info = (uintptr_t)sh_result; 86 result = 0; 87 } 88 return result; 89 } 90 91 92 /* Seek to a particular file offset on the semi-hosting device */ 93 static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset) 94 { 95 long file_handle, sh_result; 96 97 assert(entity != NULL); 98 99 file_handle = (long)entity->info; 100 101 sh_result = semihosting_file_seek(file_handle, (ssize_t)offset); 102 103 return (sh_result == 0) ? 0 : -ENOENT; 104 } 105 106 107 /* Return the size of a file on the semi-hosting device */ 108 static int sh_file_len(io_entity_t *entity, size_t *length) 109 { 110 int result = -ENOENT; 111 112 assert(entity != NULL); 113 assert(length != NULL); 114 115 long sh_handle = (long)entity->info; 116 long sh_result = semihosting_file_length(sh_handle); 117 118 if (sh_result >= 0) { 119 result = 0; 120 *length = (size_t)sh_result; 121 } 122 123 return result; 124 } 125 126 127 /* Read data from a file on the semi-hosting device */ 128 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 129 size_t *length_read) 130 { 131 int result = -ENOENT; 132 long sh_result; 133 size_t bytes = length; 134 long file_handle; 135 136 assert(entity != NULL); 137 assert(length_read != NULL); 138 139 file_handle = (long)entity->info; 140 141 sh_result = semihosting_file_read(file_handle, &bytes, buffer); 142 143 if (sh_result >= 0) { 144 *length_read = (bytes != length) ? bytes : length; 145 result = 0; 146 } 147 148 return result; 149 } 150 151 152 /* Write data to a file on the semi-hosting device */ 153 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 154 size_t length, size_t *length_written) 155 { 156 long sh_result; 157 long file_handle; 158 size_t bytes = length; 159 160 assert(entity != NULL); 161 assert(length_written != NULL); 162 163 file_handle = (long)entity->info; 164 165 sh_result = semihosting_file_write(file_handle, &bytes, buffer); 166 167 *length_written = length - bytes; 168 169 return (sh_result == 0) ? 0 : -ENOENT; 170 } 171 172 173 /* Close a file on the semi-hosting device */ 174 static int sh_file_close(io_entity_t *entity) 175 { 176 long sh_result; 177 long file_handle; 178 179 assert(entity != NULL); 180 181 file_handle = (long)entity->info; 182 183 sh_result = semihosting_file_close(file_handle); 184 185 return (sh_result >= 0) ? 0 : -ENOENT; 186 } 187 188 189 /* Exported functions */ 190 191 /* Register the semi-hosting driver with the IO abstraction */ 192 int register_io_dev_sh(const io_dev_connector_t **dev_con) 193 { 194 int result; 195 assert(dev_con != NULL); 196 197 result = io_register_device(&sh_dev_info); 198 if (result == 0) 199 *dev_con = &sh_dev_connector; 200 201 return result; 202 } 203