xref: /rk3399_ARM-atf/lib/semihosting/semihosting.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
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