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_storage.h> 33 #include <io_driver.h> 34 #include <semihosting.h> 35 36 37 38 /* Identify the device type as semihosting */ 39 static io_type 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(void *spec, struct io_dev_info **dev_info); 48 static int sh_file_open(struct io_dev_info *dev_info, const void *spec, 49 struct io_entity *entity); 50 static int sh_file_seek(struct io_entity *entity, int mode, ssize_t offset); 51 static int sh_file_len(struct io_entity *entity, size_t *length); 52 static int sh_file_read(struct io_entity *entity, void *buffer, size_t length, 53 size_t *length_read); 54 static int sh_file_write(struct io_entity *entity, const void *buffer, 55 size_t length, size_t *length_written); 56 static int sh_file_close(struct io_entity *entity); 57 58 static struct io_dev_connector sh_dev_connector = { 59 .dev_open = sh_dev_open 60 }; 61 62 63 static struct io_dev_funcs 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 static struct io_dev_info sh_dev_info = { 77 .funcs = &sh_dev_funcs, 78 .info = (uintptr_t)NULL 79 }; 80 81 82 /* Open a connection to the semi-hosting device */ 83 static int sh_dev_open(void *spec __unused, struct io_dev_info **dev_info) 84 { 85 int result = IO_SUCCESS; 86 assert(dev_info != NULL); 87 *dev_info = &sh_dev_info; 88 return result; 89 } 90 91 92 /* Open a file on the semi-hosting device */ 93 static int sh_file_open(struct io_dev_info *dev_info __attribute__((unused)), 94 const void *spec, struct io_entity *entity) 95 { 96 int result = IO_FAIL; 97 long sh_result = -1; 98 const io_file_spec *file_spec = (io_file_spec *)spec; 99 100 assert(file_spec != NULL); 101 assert(entity != NULL); 102 103 sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 104 105 if (sh_result > 0) { 106 entity->info = (uintptr_t)sh_result; 107 result = IO_SUCCESS; 108 } else { 109 result = IO_FAIL; 110 } 111 return result; 112 } 113 114 115 /* Seek to a particular file offset on the semi-hosting device */ 116 static int sh_file_seek(struct io_entity *entity, int mode, ssize_t offset) 117 { 118 int result = IO_FAIL; 119 long file_handle, sh_result; 120 121 assert(entity != NULL); 122 123 file_handle = (long)entity->info; 124 125 sh_result = semihosting_file_seek(file_handle, offset); 126 127 result = (sh_result == 0) ? IO_SUCCESS : IO_FAIL; 128 129 return result; 130 } 131 132 133 /* Return the size of a file on the semi-hosting device */ 134 static int sh_file_len(struct io_entity *entity, size_t *length) 135 { 136 int result = IO_FAIL; 137 138 assert(entity != NULL); 139 assert(length != NULL); 140 141 long sh_handle = (long)entity->info; 142 long sh_result = semihosting_file_length(sh_handle); 143 144 if (sh_result >= 0) { 145 result = IO_SUCCESS; 146 *length = (size_t)sh_result; 147 } 148 149 return result; 150 } 151 152 153 /* Read data from a file on the semi-hosting device */ 154 static int sh_file_read(struct io_entity *entity, void *buffer, size_t length, 155 size_t *length_read) 156 { 157 int result = IO_FAIL; 158 long sh_result = -1; 159 size_t bytes = length; 160 long file_handle; 161 162 assert(entity != NULL); 163 assert(buffer != NULL); 164 assert(length_read != NULL); 165 166 file_handle = (long)entity->info; 167 168 sh_result = semihosting_file_read(file_handle, &bytes, buffer); 169 170 if (sh_result >= 0) { 171 *length_read = (bytes != length) ? bytes : length; 172 result = IO_SUCCESS; 173 } else 174 result = IO_FAIL; 175 176 return result; 177 } 178 179 180 /* Write data to a file on the semi-hosting device */ 181 static int sh_file_write(struct io_entity *entity, const void *buffer, 182 size_t length, size_t *length_written) 183 { 184 int result = IO_FAIL; 185 long sh_result = -1; 186 long file_handle; 187 size_t bytes = length; 188 189 assert(entity != NULL); 190 assert(buffer != NULL); 191 assert(length_written != NULL); 192 193 file_handle = (long)entity->info; 194 195 sh_result = semihosting_file_write(file_handle, &bytes, buffer); 196 197 if (sh_result >= 0) { 198 *length_written = sh_result; 199 result = IO_SUCCESS; 200 } else 201 result = IO_FAIL; 202 203 return result; 204 } 205 206 207 /* Close a file on the semi-hosting device */ 208 static int sh_file_close(struct io_entity *entity) 209 { 210 int result = IO_FAIL; 211 long sh_result = -1; 212 long file_handle; 213 214 assert(entity != NULL); 215 216 file_handle = (long)entity->info; 217 218 sh_result = semihosting_file_close(file_handle); 219 220 result = (sh_result >= 0) ? IO_SUCCESS : IO_FAIL; 221 222 return result; 223 } 224 225 226 /* Exported functions */ 227 228 /* Register the semi-hosting driver with the IO abstraction */ 229 int register_io_dev_sh(struct io_dev_connector **dev_con) 230 { 231 int result = IO_FAIL; 232 assert(dev_con != NULL); 233 234 result = io_register_device(&sh_dev_info); 235 if (result == IO_SUCCESS) 236 *dev_con = &sh_dev_connector; 237 238 return result; 239 } 240