14f6ad66aSAchin Gupta /* 2e83b0cadSDan Handley * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 54f6ad66aSAchin Gupta */ 64f6ad66aSAchin Gupta 74f6ad66aSAchin Gupta #include <assert.h> 84f6ad66aSAchin Gupta #include <errno.h> 997043ac9SDan Handley #include <string.h> 104f6ad66aSAchin Gupta 11*09d40e0eSAntonio Nino Diaz #include <lib/semihosting.h> 12*09d40e0eSAntonio Nino Diaz 134f6ad66aSAchin Gupta #ifndef SEMIHOSTING_SUPPORTED 144f6ad66aSAchin Gupta #define SEMIHOSTING_SUPPORTED 1 154f6ad66aSAchin Gupta #endif 164f6ad66aSAchin Gupta 17c6bc0710SDan Handley long semihosting_call(unsigned long operation, 184f6ad66aSAchin Gupta void *system_block_address); 194f6ad66aSAchin Gupta 204f6ad66aSAchin Gupta typedef struct { 214f6ad66aSAchin Gupta const char *file_name; 22cd529320SRyan Harkin unsigned long mode; 23cd529320SRyan Harkin size_t name_length; 24fb037bfbSDan Handley } smh_file_open_block_t; 254f6ad66aSAchin Gupta 264f6ad66aSAchin Gupta typedef struct { 27cd529320SRyan Harkin long handle; 28625de1d4SDan Handley uintptr_t buffer; 29cd529320SRyan Harkin size_t length; 30fb037bfbSDan Handley } smh_file_read_write_block_t; 314f6ad66aSAchin Gupta 324f6ad66aSAchin Gupta typedef struct { 33cd529320SRyan Harkin long handle; 34cd529320SRyan Harkin ssize_t location; 35fb037bfbSDan Handley } smh_file_seek_block_t; 364f6ad66aSAchin Gupta 374f6ad66aSAchin Gupta typedef struct { 384f6ad66aSAchin Gupta char *command_line; 39cd529320SRyan Harkin size_t command_length; 40fb037bfbSDan Handley } smh_system_block_t; 414f6ad66aSAchin Gupta 42cd529320SRyan Harkin long semihosting_connection_supported(void) 434f6ad66aSAchin Gupta { 444f6ad66aSAchin Gupta return SEMIHOSTING_SUPPORTED; 454f6ad66aSAchin Gupta } 464f6ad66aSAchin Gupta 47cd529320SRyan Harkin long semihosting_file_open(const char *file_name, size_t mode) 484f6ad66aSAchin Gupta { 49fb037bfbSDan Handley smh_file_open_block_t open_block; 504f6ad66aSAchin Gupta 514f6ad66aSAchin Gupta open_block.file_name = file_name; 524f6ad66aSAchin Gupta open_block.mode = mode; 534f6ad66aSAchin Gupta open_block.name_length = strlen(file_name); 544f6ad66aSAchin Gupta 554f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_OPEN, 564f6ad66aSAchin Gupta (void *) &open_block); 574f6ad66aSAchin Gupta } 584f6ad66aSAchin Gupta 59cd529320SRyan Harkin long semihosting_file_seek(long file_handle, ssize_t offset) 604f6ad66aSAchin Gupta { 61fb037bfbSDan Handley smh_file_seek_block_t seek_block; 62cd529320SRyan Harkin long result; 634f6ad66aSAchin Gupta 644f6ad66aSAchin Gupta seek_block.handle = file_handle; 654f6ad66aSAchin Gupta seek_block.location = offset; 664f6ad66aSAchin Gupta 674f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_SEEK, 684f6ad66aSAchin Gupta (void *) &seek_block); 694f6ad66aSAchin Gupta 704f6ad66aSAchin Gupta if (result) 714f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); 724f6ad66aSAchin Gupta 734f6ad66aSAchin Gupta return result; 744f6ad66aSAchin Gupta } 754f6ad66aSAchin Gupta 76625de1d4SDan Handley long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer) 774f6ad66aSAchin Gupta { 78fb037bfbSDan Handley smh_file_read_write_block_t read_block; 79cd529320SRyan Harkin long result = -EINVAL; 804f6ad66aSAchin Gupta 81625de1d4SDan Handley if ((length == NULL) || (buffer == (uintptr_t)NULL)) 824f6ad66aSAchin Gupta return result; 834f6ad66aSAchin Gupta 844f6ad66aSAchin Gupta read_block.handle = file_handle; 854f6ad66aSAchin Gupta read_block.buffer = buffer; 864f6ad66aSAchin Gupta read_block.length = *length; 874f6ad66aSAchin Gupta 884f6ad66aSAchin Gupta result = semihosting_call(SEMIHOSTING_SYS_READ, 894f6ad66aSAchin Gupta (void *) &read_block); 904f6ad66aSAchin Gupta 914f6ad66aSAchin Gupta if (result == *length) { 924f6ad66aSAchin Gupta return -EINVAL; 934f6ad66aSAchin Gupta } else if (result < *length) { 944f6ad66aSAchin Gupta *length -= result; 954f6ad66aSAchin Gupta return 0; 964f6ad66aSAchin Gupta } else 974f6ad66aSAchin Gupta return result; 984f6ad66aSAchin Gupta } 994f6ad66aSAchin Gupta 100cd529320SRyan Harkin long semihosting_file_write(long file_handle, 101cd529320SRyan Harkin size_t *length, 102625de1d4SDan Handley const uintptr_t buffer) 1034f6ad66aSAchin Gupta { 104fb037bfbSDan Handley smh_file_read_write_block_t write_block; 10531833affSJuan Castillo long result = -EINVAL; 1064f6ad66aSAchin Gupta 107625de1d4SDan Handley if ((length == NULL) || (buffer == (uintptr_t)NULL)) 1084f6ad66aSAchin Gupta return -EINVAL; 1094f6ad66aSAchin Gupta 1104f6ad66aSAchin Gupta write_block.handle = file_handle; 111625de1d4SDan Handley write_block.buffer = (uintptr_t)buffer; /* cast away const */ 1124f6ad66aSAchin Gupta write_block.length = *length; 1134f6ad66aSAchin Gupta 11431833affSJuan Castillo result = semihosting_call(SEMIHOSTING_SYS_WRITE, 1154f6ad66aSAchin Gupta (void *) &write_block); 1164f6ad66aSAchin Gupta 11731833affSJuan Castillo *length = result; 11831833affSJuan Castillo 11931833affSJuan Castillo return (result == 0) ? 0 : -EINVAL; 1204f6ad66aSAchin Gupta } 1214f6ad66aSAchin Gupta 122cd529320SRyan Harkin long semihosting_file_close(long file_handle) 1234f6ad66aSAchin Gupta { 1244f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_CLOSE, 1254f6ad66aSAchin Gupta (void *) &file_handle); 1264f6ad66aSAchin Gupta } 1274f6ad66aSAchin Gupta 128cd529320SRyan Harkin long semihosting_file_length(long file_handle) 1294f6ad66aSAchin Gupta { 1304f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_FLEN, 1314f6ad66aSAchin Gupta (void *) &file_handle); 1324f6ad66aSAchin Gupta } 1334f6ad66aSAchin Gupta 1344f6ad66aSAchin Gupta char semihosting_read_char(void) 1354f6ad66aSAchin Gupta { 1364f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_READC, NULL); 1374f6ad66aSAchin Gupta } 1384f6ad66aSAchin Gupta 1394f6ad66aSAchin Gupta void semihosting_write_char(char character) 1404f6ad66aSAchin Gupta { 1414f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); 1424f6ad66aSAchin Gupta } 1434f6ad66aSAchin Gupta 1444f6ad66aSAchin Gupta void semihosting_write_string(char *string) 1454f6ad66aSAchin Gupta { 1464f6ad66aSAchin Gupta semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); 1474f6ad66aSAchin Gupta } 1484f6ad66aSAchin Gupta 149cd529320SRyan Harkin long semihosting_system(char *command_line) 1504f6ad66aSAchin Gupta { 151fb037bfbSDan Handley smh_system_block_t system_block; 1524f6ad66aSAchin Gupta 1534f6ad66aSAchin Gupta system_block.command_line = command_line; 1544f6ad66aSAchin Gupta system_block.command_length = strlen(command_line); 1554f6ad66aSAchin Gupta 1564f6ad66aSAchin Gupta return semihosting_call(SEMIHOSTING_SYS_SYSTEM, 1574f6ad66aSAchin Gupta (void *) &system_block); 1584f6ad66aSAchin Gupta } 1594f6ad66aSAchin Gupta 160cd529320SRyan Harkin long semihosting_get_flen(const char *file_name) 1614f6ad66aSAchin Gupta { 162cd529320SRyan Harkin long file_handle; 163cd529320SRyan Harkin size_t length; 1644f6ad66aSAchin Gupta 1654f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 1664f6ad66aSAchin Gupta 1674f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 1684f6ad66aSAchin Gupta if (file_handle == -1) 1694f6ad66aSAchin Gupta return file_handle; 1704f6ad66aSAchin Gupta 1714f6ad66aSAchin Gupta /* Find the length of the file */ 1724f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 1734f6ad66aSAchin Gupta 1744f6ad66aSAchin Gupta return semihosting_file_close(file_handle) ? -1 : length; 1754f6ad66aSAchin Gupta } 1764f6ad66aSAchin Gupta 177cd529320SRyan Harkin long semihosting_download_file(const char *file_name, 178cd529320SRyan Harkin size_t buf_size, 179625de1d4SDan Handley uintptr_t buf) 1804f6ad66aSAchin Gupta { 181cd529320SRyan Harkin long ret = -EINVAL; 182cd529320SRyan Harkin size_t length; 183cd529320SRyan Harkin long file_handle; 1844f6ad66aSAchin Gupta 1854f6ad66aSAchin Gupta /* Null pointer check */ 1864f6ad66aSAchin Gupta if (!buf) 1874f6ad66aSAchin Gupta return ret; 1884f6ad66aSAchin Gupta 1894f6ad66aSAchin Gupta assert(semihosting_connection_supported()); 1904f6ad66aSAchin Gupta 1914f6ad66aSAchin Gupta file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); 1924f6ad66aSAchin Gupta if (file_handle == -1) 1934f6ad66aSAchin Gupta return ret; 1944f6ad66aSAchin Gupta 1954f6ad66aSAchin Gupta /* Find the actual length of the file */ 1964f6ad66aSAchin Gupta length = semihosting_file_length(file_handle); 1974f6ad66aSAchin Gupta if (length == -1) 1984f6ad66aSAchin Gupta goto semihosting_fail; 1994f6ad66aSAchin Gupta 2004f6ad66aSAchin Gupta /* Signal error if we do not have enough space for the file */ 2014f6ad66aSAchin Gupta if (length > buf_size) 2024f6ad66aSAchin Gupta goto semihosting_fail; 2034f6ad66aSAchin Gupta 2044f6ad66aSAchin Gupta /* 2054f6ad66aSAchin Gupta * A successful read will return 0 in which case we pass back 2064f6ad66aSAchin Gupta * the actual number of bytes read. Else we pass a negative 2074f6ad66aSAchin Gupta * value indicating an error. 2084f6ad66aSAchin Gupta */ 2094f6ad66aSAchin Gupta ret = semihosting_file_read(file_handle, &length, buf); 2104f6ad66aSAchin Gupta if (ret) 2114f6ad66aSAchin Gupta goto semihosting_fail; 2124f6ad66aSAchin Gupta else 2134f6ad66aSAchin Gupta ret = length; 2144f6ad66aSAchin Gupta 2154f6ad66aSAchin Gupta semihosting_fail: 2164f6ad66aSAchin Gupta semihosting_file_close(file_handle); 2174f6ad66aSAchin Gupta return ret; 2184f6ad66aSAchin Gupta } 219