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 <string.h> 334f6ad66aSAchin Gupta #include <errno.h> 34cd529320SRyan Harkin #include <stdio.h> 354f6ad66aSAchin Gupta #include <semihosting.h> 364f6ad66aSAchin Gupta 374f6ad66aSAchin Gupta #ifndef SEMIHOSTING_SUPPORTED 384f6ad66aSAchin Gupta #define SEMIHOSTING_SUPPORTED 1 394f6ad66aSAchin Gupta #endif 404f6ad66aSAchin Gupta 41cd529320SRyan Harkin extern long semihosting_call(unsigned long operation, 424f6ad66aSAchin Gupta void *system_block_address); 434f6ad66aSAchin Gupta 444f6ad66aSAchin Gupta typedef struct { 454f6ad66aSAchin Gupta const char *file_name; 46cd529320SRyan Harkin unsigned long mode; 47cd529320SRyan Harkin size_t name_length; 48*fb037bfbSDan Handley } smh_file_open_block_t; 494f6ad66aSAchin Gupta 504f6ad66aSAchin Gupta typedef struct { 51cd529320SRyan Harkin long handle; 524f6ad66aSAchin Gupta void *buffer; 53cd529320SRyan Harkin size_t length; 54*fb037bfbSDan Handley } smh_file_read_write_block_t; 554f6ad66aSAchin Gupta 564f6ad66aSAchin Gupta typedef struct { 57cd529320SRyan Harkin long handle; 58cd529320SRyan Harkin ssize_t location; 59*fb037bfbSDan Handley } smh_file_seek_block_t; 604f6ad66aSAchin Gupta 614f6ad66aSAchin Gupta typedef struct { 624f6ad66aSAchin Gupta char *command_line; 63cd529320SRyan Harkin size_t command_length; 64*fb037bfbSDan Handley } smh_system_block_t; 654f6ad66aSAchin Gupta 66cd529320SRyan Harkin long semihosting_connection_supported(void) 674f6ad66aSAchin Gupta { 684f6ad66aSAchin Gupta return SEMIHOSTING_SUPPORTED; 694f6ad66aSAchin Gupta } 704f6ad66aSAchin Gupta 71cd529320SRyan Harkin long semihosting_file_open(const char *file_name, size_t mode) 724f6ad66aSAchin Gupta { 73*fb037bfbSDan Handley smh_file_open_block_t open_block; 744f6ad66aSAchin Gupta 754f6ad66aSAchin Gupta open_block.file_name = file_name; 764f6ad66aSAchin Gupta open_block.mode = mode; 774f6ad66aSAchin Gupta open_block.name_length = strlen(file_name); 784f6ad66aSAchin Gupta 794f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_OPEN, 804f6ad66aSAchin Gupta (void *) &open_block); 814f6ad66aSAchin Gupta } 824f6ad66aSAchin Gupta 83cd529320SRyan Harkin long semihosting_file_seek(long file_handle, ssize_t offset) 844f6ad66aSAchin Gupta { 85*fb037bfbSDan Handley smh_file_seek_block_t seek_block; 86cd529320SRyan Harkin long result; 874f6ad66aSAchin Gupta 884f6ad66aSAchin Gupta seek_block.handle = file_handle; 894f6ad66aSAchin Gupta seek_block.location = offset; 904f6ad66aSAchin Gupta 914f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_SEEK, 924f6ad66aSAchin Gupta (void *) &seek_block); 934f6ad66aSAchin Gupta 944f6ad66aSAchin Gupta if (result) 954f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); 964f6ad66aSAchin Gupta 974f6ad66aSAchin Gupta return result; 984f6ad66aSAchin Gupta } 994f6ad66aSAchin Gupta 100cd529320SRyan Harkin long semihosting_file_read(long file_handle, size_t *length, void *buffer) 1014f6ad66aSAchin Gupta { 102*fb037bfbSDan Handley smh_file_read_write_block_t read_block; 103cd529320SRyan Harkin long result = -EINVAL; 1044f6ad66aSAchin Gupta 1054f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 1064f6ad66aSAchin Gupta return result; 1074f6ad66aSAchin Gupta 1084f6ad66aSAchin Gupta read_block.handle = file_handle; 1094f6ad66aSAchin Gupta read_block.buffer = buffer; 1104f6ad66aSAchin Gupta read_block.length = *length; 1114f6ad66aSAchin Gupta 1124f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_READ, 1134f6ad66aSAchin Gupta (void *) &read_block); 1144f6ad66aSAchin Gupta 1154f6ad66aSAchin Gupta if (result == *length) { 1164f6ad66aSAchin Gupta return -EINVAL; 1174f6ad66aSAchin Gupta } else if (result < *length) { 1184f6ad66aSAchin Gupta *length -= result; 1194f6ad66aSAchin Gupta return 0; 1204f6ad66aSAchin Gupta } else 1214f6ad66aSAchin Gupta return result; 1224f6ad66aSAchin Gupta } 1234f6ad66aSAchin Gupta 124cd529320SRyan Harkin long semihosting_file_write(long file_handle, 125cd529320SRyan Harkin size_t *length, 126cd529320SRyan Harkin const void *buffer) 1274f6ad66aSAchin Gupta { 128*fb037bfbSDan Handley smh_file_read_write_block_t write_block; 1294f6ad66aSAchin Gupta 1304f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 1314f6ad66aSAchin Gupta return -EINVAL; 1324f6ad66aSAchin Gupta 1334f6ad66aSAchin Gupta write_block.handle = file_handle; 1349d72b4eaSJames Morrissey write_block.buffer = (void *)buffer; 1354f6ad66aSAchin Gupta write_block.length = *length; 1364f6ad66aSAchin Gupta 1374f6ad66aSAchin Gupta *length = semihosting_call(SEMIHOSTING_SYS_WRITE, 1384f6ad66aSAchin Gupta (void *) &write_block); 1394f6ad66aSAchin Gupta 1404f6ad66aSAchin Gupta return *length; 1414f6ad66aSAchin Gupta } 1424f6ad66aSAchin Gupta 143cd529320SRyan Harkin long semihosting_file_close(long file_handle) 1444f6ad66aSAchin Gupta { 1454f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_CLOSE, 1464f6ad66aSAchin Gupta (void *) &file_handle); 1474f6ad66aSAchin Gupta } 1484f6ad66aSAchin Gupta 149cd529320SRyan Harkin long semihosting_file_length(long file_handle) 1504f6ad66aSAchin Gupta { 1514f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_FLEN, 1524f6ad66aSAchin Gupta (void *) &file_handle); 1534f6ad66aSAchin Gupta } 1544f6ad66aSAchin Gupta 1554f6ad66aSAchin Gupta char semihosting_read_char(void) 1564f6ad66aSAchin Gupta { 1574f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_READC, NULL); 1584f6ad66aSAchin Gupta } 1594f6ad66aSAchin Gupta 1604f6ad66aSAchin Gupta void semihosting_write_char(char character) 1614f6ad66aSAchin Gupta { 1624f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); 1634f6ad66aSAchin Gupta } 1644f6ad66aSAchin Gupta 1654f6ad66aSAchin Gupta void semihosting_write_string(char *string) 1664f6ad66aSAchin Gupta { 1674f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); 1684f6ad66aSAchin Gupta } 1694f6ad66aSAchin Gupta 170cd529320SRyan Harkin long semihosting_system(char *command_line) 1714f6ad66aSAchin Gupta { 172*fb037bfbSDan Handley smh_system_block_t system_block; 1734f6ad66aSAchin Gupta 1744f6ad66aSAchin Gupta system_block.command_line = command_line; 1754f6ad66aSAchin Gupta system_block.command_length = strlen(command_line); 1764f6ad66aSAchin Gupta 1774f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_SYSTEM, 1784f6ad66aSAchin Gupta (void *) &system_block); 1794f6ad66aSAchin Gupta } 1804f6ad66aSAchin Gupta 181cd529320SRyan Harkin long semihosting_get_flen(const char *file_name) 1824f6ad66aSAchin Gupta { 183cd529320SRyan Harkin long file_handle; 184cd529320SRyan Harkin size_t length; 1854f6ad66aSAchin Gupta 1864f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 1874f6ad66aSAchin Gupta 1884f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 1894f6ad66aSAchin Gupta if (file_handle == -1) 1904f6ad66aSAchin Gupta return file_handle; 1914f6ad66aSAchin Gupta 1924f6ad66aSAchin Gupta /* Find the length of the file */ 1934f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 1944f6ad66aSAchin Gupta 1954f6ad66aSAchin Gupta return semihosting_file_close(file_handle) ? -1 : length; 1964f6ad66aSAchin Gupta } 1974f6ad66aSAchin Gupta 198cd529320SRyan Harkin long semihosting_download_file(const char *file_name, 199cd529320SRyan Harkin size_t buf_size, 2004f6ad66aSAchin Gupta void *buf) 2014f6ad66aSAchin Gupta { 202cd529320SRyan Harkin long ret = -EINVAL; 203cd529320SRyan Harkin size_t length; 204cd529320SRyan Harkin long file_handle; 2054f6ad66aSAchin Gupta 2064f6ad66aSAchin Gupta /* Null pointer check */ 2074f6ad66aSAchin Gupta if (!buf) 2084f6ad66aSAchin Gupta return ret; 2094f6ad66aSAchin Gupta 2104f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 2114f6ad66aSAchin Gupta 2124f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 2134f6ad66aSAchin Gupta if (file_handle == -1) 2144f6ad66aSAchin Gupta return ret; 2154f6ad66aSAchin Gupta 2164f6ad66aSAchin Gupta /* Find the actual length of the file */ 2174f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 2184f6ad66aSAchin Gupta if (length == -1) 2194f6ad66aSAchin Gupta goto semihosting_fail; 2204f6ad66aSAchin Gupta 2214f6ad66aSAchin Gupta /* Signal error if we do not have enough space for the file */ 2224f6ad66aSAchin Gupta if (length > buf_size) 2234f6ad66aSAchin Gupta goto semihosting_fail; 2244f6ad66aSAchin Gupta 2254f6ad66aSAchin Gupta /* 2264f6ad66aSAchin Gupta * A successful read will return 0 in which case we pass back 2274f6ad66aSAchin Gupta * the actual number of bytes read. Else we pass a negative 2284f6ad66aSAchin Gupta * value indicating an error. 2294f6ad66aSAchin Gupta */ 2304f6ad66aSAchin Gupta ret = semihosting_file_read(file_handle, &length, buf); 2314f6ad66aSAchin Gupta if (ret) 2324f6ad66aSAchin Gupta goto semihosting_fail; 2334f6ad66aSAchin Gupta else 2344f6ad66aSAchin Gupta ret = length; 2354f6ad66aSAchin Gupta 2364f6ad66aSAchin Gupta semihosting_fail: 2374f6ad66aSAchin Gupta semihosting_file_close(file_handle); 2384f6ad66aSAchin Gupta return ret; 2394f6ad66aSAchin Gupta } 240