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