1 /* 2 * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <io_driver.h> 33 #include <io_storage.h> 34 #include <semihosting.h> 35 36 37 38 /* Identify the device type as semihosting */ 39 static io_type_t device_type_sh(void) 40 { 41 return IO_TYPE_SEMIHOSTING; 42 } 43 44 45 /* Semi-hosting functions, device info and handle */ 46 47 static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 48 static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, 49 io_entity_t *entity); 50 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset); 51 static int sh_file_len(io_entity_t *entity, size_t *length); 52 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 53 size_t *length_read); 54 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 55 size_t length, size_t *length_written); 56 static int sh_file_close(io_entity_t *entity); 57 58 static const io_dev_connector_t sh_dev_connector = { 59 .dev_open = sh_dev_open 60 }; 61 62 63 static const io_dev_funcs_t sh_dev_funcs = { 64 .type = device_type_sh, 65 .open = sh_file_open, 66 .seek = sh_file_seek, 67 .size = sh_file_len, 68 .read = sh_file_read, 69 .write = sh_file_write, 70 .close = sh_file_close, 71 .dev_init = NULL, /* NOP */ 72 .dev_close = NULL, /* NOP */ 73 }; 74 75 76 /* No state associated with this device so structure can be const */ 77 static const io_dev_info_t sh_dev_info = { 78 .funcs = &sh_dev_funcs, 79 .info = (uintptr_t)NULL 80 }; 81 82 83 /* Open a connection to the semi-hosting device */ 84 static int sh_dev_open(const uintptr_t dev_spec __unused, 85 io_dev_info_t **dev_info) 86 { 87 int result = IO_SUCCESS; 88 assert(dev_info != NULL); 89 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ 90 return result; 91 } 92 93 94 /* Open a file on the semi-hosting device */ 95 static int sh_file_open(io_dev_info_t *dev_info __attribute__((unused)), 96 const uintptr_t spec, io_entity_t *entity) 97 { 98 int result = IO_FAIL; 99 long sh_result = -1; 100 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; 101 102 assert(file_spec != NULL); 103 assert(entity != NULL); 104 105 sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 106 107 if (sh_result > 0) { 108 entity->info = (uintptr_t)sh_result; 109 result = IO_SUCCESS; 110 } else { 111 result = IO_FAIL; 112 } 113 return result; 114 } 115 116 117 /* Seek to a particular file offset on the semi-hosting device */ 118 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset) 119 { 120 int result = IO_FAIL; 121 long file_handle, sh_result; 122 123 assert(entity != NULL); 124 125 file_handle = (long)entity->info; 126 127 sh_result = semihosting_file_seek(file_handle, offset); 128 129 result = (sh_result == 0) ? IO_SUCCESS : IO_FAIL; 130 131 return result; 132 } 133 134 135 /* Return the size of a file on the semi-hosting device */ 136 static int sh_file_len(io_entity_t *entity, size_t *length) 137 { 138 int result = IO_FAIL; 139 140 assert(entity != NULL); 141 assert(length != NULL); 142 143 long sh_handle = (long)entity->info; 144 long sh_result = semihosting_file_length(sh_handle); 145 146 if (sh_result >= 0) { 147 result = IO_SUCCESS; 148 *length = (size_t)sh_result; 149 } 150 151 return result; 152 } 153 154 155 /* Read data from a file on the semi-hosting device */ 156 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 157 size_t *length_read) 158 { 159 int result = IO_FAIL; 160 long sh_result = -1; 161 size_t bytes = length; 162 long file_handle; 163 164 assert(entity != NULL); 165 assert(buffer != (uintptr_t)NULL); 166 assert(length_read != NULL); 167 168 file_handle = (long)entity->info; 169 170 sh_result = semihosting_file_read(file_handle, &bytes, buffer); 171 172 if (sh_result >= 0) { 173 *length_read = (bytes != length) ? bytes : length; 174 result = IO_SUCCESS; 175 } else 176 result = IO_FAIL; 177 178 return result; 179 } 180 181 182 /* Write data to a file on the semi-hosting device */ 183 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 184 size_t length, size_t *length_written) 185 { 186 int result = IO_FAIL; 187 long sh_result = -1; 188 long file_handle; 189 size_t bytes = length; 190 191 assert(entity != NULL); 192 assert(buffer != (uintptr_t)NULL); 193 assert(length_written != NULL); 194 195 file_handle = (long)entity->info; 196 197 sh_result = semihosting_file_write(file_handle, &bytes, buffer); 198 199 if (sh_result >= 0) { 200 *length_written = sh_result; 201 result = IO_SUCCESS; 202 } else 203 result = IO_FAIL; 204 205 return result; 206 } 207 208 209 /* Close a file on the semi-hosting device */ 210 static int sh_file_close(io_entity_t *entity) 211 { 212 int result = IO_FAIL; 213 long sh_result = -1; 214 long file_handle; 215 216 assert(entity != NULL); 217 218 file_handle = (long)entity->info; 219 220 sh_result = semihosting_file_close(file_handle); 221 222 result = (sh_result >= 0) ? IO_SUCCESS : IO_FAIL; 223 224 return result; 225 } 226 227 228 /* Exported functions */ 229 230 /* Register the semi-hosting driver with the IO abstraction */ 231 int register_io_dev_sh(const io_dev_connector_t **dev_con) 232 { 233 int result = IO_FAIL; 234 assert(dev_con != NULL); 235 236 result = io_register_device(&sh_dev_info); 237 if (result == IO_SUCCESS) 238 *dev_con = &sh_dev_connector; 239 240 return result; 241 } 242