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 assert(dev_info != NULL); 88 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ 89 return 0; 90 } 91 92 93 /* Open a file on the semi-hosting device */ 94 static int sh_file_open(io_dev_info_t *dev_info __unused, 95 const uintptr_t spec, io_entity_t *entity) 96 { 97 int result = -ENOENT; 98 long sh_result; 99 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; 100 101 assert(file_spec != NULL); 102 assert(entity != NULL); 103 104 sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 105 106 if (sh_result > 0) { 107 entity->info = (uintptr_t)sh_result; 108 result = 0; 109 } 110 return result; 111 } 112 113 114 /* Seek to a particular file offset on the semi-hosting device */ 115 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset) 116 { 117 long file_handle, sh_result; 118 119 assert(entity != NULL); 120 121 file_handle = (long)entity->info; 122 123 sh_result = semihosting_file_seek(file_handle, offset); 124 125 return (sh_result == 0) ? 0 : -ENOENT; 126 } 127 128 129 /* Return the size of a file on the semi-hosting device */ 130 static int sh_file_len(io_entity_t *entity, size_t *length) 131 { 132 int result = -ENOENT; 133 134 assert(entity != NULL); 135 assert(length != NULL); 136 137 long sh_handle = (long)entity->info; 138 long sh_result = semihosting_file_length(sh_handle); 139 140 if (sh_result >= 0) { 141 result = 0; 142 *length = (size_t)sh_result; 143 } 144 145 return result; 146 } 147 148 149 /* Read data from a file on the semi-hosting device */ 150 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 151 size_t *length_read) 152 { 153 int result = -ENOENT; 154 long sh_result; 155 size_t bytes = length; 156 long file_handle; 157 158 assert(entity != NULL); 159 assert(buffer != (uintptr_t)NULL); 160 assert(length_read != NULL); 161 162 file_handle = (long)entity->info; 163 164 sh_result = semihosting_file_read(file_handle, &bytes, buffer); 165 166 if (sh_result >= 0) { 167 *length_read = (bytes != length) ? bytes : length; 168 result = 0; 169 } 170 171 return result; 172 } 173 174 175 /* Write data to a file on the semi-hosting device */ 176 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 177 size_t length, size_t *length_written) 178 { 179 long sh_result; 180 long file_handle; 181 size_t bytes = length; 182 183 assert(entity != NULL); 184 assert(buffer != (uintptr_t)NULL); 185 assert(length_written != NULL); 186 187 file_handle = (long)entity->info; 188 189 sh_result = semihosting_file_write(file_handle, &bytes, buffer); 190 191 *length_written = length - bytes; 192 193 return (sh_result == 0) ? 0 : -ENOENT; 194 } 195 196 197 /* Close a file on the semi-hosting device */ 198 static int sh_file_close(io_entity_t *entity) 199 { 200 long sh_result; 201 long file_handle; 202 203 assert(entity != NULL); 204 205 file_handle = (long)entity->info; 206 207 sh_result = semihosting_file_close(file_handle); 208 209 return (sh_result >= 0) ? 0 : -ENOENT; 210 } 211 212 213 /* Exported functions */ 214 215 /* Register the semi-hosting driver with the IO abstraction */ 216 int register_io_dev_sh(const io_dev_connector_t **dev_con) 217 { 218 int result; 219 assert(dev_con != NULL); 220 221 result = io_register_device(&sh_dev_info); 222 if (result == 0) 223 *dev_con = &sh_dev_connector; 224 225 return result; 226 } 227