1 /* 2 * Copyright (c) 2014, 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_storage.h> 10 #include <semihosting.h> 11 12 13 14 /* Identify the device type as semihosting */ 15 static io_type_t device_type_sh(void) 16 { 17 return IO_TYPE_SEMIHOSTING; 18 } 19 20 21 /* Semi-hosting functions, device info and handle */ 22 23 static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 24 static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, 25 io_entity_t *entity); 26 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset); 27 static int sh_file_len(io_entity_t *entity, size_t *length); 28 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 29 size_t *length_read); 30 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 31 size_t length, size_t *length_written); 32 static int sh_file_close(io_entity_t *entity); 33 34 static const io_dev_connector_t sh_dev_connector = { 35 .dev_open = sh_dev_open 36 }; 37 38 39 static const io_dev_funcs_t sh_dev_funcs = { 40 .type = device_type_sh, 41 .open = sh_file_open, 42 .seek = sh_file_seek, 43 .size = sh_file_len, 44 .read = sh_file_read, 45 .write = sh_file_write, 46 .close = sh_file_close, 47 .dev_init = NULL, /* NOP */ 48 .dev_close = NULL, /* NOP */ 49 }; 50 51 52 /* No state associated with this device so structure can be const */ 53 static const io_dev_info_t sh_dev_info = { 54 .funcs = &sh_dev_funcs, 55 .info = (uintptr_t)NULL 56 }; 57 58 59 /* Open a connection to the semi-hosting device */ 60 static int sh_dev_open(const uintptr_t dev_spec __unused, 61 io_dev_info_t **dev_info) 62 { 63 assert(dev_info != NULL); 64 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ 65 return 0; 66 } 67 68 69 /* Open a file on the semi-hosting device */ 70 static int sh_file_open(io_dev_info_t *dev_info __unused, 71 const uintptr_t spec, io_entity_t *entity) 72 { 73 int result = -ENOENT; 74 long sh_result; 75 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; 76 77 assert(file_spec != NULL); 78 assert(entity != NULL); 79 80 sh_result = semihosting_file_open(file_spec->path, file_spec->mode); 81 82 if (sh_result > 0) { 83 entity->info = (uintptr_t)sh_result; 84 result = 0; 85 } 86 return result; 87 } 88 89 90 /* Seek to a particular file offset on the semi-hosting device */ 91 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset) 92 { 93 long file_handle, sh_result; 94 95 assert(entity != NULL); 96 97 file_handle = (long)entity->info; 98 99 sh_result = semihosting_file_seek(file_handle, offset); 100 101 return (sh_result == 0) ? 0 : -ENOENT; 102 } 103 104 105 /* Return the size of a file on the semi-hosting device */ 106 static int sh_file_len(io_entity_t *entity, size_t *length) 107 { 108 int result = -ENOENT; 109 110 assert(entity != NULL); 111 assert(length != NULL); 112 113 long sh_handle = (long)entity->info; 114 long sh_result = semihosting_file_length(sh_handle); 115 116 if (sh_result >= 0) { 117 result = 0; 118 *length = (size_t)sh_result; 119 } 120 121 return result; 122 } 123 124 125 /* Read data from a file on the semi-hosting device */ 126 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 127 size_t *length_read) 128 { 129 int result = -ENOENT; 130 long sh_result; 131 size_t bytes = length; 132 long file_handle; 133 134 assert(entity != NULL); 135 assert(buffer != (uintptr_t)NULL); 136 assert(length_read != NULL); 137 138 file_handle = (long)entity->info; 139 140 sh_result = semihosting_file_read(file_handle, &bytes, buffer); 141 142 if (sh_result >= 0) { 143 *length_read = (bytes != length) ? bytes : length; 144 result = 0; 145 } 146 147 return result; 148 } 149 150 151 /* Write data to a file on the semi-hosting device */ 152 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 153 size_t length, size_t *length_written) 154 { 155 long sh_result; 156 long file_handle; 157 size_t bytes = length; 158 159 assert(entity != NULL); 160 assert(buffer != (uintptr_t)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