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