1 /* 2 * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <platform_def.h> 10 11 #include <drivers/io/io_driver.h> 12 #include <drivers/io/io_semihosting.h> 13 #include <drivers/io/io_storage.h> 14 #include <lib/semihosting.h> 15 16 /* Identify the device type as semihosting */ 17 static io_type_t device_type_sh(void) 18 { 19 return IO_TYPE_SEMIHOSTING; 20 } 21 22 23 /* Semi-hosting functions, device info and handle */ 24 25 static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 26 static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, 27 io_entity_t *entity); 28 static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset); 29 static int sh_file_len(io_entity_t *entity, size_t *length); 30 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, 31 size_t *length_read); 32 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, 33 size_t length, size_t *length_written); 34 static int sh_file_close(io_entity_t *entity); 35 36 static const io_dev_connector_t sh_dev_connector = { 37 .dev_open = sh_dev_open 38 }; 39 40 41 static const io_dev_funcs_t sh_dev_funcs = { 42 .type = device_type_sh, 43 .open = sh_file_open, 44 .seek = sh_file_seek, 45 .size = sh_file_len, 46 .read = sh_file_read, 47 .write = sh_file_write, 48 .close = sh_file_close, 49 .dev_init = NULL, /* NOP */ 50 .dev_close = NULL, /* NOP */ 51 }; 52 53 54 static 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 = &sh_dev_info; 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, signed long long 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, (ssize_t)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(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(length_written != NULL); 161 162 file_handle = (long)entity->info; 163 164 sh_result = semihosting_file_write(file_handle, &bytes, buffer); 165 166 *length_written = length - bytes; 167 168 return (sh_result == 0) ? 0 : -ENOENT; 169 } 170 171 172 /* Close a file on the semi-hosting device */ 173 static int sh_file_close(io_entity_t *entity) 174 { 175 long sh_result; 176 long file_handle; 177 178 assert(entity != NULL); 179 180 file_handle = (long)entity->info; 181 182 sh_result = semihosting_file_close(file_handle); 183 184 return (sh_result >= 0) ? 0 : -ENOENT; 185 } 186 187 188 /* Exported functions */ 189 190 /* Register the semi-hosting driver with the IO abstraction */ 191 int register_io_dev_sh(const io_dev_connector_t **dev_con) 192 { 193 int result; 194 assert(dev_con != NULL); 195 196 result = io_register_device(&sh_dev_info); 197 if (result == 0) 198 *dev_con = &sh_dev_connector; 199 200 return result; 201 } 202