1*4f6ad66aSAchin Gupta /* 2*4f6ad66aSAchin Gupta * Copyright (c) 2013, ARM Limited. All rights reserved. 3*4f6ad66aSAchin Gupta * 4*4f6ad66aSAchin Gupta * Redistribution and use in source and binary forms, with or without 5*4f6ad66aSAchin Gupta * modification, are permitted provided that the following conditions are met: 6*4f6ad66aSAchin Gupta * 7*4f6ad66aSAchin Gupta * Redistributions of source code must retain the above copyright notice, this 8*4f6ad66aSAchin Gupta * list of conditions and the following disclaimer. 9*4f6ad66aSAchin Gupta * 10*4f6ad66aSAchin Gupta * Redistributions in binary form must reproduce the above copyright notice, 11*4f6ad66aSAchin Gupta * this list of conditions and the following disclaimer in the documentation 12*4f6ad66aSAchin Gupta * and/or other materials provided with the distribution. 13*4f6ad66aSAchin Gupta * 14*4f6ad66aSAchin Gupta * Neither the name of ARM nor the names of its contributors may be used 15*4f6ad66aSAchin Gupta * to endorse or promote products derived from this software without specific 16*4f6ad66aSAchin Gupta * prior written permission. 17*4f6ad66aSAchin Gupta * 18*4f6ad66aSAchin Gupta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*4f6ad66aSAchin Gupta * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*4f6ad66aSAchin Gupta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*4f6ad66aSAchin Gupta * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*4f6ad66aSAchin Gupta * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*4f6ad66aSAchin Gupta * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*4f6ad66aSAchin Gupta * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*4f6ad66aSAchin Gupta * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*4f6ad66aSAchin Gupta * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*4f6ad66aSAchin Gupta * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*4f6ad66aSAchin Gupta * POSSIBILITY OF SUCH DAMAGE. 29*4f6ad66aSAchin Gupta */ 30*4f6ad66aSAchin Gupta 31*4f6ad66aSAchin Gupta #include <assert.h> 32*4f6ad66aSAchin Gupta #include <stdlib.h> 33*4f6ad66aSAchin Gupta #include <string.h> 34*4f6ad66aSAchin Gupta #include <errno.h> 35*4f6ad66aSAchin Gupta #include <semihosting.h> 36*4f6ad66aSAchin Gupta 37*4f6ad66aSAchin Gupta #ifndef SEMIHOSTING_SUPPORTED 38*4f6ad66aSAchin Gupta #define SEMIHOSTING_SUPPORTED 1 39*4f6ad66aSAchin Gupta #endif 40*4f6ad66aSAchin Gupta 41*4f6ad66aSAchin Gupta extern int semihosting_call(unsigned int operation, 42*4f6ad66aSAchin Gupta void *system_block_address); 43*4f6ad66aSAchin Gupta 44*4f6ad66aSAchin Gupta typedef struct { 45*4f6ad66aSAchin Gupta const char *file_name; 46*4f6ad66aSAchin Gupta unsigned int mode; 47*4f6ad66aSAchin Gupta unsigned int name_length; 48*4f6ad66aSAchin Gupta } smh_file_open_block; 49*4f6ad66aSAchin Gupta 50*4f6ad66aSAchin Gupta typedef struct { 51*4f6ad66aSAchin Gupta int handle; 52*4f6ad66aSAchin Gupta void *buffer; 53*4f6ad66aSAchin Gupta unsigned int length; 54*4f6ad66aSAchin Gupta } smh_file_read_write_block; 55*4f6ad66aSAchin Gupta 56*4f6ad66aSAchin Gupta typedef struct { 57*4f6ad66aSAchin Gupta int handle; 58*4f6ad66aSAchin Gupta unsigned int location; 59*4f6ad66aSAchin Gupta } smh_file_seek_block; 60*4f6ad66aSAchin Gupta 61*4f6ad66aSAchin Gupta typedef struct { 62*4f6ad66aSAchin Gupta char *command_line; 63*4f6ad66aSAchin Gupta unsigned int command_length; 64*4f6ad66aSAchin Gupta } smh_system_block; 65*4f6ad66aSAchin Gupta 66*4f6ad66aSAchin Gupta int semihosting_connection_supported(void) 67*4f6ad66aSAchin Gupta { 68*4f6ad66aSAchin Gupta return SEMIHOSTING_SUPPORTED; 69*4f6ad66aSAchin Gupta } 70*4f6ad66aSAchin Gupta 71*4f6ad66aSAchin Gupta int semihosting_file_open(const char *file_name, unsigned int mode) 72*4f6ad66aSAchin Gupta { 73*4f6ad66aSAchin Gupta smh_file_open_block open_block; 74*4f6ad66aSAchin Gupta 75*4f6ad66aSAchin Gupta open_block.file_name = file_name; 76*4f6ad66aSAchin Gupta open_block.mode = mode; 77*4f6ad66aSAchin Gupta open_block.name_length = strlen(file_name); 78*4f6ad66aSAchin Gupta 79*4f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_OPEN, 80*4f6ad66aSAchin Gupta (void *) &open_block); 81*4f6ad66aSAchin Gupta } 82*4f6ad66aSAchin Gupta 83*4f6ad66aSAchin Gupta int semihosting_file_seek(int file_handle, unsigned int offset) 84*4f6ad66aSAchin Gupta { 85*4f6ad66aSAchin Gupta smh_file_seek_block seek_block; 86*4f6ad66aSAchin Gupta int result; 87*4f6ad66aSAchin Gupta 88*4f6ad66aSAchin Gupta seek_block.handle = file_handle; 89*4f6ad66aSAchin Gupta seek_block.location = offset; 90*4f6ad66aSAchin Gupta 91*4f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_SEEK, 92*4f6ad66aSAchin Gupta (void *) &seek_block); 93*4f6ad66aSAchin Gupta 94*4f6ad66aSAchin Gupta if (result) 95*4f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); 96*4f6ad66aSAchin Gupta 97*4f6ad66aSAchin Gupta return result; 98*4f6ad66aSAchin Gupta } 99*4f6ad66aSAchin Gupta 100*4f6ad66aSAchin Gupta int semihosting_file_read(int file_handle, int *length, void *buffer) 101*4f6ad66aSAchin Gupta { 102*4f6ad66aSAchin Gupta smh_file_read_write_block read_block; 103*4f6ad66aSAchin Gupta int result = -EINVAL; 104*4f6ad66aSAchin Gupta 105*4f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 106*4f6ad66aSAchin Gupta return result; 107*4f6ad66aSAchin Gupta 108*4f6ad66aSAchin Gupta read_block.handle = file_handle; 109*4f6ad66aSAchin Gupta read_block.buffer = buffer; 110*4f6ad66aSAchin Gupta read_block.length = *length; 111*4f6ad66aSAchin Gupta 112*4f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_READ, 113*4f6ad66aSAchin Gupta (void *) &read_block); 114*4f6ad66aSAchin Gupta 115*4f6ad66aSAchin Gupta if (result == *length) { 116*4f6ad66aSAchin Gupta return -EINVAL; 117*4f6ad66aSAchin Gupta } else if (result < *length) { 118*4f6ad66aSAchin Gupta *length -= result; 119*4f6ad66aSAchin Gupta return 0; 120*4f6ad66aSAchin Gupta } else 121*4f6ad66aSAchin Gupta return result; 122*4f6ad66aSAchin Gupta } 123*4f6ad66aSAchin Gupta 124*4f6ad66aSAchin Gupta int semihosting_file_write(int file_handle, int *length, void *buffer) 125*4f6ad66aSAchin Gupta { 126*4f6ad66aSAchin Gupta smh_file_read_write_block write_block; 127*4f6ad66aSAchin Gupta 128*4f6ad66aSAchin Gupta if ((length == NULL) || (buffer == NULL)) 129*4f6ad66aSAchin Gupta return -EINVAL; 130*4f6ad66aSAchin Gupta 131*4f6ad66aSAchin Gupta write_block.handle = file_handle; 132*4f6ad66aSAchin Gupta write_block.buffer = buffer; 133*4f6ad66aSAchin Gupta write_block.length = *length; 134*4f6ad66aSAchin Gupta 135*4f6ad66aSAchin Gupta *length = semihosting_call(SEMIHOSTING_SYS_WRITE, 136*4f6ad66aSAchin Gupta (void *) &write_block); 137*4f6ad66aSAchin Gupta 138*4f6ad66aSAchin Gupta return *length; 139*4f6ad66aSAchin Gupta } 140*4f6ad66aSAchin Gupta 141*4f6ad66aSAchin Gupta int semihosting_file_close(int file_handle) 142*4f6ad66aSAchin Gupta { 143*4f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_CLOSE, 144*4f6ad66aSAchin Gupta (void *) &file_handle); 145*4f6ad66aSAchin Gupta } 146*4f6ad66aSAchin Gupta 147*4f6ad66aSAchin Gupta int semihosting_file_length(int file_handle) 148*4f6ad66aSAchin Gupta { 149*4f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_FLEN, 150*4f6ad66aSAchin Gupta (void *) &file_handle); 151*4f6ad66aSAchin Gupta } 152*4f6ad66aSAchin Gupta 153*4f6ad66aSAchin Gupta char semihosting_read_char(void) 154*4f6ad66aSAchin Gupta { 155*4f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_READC, NULL); 156*4f6ad66aSAchin Gupta } 157*4f6ad66aSAchin Gupta 158*4f6ad66aSAchin Gupta void semihosting_write_char(char character) 159*4f6ad66aSAchin Gupta { 160*4f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); 161*4f6ad66aSAchin Gupta } 162*4f6ad66aSAchin Gupta 163*4f6ad66aSAchin Gupta void semihosting_write_string(char *string) 164*4f6ad66aSAchin Gupta { 165*4f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); 166*4f6ad66aSAchin Gupta } 167*4f6ad66aSAchin Gupta 168*4f6ad66aSAchin Gupta int semihosting_system(char *command_line) 169*4f6ad66aSAchin Gupta { 170*4f6ad66aSAchin Gupta smh_system_block system_block; 171*4f6ad66aSAchin Gupta 172*4f6ad66aSAchin Gupta system_block.command_line = command_line; 173*4f6ad66aSAchin Gupta system_block.command_length = strlen(command_line); 174*4f6ad66aSAchin Gupta 175*4f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_SYSTEM, 176*4f6ad66aSAchin Gupta (void *) &system_block); 177*4f6ad66aSAchin Gupta } 178*4f6ad66aSAchin Gupta 179*4f6ad66aSAchin Gupta int semihosting_get_flen(const char *file_name) 180*4f6ad66aSAchin Gupta { 181*4f6ad66aSAchin Gupta int file_handle, length; 182*4f6ad66aSAchin Gupta 183*4f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 184*4f6ad66aSAchin Gupta 185*4f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 186*4f6ad66aSAchin Gupta if (file_handle == -1) 187*4f6ad66aSAchin Gupta return file_handle; 188*4f6ad66aSAchin Gupta 189*4f6ad66aSAchin Gupta /* Find the length of the file */ 190*4f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 191*4f6ad66aSAchin Gupta 192*4f6ad66aSAchin Gupta return semihosting_file_close(file_handle) ? -1 : length; 193*4f6ad66aSAchin Gupta } 194*4f6ad66aSAchin Gupta 195*4f6ad66aSAchin Gupta int semihosting_download_file(const char *file_name, 196*4f6ad66aSAchin Gupta int buf_size, 197*4f6ad66aSAchin Gupta void *buf) 198*4f6ad66aSAchin Gupta { 199*4f6ad66aSAchin Gupta int ret = -EINVAL, file_handle, length; 200*4f6ad66aSAchin Gupta 201*4f6ad66aSAchin Gupta /* Null pointer check */ 202*4f6ad66aSAchin Gupta if (!buf) 203*4f6ad66aSAchin Gupta return ret; 204*4f6ad66aSAchin Gupta 205*4f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 206*4f6ad66aSAchin Gupta 207*4f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 208*4f6ad66aSAchin Gupta if (file_handle == -1) 209*4f6ad66aSAchin Gupta return ret; 210*4f6ad66aSAchin Gupta 211*4f6ad66aSAchin Gupta /* Find the actual length of the file */ 212*4f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 213*4f6ad66aSAchin Gupta if (length == -1) 214*4f6ad66aSAchin Gupta goto semihosting_fail; 215*4f6ad66aSAchin Gupta 216*4f6ad66aSAchin Gupta /* Signal error if we do not have enough space for the file */ 217*4f6ad66aSAchin Gupta if (length > buf_size) 218*4f6ad66aSAchin Gupta goto semihosting_fail; 219*4f6ad66aSAchin Gupta 220*4f6ad66aSAchin Gupta /* 221*4f6ad66aSAchin Gupta * A successful read will return 0 in which case we pass back 222*4f6ad66aSAchin Gupta * the actual number of bytes read. Else we pass a negative 223*4f6ad66aSAchin Gupta * value indicating an error. 224*4f6ad66aSAchin Gupta */ 225*4f6ad66aSAchin Gupta ret = semihosting_file_read(file_handle, &length, buf); 226*4f6ad66aSAchin Gupta if (ret) 227*4f6ad66aSAchin Gupta goto semihosting_fail; 228*4f6ad66aSAchin Gupta else 229*4f6ad66aSAchin Gupta ret = length; 230*4f6ad66aSAchin Gupta 231*4f6ad66aSAchin Gupta semihosting_fail: 232*4f6ad66aSAchin Gupta semihosting_file_close(file_handle); 233*4f6ad66aSAchin Gupta return ret; 234*4f6ad66aSAchin Gupta } 235