1 /* 2 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <semihosting.h> 10 #include <string.h> 11 12 #ifndef SEMIHOSTING_SUPPORTED 13 #define SEMIHOSTING_SUPPORTED 1 14 #endif 15 16 long semihosting_call(unsigned long operation, 17 void *system_block_address); 18 19 typedef struct { 20 const char *file_name; 21 unsigned long mode; 22 size_t name_length; 23 } smh_file_open_block_t; 24 25 typedef struct { 26 long handle; 27 uintptr_t buffer; 28 size_t length; 29 } smh_file_read_write_block_t; 30 31 typedef struct { 32 long handle; 33 ssize_t location; 34 } smh_file_seek_block_t; 35 36 typedef struct { 37 char *command_line; 38 size_t command_length; 39 } smh_system_block_t; 40 41 long semihosting_connection_supported(void) 42 { 43 return SEMIHOSTING_SUPPORTED; 44 } 45 46 long semihosting_file_open(const char *file_name, size_t mode) 47 { 48 smh_file_open_block_t open_block; 49 50 open_block.file_name = file_name; 51 open_block.mode = mode; 52 open_block.name_length = strlen(file_name); 53 54 return semihosting_call(SEMIHOSTING_SYS_OPEN, 55 (void *) &open_block); 56 } 57 58 long semihosting_file_seek(long file_handle, ssize_t offset) 59 { 60 smh_file_seek_block_t seek_block; 61 long result; 62 63 seek_block.handle = file_handle; 64 seek_block.location = offset; 65 66 result = semihosting_call(SEMIHOSTING_SYS_SEEK, 67 (void *) &seek_block); 68 69 if (result) 70 result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); 71 72 return result; 73 } 74 75 long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer) 76 { 77 smh_file_read_write_block_t read_block; 78 long result = -EINVAL; 79 80 if ((length == NULL) || (buffer == (uintptr_t)NULL)) 81 return result; 82 83 read_block.handle = file_handle; 84 read_block.buffer = buffer; 85 read_block.length = *length; 86 87 result = semihosting_call(SEMIHOSTING_SYS_READ, 88 (void *) &read_block); 89 90 if (result == *length) { 91 return -EINVAL; 92 } else if (result < *length) { 93 *length -= result; 94 return 0; 95 } else 96 return result; 97 } 98 99 long semihosting_file_write(long file_handle, 100 size_t *length, 101 const uintptr_t buffer) 102 { 103 smh_file_read_write_block_t write_block; 104 long result = -EINVAL; 105 106 if ((length == NULL) || (buffer == (uintptr_t)NULL)) 107 return -EINVAL; 108 109 write_block.handle = file_handle; 110 write_block.buffer = (uintptr_t)buffer; /* cast away const */ 111 write_block.length = *length; 112 113 result = semihosting_call(SEMIHOSTING_SYS_WRITE, 114 (void *) &write_block); 115 116 *length = result; 117 118 return (result == 0) ? 0 : -EINVAL; 119 } 120 121 long semihosting_file_close(long file_handle) 122 { 123 return semihosting_call(SEMIHOSTING_SYS_CLOSE, 124 (void *) &file_handle); 125 } 126 127 long semihosting_file_length(long file_handle) 128 { 129 return semihosting_call(SEMIHOSTING_SYS_FLEN, 130 (void *) &file_handle); 131 } 132 133 char semihosting_read_char(void) 134 { 135 return semihosting_call(SEMIHOSTING_SYS_READC, NULL); 136 } 137 138 void semihosting_write_char(char character) 139 { 140 semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); 141 } 142 143 void semihosting_write_string(char *string) 144 { 145 semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); 146 } 147 148 long semihosting_system(char *command_line) 149 { 150 smh_system_block_t system_block; 151 152 system_block.command_line = command_line; 153 system_block.command_length = strlen(command_line); 154 155 return semihosting_call(SEMIHOSTING_SYS_SYSTEM, 156 (void *) &system_block); 157 } 158 159 long semihosting_get_flen(const char *file_name) 160 { 161 long file_handle; 162 size_t length; 163 164 assert(semihosting_connection_supported()); 165 166 file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 167 if (file_handle == -1) 168 return file_handle; 169 170 /* Find the length of the file */ 171 length = semihosting_file_length(file_handle); 172 173 return semihosting_file_close(file_handle) ? -1 : length; 174 } 175 176 long semihosting_download_file(const char *file_name, 177 size_t buf_size, 178 uintptr_t buf) 179 { 180 long ret = -EINVAL; 181 size_t length; 182 long file_handle; 183 184 /* Null pointer check */ 185 if (!buf) 186 return ret; 187 188 assert(semihosting_connection_supported()); 189 190 file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 191 if (file_handle == -1) 192 return ret; 193 194 /* Find the actual length of the file */ 195 length = semihosting_file_length(file_handle); 196 if (length == -1) 197 goto semihosting_fail; 198 199 /* Signal error if we do not have enough space for the file */ 200 if (length > buf_size) 201 goto semihosting_fail; 202 203 /* 204 * A successful read will return 0 in which case we pass back 205 * the actual number of bytes read. Else we pass a negative 206 * value indicating an error. 207 */ 208 ret = semihosting_file_read(file_handle, &length, buf); 209 if (ret) 210 goto semihosting_fail; 211 else 212 ret = length; 213 214 semihosting_fail: 215 semihosting_file_close(file_handle); 216 return ret; 217 } 218