blob: d5b8524b417f9960bd4d1f187e3c5bf31e5e8fc9 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handleye83b0ca2014-01-14 18:17:09 +00002 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <assert.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <string.h>
33#include <errno.h>
Ryan Harkincd529322014-02-10 17:17:04 +000034#include <stdio.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010035#include <semihosting.h>
36
37#ifndef SEMIHOSTING_SUPPORTED
38#define SEMIHOSTING_SUPPORTED 1
39#endif
40
Ryan Harkincd529322014-02-10 17:17:04 +000041extern long semihosting_call(unsigned long operation,
Achin Gupta4f6ad662013-10-25 09:08:21 +010042 void *system_block_address);
43
44typedef struct {
45 const char *file_name;
Ryan Harkincd529322014-02-10 17:17:04 +000046 unsigned long mode;
47 size_t name_length;
Achin Gupta4f6ad662013-10-25 09:08:21 +010048} smh_file_open_block;
49
50typedef struct {
Ryan Harkincd529322014-02-10 17:17:04 +000051 long handle;
Achin Gupta4f6ad662013-10-25 09:08:21 +010052 void *buffer;
Ryan Harkincd529322014-02-10 17:17:04 +000053 size_t length;
Achin Gupta4f6ad662013-10-25 09:08:21 +010054} smh_file_read_write_block;
55
56typedef struct {
Ryan Harkincd529322014-02-10 17:17:04 +000057 long handle;
58 ssize_t location;
Achin Gupta4f6ad662013-10-25 09:08:21 +010059} smh_file_seek_block;
60
61typedef struct {
62 char *command_line;
Ryan Harkincd529322014-02-10 17:17:04 +000063 size_t command_length;
Achin Gupta4f6ad662013-10-25 09:08:21 +010064} smh_system_block;
65
Ryan Harkincd529322014-02-10 17:17:04 +000066long semihosting_connection_supported(void)
Achin Gupta4f6ad662013-10-25 09:08:21 +010067{
68 return SEMIHOSTING_SUPPORTED;
69}
70
Ryan Harkincd529322014-02-10 17:17:04 +000071long semihosting_file_open(const char *file_name, size_t mode)
Achin Gupta4f6ad662013-10-25 09:08:21 +010072{
73 smh_file_open_block open_block;
74
75 open_block.file_name = file_name;
76 open_block.mode = mode;
77 open_block.name_length = strlen(file_name);
78
79 return semihosting_call(SEMIHOSTING_SYS_OPEN,
80 (void *) &open_block);
81}
82
Ryan Harkincd529322014-02-10 17:17:04 +000083long semihosting_file_seek(long file_handle, ssize_t offset)
Achin Gupta4f6ad662013-10-25 09:08:21 +010084{
85 smh_file_seek_block seek_block;
Ryan Harkincd529322014-02-10 17:17:04 +000086 long result;
Achin Gupta4f6ad662013-10-25 09:08:21 +010087
88 seek_block.handle = file_handle;
89 seek_block.location = offset;
90
91 result = semihosting_call(SEMIHOSTING_SYS_SEEK,
92 (void *) &seek_block);
93
94 if (result)
95 result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
96
97 return result;
98}
99
Ryan Harkincd529322014-02-10 17:17:04 +0000100long semihosting_file_read(long file_handle, size_t *length, void *buffer)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100101{
102 smh_file_read_write_block read_block;
Ryan Harkincd529322014-02-10 17:17:04 +0000103 long result = -EINVAL;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100104
105 if ((length == NULL) || (buffer == NULL))
106 return result;
107
108 read_block.handle = file_handle;
109 read_block.buffer = buffer;
110 read_block.length = *length;
111
112 result = semihosting_call(SEMIHOSTING_SYS_READ,
113 (void *) &read_block);
114
115 if (result == *length) {
116 return -EINVAL;
117 } else if (result < *length) {
118 *length -= result;
119 return 0;
120 } else
121 return result;
122}
123
Ryan Harkincd529322014-02-10 17:17:04 +0000124long semihosting_file_write(long file_handle,
125 size_t *length,
126 const void *buffer)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100127{
128 smh_file_read_write_block write_block;
129
130 if ((length == NULL) || (buffer == NULL))
131 return -EINVAL;
132
133 write_block.handle = file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000134 write_block.buffer = (void *)buffer;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100135 write_block.length = *length;
136
137 *length = semihosting_call(SEMIHOSTING_SYS_WRITE,
138 (void *) &write_block);
139
140 return *length;
141}
142
Ryan Harkincd529322014-02-10 17:17:04 +0000143long semihosting_file_close(long file_handle)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100144{
145 return semihosting_call(SEMIHOSTING_SYS_CLOSE,
146 (void *) &file_handle);
147}
148
Ryan Harkincd529322014-02-10 17:17:04 +0000149long semihosting_file_length(long file_handle)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100150{
151 return semihosting_call(SEMIHOSTING_SYS_FLEN,
152 (void *) &file_handle);
153}
154
155char semihosting_read_char(void)
156{
157 return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
158}
159
160void semihosting_write_char(char character)
161{
162 semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character);
163}
164
165void semihosting_write_string(char *string)
166{
167 semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string);
168}
169
Ryan Harkincd529322014-02-10 17:17:04 +0000170long semihosting_system(char *command_line)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100171{
172 smh_system_block system_block;
173
174 system_block.command_line = command_line;
175 system_block.command_length = strlen(command_line);
176
177 return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
178 (void *) &system_block);
179}
180
Ryan Harkincd529322014-02-10 17:17:04 +0000181long semihosting_get_flen(const char *file_name)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100182{
Ryan Harkincd529322014-02-10 17:17:04 +0000183 long file_handle;
184 size_t length;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100185
186 assert(semihosting_connection_supported());
187
188 file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
189 if (file_handle == -1)
190 return file_handle;
191
192 /* Find the length of the file */
193 length = semihosting_file_length(file_handle);
194
195 return semihosting_file_close(file_handle) ? -1 : length;
196}
197
Ryan Harkincd529322014-02-10 17:17:04 +0000198long semihosting_download_file(const char *file_name,
199 size_t buf_size,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100200 void *buf)
201{
Ryan Harkincd529322014-02-10 17:17:04 +0000202 long ret = -EINVAL;
203 size_t length;
204 long file_handle;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100205
206 /* Null pointer check */
207 if (!buf)
208 return ret;
209
210 assert(semihosting_connection_supported());
211
212 file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
213 if (file_handle == -1)
214 return ret;
215
216 /* Find the actual length of the file */
217 length = semihosting_file_length(file_handle);
218 if (length == -1)
219 goto semihosting_fail;
220
221 /* Signal error if we do not have enough space for the file */
222 if (length > buf_size)
223 goto semihosting_fail;
224
225 /*
226 * A successful read will return 0 in which case we pass back
227 * the actual number of bytes read. Else we pass a negative
228 * value indicating an error.
229 */
230 ret = semihosting_file_read(file_handle, &length, buf);
231 if (ret)
232 goto semihosting_fail;
233 else
234 ret = length;
235
236semihosting_fail:
237 semihosting_file_close(file_handle);
238 return ret;
239}