xref: /rk3399_ARM-atf/lib/semihosting/semihosting.c (revision 18ff0b61bb205e01d2c4dba23f1be5fd1081c6b4)
1 /*
2  * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10 
11 #include <lib/semihosting.h>
12 
13 #ifndef SEMIHOSTING_SUPPORTED
14 #define SEMIHOSTING_SUPPORTED  1
15 #endif
16 
17 long semihosting_call(unsigned long operation,
18 			void *system_block_address);
19 
20 typedef struct {
21 	const char *file_name;
22 	unsigned long mode;
23 	size_t name_length;
24 } smh_file_open_block_t;
25 
26 typedef struct {
27 	long handle;
28 	uintptr_t buffer;
29 	size_t length;
30 } smh_file_read_write_block_t;
31 
32 typedef struct {
33 	long handle;
34 	ssize_t location;
35 } smh_file_seek_block_t;
36 
37 typedef struct {
38 	char *command_line;
39 	size_t command_length;
40 } smh_system_block_t;
41 
42 long semihosting_connection_supported(void)
43 {
44 	return SEMIHOSTING_SUPPORTED;
45 }
46 
47 long semihosting_file_open(const char *file_name, size_t mode)
48 {
49 	smh_file_open_block_t open_block;
50 
51 	open_block.file_name = file_name;
52 	open_block.mode = mode;
53 	open_block.name_length = strlen(file_name);
54 
55 	return semihosting_call(SEMIHOSTING_SYS_OPEN,
56 				(void *) &open_block);
57 }
58 
59 long semihosting_file_seek(long file_handle, ssize_t offset)
60 {
61 	smh_file_seek_block_t seek_block;
62 	long result;
63 
64 	seek_block.handle = file_handle;
65 	seek_block.location = offset;
66 
67 	result = semihosting_call(SEMIHOSTING_SYS_SEEK,
68 				  (void *) &seek_block);
69 
70 	if (result)
71 		result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
72 
73 	return result;
74 }
75 
76 long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer)
77 {
78 	smh_file_read_write_block_t read_block;
79 	long result = -EINVAL;
80 
81 	if ((length == NULL) || (buffer == (uintptr_t)NULL))
82 		return result;
83 
84 	read_block.handle = file_handle;
85 	read_block.buffer = buffer;
86 	read_block.length = *length;
87 
88 	result = semihosting_call(SEMIHOSTING_SYS_READ,
89 				  (void *) &read_block);
90 
91 	if (result == *length) {
92 		return -EINVAL;
93 	} else if (result < *length) {
94 		*length -= result;
95 		return 0;
96 	} else
97 		return result;
98 }
99 
100 long semihosting_file_write(long file_handle,
101 			    size_t *length,
102 			    const uintptr_t buffer)
103 {
104 	smh_file_read_write_block_t write_block;
105 	long result = -EINVAL;
106 
107 	if ((length == NULL) || (buffer == (uintptr_t)NULL))
108 		return -EINVAL;
109 
110 	write_block.handle = file_handle;
111 	write_block.buffer = (uintptr_t)buffer; /* cast away const */
112 	write_block.length = *length;
113 
114 	result = semihosting_call(SEMIHOSTING_SYS_WRITE,
115 				   (void *) &write_block);
116 
117 	*length = result;
118 
119 	return (result == 0) ? 0 : -EINVAL;
120 }
121 
122 long semihosting_file_close(long file_handle)
123 {
124 	return semihosting_call(SEMIHOSTING_SYS_CLOSE,
125 				(void *) &file_handle);
126 }
127 
128 long semihosting_file_length(long file_handle)
129 {
130 	return semihosting_call(SEMIHOSTING_SYS_FLEN,
131 				(void *) &file_handle);
132 }
133 
134 char semihosting_read_char(void)
135 {
136 	return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
137 }
138 
139 void semihosting_write_char(char character)
140 {
141 	semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character);
142 }
143 
144 void semihosting_write_string(char *string)
145 {
146 	semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string);
147 }
148 
149 long semihosting_system(char *command_line)
150 {
151 	smh_system_block_t system_block;
152 
153 	system_block.command_line = command_line;
154 	system_block.command_length = strlen(command_line);
155 
156 	return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
157 				(void *) &system_block);
158 }
159 
160 long semihosting_get_flen(const char *file_name)
161 {
162 	long file_handle;
163 	long length;
164 
165 	assert(semihosting_connection_supported());
166 
167 	file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
168 	if (file_handle == -1)
169 		return file_handle;
170 
171 	/* Find the length of the file */
172 	length = semihosting_file_length(file_handle);
173 
174 	return semihosting_file_close(file_handle) ? -1 : length;
175 }
176 
177 long semihosting_download_file(const char *file_name,
178 			      size_t buf_size,
179 			      uintptr_t buf)
180 {
181 	long ret = -EINVAL;
182 	size_t length;
183 	long file_handle;
184 
185 	/* Null pointer check */
186 	if (!buf)
187 		return ret;
188 
189 	assert(semihosting_connection_supported());
190 
191 	file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
192 	if (file_handle == -1)
193 		return ret;
194 
195 	/* Find the actual length of the file */
196 	length = semihosting_file_length(file_handle);
197 	if (length == -1)
198 		goto semihosting_fail;
199 
200 	/* Signal error if we do not have enough space for the file */
201 	if (length > buf_size)
202 		goto semihosting_fail;
203 
204 	/*
205 	 * A successful read will return 0 in which case we pass back
206 	 * the actual number of bytes read. Else we pass a negative
207 	 * value indicating an error.
208 	 */
209 	ret = semihosting_file_read(file_handle, &length, buf);
210 	if (ret)
211 		goto semihosting_fail;
212 	else
213 		ret = length;
214 
215 semihosting_fail:
216 	semihosting_file_close(file_handle);
217 	return ret;
218 }
219