14f6ad66aSAchin Gupta /* 2e83b0cadSDan Handley * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 44f6ad66aSAchin Gupta * Redistribution and use in source and binary forms, with or without 54f6ad66aSAchin Gupta * modification, are permitted provided that the following conditions are met: 64f6ad66aSAchin Gupta * 74f6ad66aSAchin Gupta * Redistributions of source code must retain the above copyright notice, this 84f6ad66aSAchin Gupta * list of conditions and the following disclaimer. 94f6ad66aSAchin Gupta * 104f6ad66aSAchin Gupta * Redistributions in binary form must reproduce the above copyright notice, 114f6ad66aSAchin Gupta * this list of conditions and the following disclaimer in the documentation 124f6ad66aSAchin Gupta * and/or other materials provided with the distribution. 134f6ad66aSAchin Gupta * 144f6ad66aSAchin Gupta * Neither the name of ARM nor the names of its contributors may be used 154f6ad66aSAchin Gupta * to endorse or promote products derived from this software without specific 164f6ad66aSAchin Gupta * prior written permission. 174f6ad66aSAchin Gupta * 184f6ad66aSAchin Gupta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 194f6ad66aSAchin Gupta * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 204f6ad66aSAchin Gupta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 214f6ad66aSAchin Gupta * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 224f6ad66aSAchin Gupta * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 234f6ad66aSAchin Gupta * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 244f6ad66aSAchin Gupta * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 254f6ad66aSAchin Gupta * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 264f6ad66aSAchin Gupta * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 274f6ad66aSAchin Gupta * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 284f6ad66aSAchin Gupta * POSSIBILITY OF SUCH DAMAGE. 294f6ad66aSAchin Gupta */ 304f6ad66aSAchin Gupta 314f6ad66aSAchin Gupta #include <assert.h> 324f6ad66aSAchin Gupta #include <errno.h> 334f6ad66aSAchin Gupta #include <semihosting.h> 34*97043ac9SDan Handley #include <string.h> 354f6ad66aSAchin Gupta 364f6ad66aSAchin Gupta #ifndef SEMIHOSTING_SUPPORTED 374f6ad66aSAchin Gupta #define SEMIHOSTING_SUPPORTED 1 384f6ad66aSAchin Gupta #endif 394f6ad66aSAchin Gupta 40cd529320SRyan Harkin extern long semihosting_call(unsigned long operation, 414f6ad66aSAchin Gupta void *system_block_address); 424f6ad66aSAchin Gupta 434f6ad66aSAchin Gupta typedef struct { 444f6ad66aSAchin Gupta const char *file_name; 45cd529320SRyan Harkin unsigned long mode; 46cd529320SRyan Harkin size_t name_length; 47fb037bfbSDan Handley } smh_file_open_block_t; 484f6ad66aSAchin Gupta 494f6ad66aSAchin Gupta typedef struct { 50cd529320SRyan Harkin long handle; 514f6ad66aSAchin Gupta void *buffer; 52cd529320SRyan Harkin size_t length; 53fb037bfbSDan Handley } smh_file_read_write_block_t; 544f6ad66aSAchin Gupta 554f6ad66aSAchin Gupta typedef struct { 56cd529320SRyan Harkin long handle; 57cd529320SRyan Harkin ssize_t location; 58fb037bfbSDan Handley } smh_file_seek_block_t; 594f6ad66aSAchin Gupta 604f6ad66aSAchin Gupta typedef struct { 614f6ad66aSAchin Gupta char *command_line; 62cd529320SRyan Harkin size_t command_length; 63fb037bfbSDan Handley } smh_system_block_t; 644f6ad66aSAchin Gupta 65cd529320SRyan Harkin long semihosting_connection_supported(void) 664f6ad66aSAchin Gupta { 674f6ad66aSAchin Gupta return SEMIHOSTING_SUPPORTED; 684f6ad66aSAchin Gupta } 694f6ad66aSAchin Gupta 70cd529320SRyan Harkin long semihosting_file_open(const char *file_name, size_t mode) 714f6ad66aSAchin Gupta { 72fb037bfbSDan Handley smh_file_open_block_t open_block; 734f6ad66aSAchin Gupta 744f6ad66aSAchin Gupta open_block.file_name = file_name; 754f6ad66aSAchin Gupta open_block.mode = mode; 764f6ad66aSAchin Gupta open_block.name_length = strlen(file_name); 774f6ad66aSAchin Gupta 784f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_OPEN, 794f6ad66aSAchin Gupta (void *) &open_block); 804f6ad66aSAchin Gupta } 814f6ad66aSAchin Gupta 82cd529320SRyan Harkin long semihosting_file_seek(long file_handle, ssize_t offset) 834f6ad66aSAchin Gupta { 84fb037bfbSDan Handley smh_file_seek_block_t seek_block; 85cd529320SRyan Harkin long result; 864f6ad66aSAchin Gupta 874f6ad66aSAchin Gupta seek_block.handle = file_handle; 884f6ad66aSAchin Gupta seek_block.location = offset; 894f6ad66aSAchin Gupta 904f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_SEEK, 914f6ad66aSAchin Gupta (void *) &seek_block); 924f6ad66aSAchin Gupta 934f6ad66aSAchin Gupta if (result) 944f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); 954f6ad66aSAchin Gupta 964f6ad66aSAchin Gupta return result; 974f6ad66aSAchin Gupta } 984f6ad66aSAchin Gupta 99cd529320SRyan Harkin long semihosting_file_read(long file_handle, size_t *length, void *buffer) 1004f6ad66aSAchin Gupta { 101fb037bfbSDan Handley smh_file_read_write_block_t read_block; 102cd529320SRyan Harkin long result = -EINVAL; 1034f6ad66aSAchin Gupta 1044f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 1054f6ad66aSAchin Gupta return result; 1064f6ad66aSAchin Gupta 1074f6ad66aSAchin Gupta read_block.handle = file_handle; 1084f6ad66aSAchin Gupta read_block.buffer = buffer; 1094f6ad66aSAchin Gupta read_block.length = *length; 1104f6ad66aSAchin Gupta 1114f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_READ, 1124f6ad66aSAchin Gupta (void *) &read_block); 1134f6ad66aSAchin Gupta 1144f6ad66aSAchin Gupta if (result == *length) { 1154f6ad66aSAchin Gupta return -EINVAL; 1164f6ad66aSAchin Gupta } else if (result < *length) { 1174f6ad66aSAchin Gupta *length -= result; 1184f6ad66aSAchin Gupta return 0; 1194f6ad66aSAchin Gupta } else 1204f6ad66aSAchin Gupta return result; 1214f6ad66aSAchin Gupta } 1224f6ad66aSAchin Gupta 123cd529320SRyan Harkin long semihosting_file_write(long file_handle, 124cd529320SRyan Harkin size_t *length, 125cd529320SRyan Harkin const void *buffer) 1264f6ad66aSAchin Gupta { 127fb037bfbSDan Handley smh_file_read_write_block_t write_block; 1284f6ad66aSAchin Gupta 1294f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 1304f6ad66aSAchin Gupta return -EINVAL; 1314f6ad66aSAchin Gupta 1324f6ad66aSAchin Gupta write_block.handle = file_handle; 1339d72b4eaSJames Morrissey write_block.buffer = (void *)buffer; 1344f6ad66aSAchin Gupta write_block.length = *length; 1354f6ad66aSAchin Gupta 1364f6ad66aSAchin Gupta *length = semihosting_call(SEMIHOSTING_SYS_WRITE, 1374f6ad66aSAchin Gupta (void *) &write_block); 1384f6ad66aSAchin Gupta 1394f6ad66aSAchin Gupta return *length; 1404f6ad66aSAchin Gupta } 1414f6ad66aSAchin Gupta 142cd529320SRyan Harkin long semihosting_file_close(long file_handle) 1434f6ad66aSAchin Gupta { 1444f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_CLOSE, 1454f6ad66aSAchin Gupta (void *) &file_handle); 1464f6ad66aSAchin Gupta } 1474f6ad66aSAchin Gupta 148cd529320SRyan Harkin long semihosting_file_length(long file_handle) 1494f6ad66aSAchin Gupta { 1504f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_FLEN, 1514f6ad66aSAchin Gupta (void *) &file_handle); 1524f6ad66aSAchin Gupta } 1534f6ad66aSAchin Gupta 1544f6ad66aSAchin Gupta char semihosting_read_char(void) 1554f6ad66aSAchin Gupta { 1564f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_READC, NULL); 1574f6ad66aSAchin Gupta } 1584f6ad66aSAchin Gupta 1594f6ad66aSAchin Gupta void semihosting_write_char(char character) 1604f6ad66aSAchin Gupta { 1614f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); 1624f6ad66aSAchin Gupta } 1634f6ad66aSAchin Gupta 1644f6ad66aSAchin Gupta void semihosting_write_string(char *string) 1654f6ad66aSAchin Gupta { 1664f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); 1674f6ad66aSAchin Gupta } 1684f6ad66aSAchin Gupta 169cd529320SRyan Harkin long semihosting_system(char *command_line) 1704f6ad66aSAchin Gupta { 171fb037bfbSDan Handley smh_system_block_t system_block; 1724f6ad66aSAchin Gupta 1734f6ad66aSAchin Gupta system_block.command_line = command_line; 1744f6ad66aSAchin Gupta system_block.command_length = strlen(command_line); 1754f6ad66aSAchin Gupta 1764f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_SYSTEM, 1774f6ad66aSAchin Gupta (void *) &system_block); 1784f6ad66aSAchin Gupta } 1794f6ad66aSAchin Gupta 180cd529320SRyan Harkin long semihosting_get_flen(const char *file_name) 1814f6ad66aSAchin Gupta { 182cd529320SRyan Harkin long file_handle; 183cd529320SRyan Harkin size_t length; 1844f6ad66aSAchin Gupta 1854f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 1864f6ad66aSAchin Gupta 1874f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 1884f6ad66aSAchin Gupta if (file_handle == -1) 1894f6ad66aSAchin Gupta return file_handle; 1904f6ad66aSAchin Gupta 1914f6ad66aSAchin Gupta /* Find the length of the file */ 1924f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 1934f6ad66aSAchin Gupta 1944f6ad66aSAchin Gupta return semihosting_file_close(file_handle) ? -1 : length; 1954f6ad66aSAchin Gupta } 1964f6ad66aSAchin Gupta 197cd529320SRyan Harkin long semihosting_download_file(const char *file_name, 198cd529320SRyan Harkin size_t buf_size, 1994f6ad66aSAchin Gupta void *buf) 2004f6ad66aSAchin Gupta { 201cd529320SRyan Harkin long ret = -EINVAL; 202cd529320SRyan Harkin size_t length; 203cd529320SRyan Harkin long file_handle; 2044f6ad66aSAchin Gupta 2054f6ad66aSAchin Gupta /* Null pointer check */ 2064f6ad66aSAchin Gupta if (!buf) 2074f6ad66aSAchin Gupta return ret; 2084f6ad66aSAchin Gupta 2094f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 2104f6ad66aSAchin Gupta 2114f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 2124f6ad66aSAchin Gupta if (file_handle == -1) 2134f6ad66aSAchin Gupta return ret; 2144f6ad66aSAchin Gupta 2154f6ad66aSAchin Gupta /* Find the actual length of the file */ 2164f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 2174f6ad66aSAchin Gupta if (length == -1) 2184f6ad66aSAchin Gupta goto semihosting_fail; 2194f6ad66aSAchin Gupta 2204f6ad66aSAchin Gupta /* Signal error if we do not have enough space for the file */ 2214f6ad66aSAchin Gupta if (length > buf_size) 2224f6ad66aSAchin Gupta goto semihosting_fail; 2234f6ad66aSAchin Gupta 2244f6ad66aSAchin Gupta /* 2254f6ad66aSAchin Gupta * A successful read will return 0 in which case we pass back 2264f6ad66aSAchin Gupta * the actual number of bytes read. Else we pass a negative 2274f6ad66aSAchin Gupta * value indicating an error. 2284f6ad66aSAchin Gupta */ 2294f6ad66aSAchin Gupta ret = semihosting_file_read(file_handle, &length, buf); 2304f6ad66aSAchin Gupta if (ret) 2314f6ad66aSAchin Gupta goto semihosting_fail; 2324f6ad66aSAchin Gupta else 2334f6ad66aSAchin Gupta ret = length; 2344f6ad66aSAchin Gupta 2354f6ad66aSAchin Gupta semihosting_fail: 2364f6ad66aSAchin Gupta semihosting_file_close(file_handle); 2374f6ad66aSAchin Gupta return ret; 2384f6ad66aSAchin Gupta } 239