blob: 051dd008bebb1fa6518305157b9af1ce00a4ae85 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Ambroise Vincenta88a35d2019-02-14 09:48:21 +00002 * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Achin Gupta4f6ad662013-10-25 09:08:21 +01005 */
6
7#include <assert.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +01008#include <errno.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01009#include <string.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010010
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <lib/semihosting.h>
12
Achin Gupta4f6ad662013-10-25 09:08:21 +010013#ifndef SEMIHOSTING_SUPPORTED
14#define SEMIHOSTING_SUPPORTED 1
15#endif
16
Dan Handleya17fefa2014-05-14 12:38:32 +010017long semihosting_call(unsigned long operation,
18 void *system_block_address);
Achin Gupta4f6ad662013-10-25 09:08:21 +010019
20typedef struct {
21 const char *file_name;
Ryan Harkincd529322014-02-10 17:17:04 +000022 unsigned long mode;
23 size_t name_length;
Dan Handleye2712bc2014-04-10 15:37:22 +010024} smh_file_open_block_t;
Achin Gupta4f6ad662013-10-25 09:08:21 +010025
26typedef struct {
Ryan Harkincd529322014-02-10 17:17:04 +000027 long handle;
Dan Handleya4cb68e2014-04-23 13:47:06 +010028 uintptr_t buffer;
Ryan Harkincd529322014-02-10 17:17:04 +000029 size_t length;
Dan Handleye2712bc2014-04-10 15:37:22 +010030} smh_file_read_write_block_t;
Achin Gupta4f6ad662013-10-25 09:08:21 +010031
32typedef struct {
Ryan Harkincd529322014-02-10 17:17:04 +000033 long handle;
34 ssize_t location;
Dan Handleye2712bc2014-04-10 15:37:22 +010035} smh_file_seek_block_t;
Achin Gupta4f6ad662013-10-25 09:08:21 +010036
37typedef struct {
38 char *command_line;
Ryan Harkincd529322014-02-10 17:17:04 +000039 size_t command_length;
Dan Handleye2712bc2014-04-10 15:37:22 +010040} smh_system_block_t;
Achin Gupta4f6ad662013-10-25 09:08:21 +010041
Ryan Harkincd529322014-02-10 17:17:04 +000042long semihosting_connection_supported(void)
Achin Gupta4f6ad662013-10-25 09:08:21 +010043{
44 return SEMIHOSTING_SUPPORTED;
45}
46
Ryan Harkincd529322014-02-10 17:17:04 +000047long semihosting_file_open(const char *file_name, size_t mode)
Achin Gupta4f6ad662013-10-25 09:08:21 +010048{
Dan Handleye2712bc2014-04-10 15:37:22 +010049 smh_file_open_block_t open_block;
Achin Gupta4f6ad662013-10-25 09:08:21 +010050
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
Ryan Harkincd529322014-02-10 17:17:04 +000059long semihosting_file_seek(long file_handle, ssize_t offset)
Achin Gupta4f6ad662013-10-25 09:08:21 +010060{
Dan Handleye2712bc2014-04-10 15:37:22 +010061 smh_file_seek_block_t seek_block;
Ryan Harkincd529322014-02-10 17:17:04 +000062 long result;
Achin Gupta4f6ad662013-10-25 09:08:21 +010063
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
Dan Handleya4cb68e2014-04-23 13:47:06 +010076long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer)
Achin Gupta4f6ad662013-10-25 09:08:21 +010077{
Dan Handleye2712bc2014-04-10 15:37:22 +010078 smh_file_read_write_block_t read_block;
Ryan Harkincd529322014-02-10 17:17:04 +000079 long result = -EINVAL;
Achin Gupta4f6ad662013-10-25 09:08:21 +010080
Dan Handleya4cb68e2014-04-23 13:47:06 +010081 if ((length == NULL) || (buffer == (uintptr_t)NULL))
Achin Gupta4f6ad662013-10-25 09:08:21 +010082 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
Ryan Harkincd529322014-02-10 17:17:04 +0000100long semihosting_file_write(long file_handle,
101 size_t *length,
Dan Handleya4cb68e2014-04-23 13:47:06 +0100102 const uintptr_t buffer)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100103{
Dan Handleye2712bc2014-04-10 15:37:22 +0100104 smh_file_read_write_block_t write_block;
Juan Castillo03fe10c2015-07-07 15:36:33 +0100105 long result = -EINVAL;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100106
Dan Handleya4cb68e2014-04-23 13:47:06 +0100107 if ((length == NULL) || (buffer == (uintptr_t)NULL))
Achin Gupta4f6ad662013-10-25 09:08:21 +0100108 return -EINVAL;
109
110 write_block.handle = file_handle;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100111 write_block.buffer = (uintptr_t)buffer; /* cast away const */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100112 write_block.length = *length;
113
Juan Castillo03fe10c2015-07-07 15:36:33 +0100114 result = semihosting_call(SEMIHOSTING_SYS_WRITE,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100115 (void *) &write_block);
116
Juan Castillo03fe10c2015-07-07 15:36:33 +0100117 *length = result;
118
119 return (result == 0) ? 0 : -EINVAL;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100120}
121
Ryan Harkincd529322014-02-10 17:17:04 +0000122long semihosting_file_close(long file_handle)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100123{
124 return semihosting_call(SEMIHOSTING_SYS_CLOSE,
125 (void *) &file_handle);
126}
127
Ryan Harkincd529322014-02-10 17:17:04 +0000128long semihosting_file_length(long file_handle)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100129{
130 return semihosting_call(SEMIHOSTING_SYS_FLEN,
131 (void *) &file_handle);
132}
133
134char semihosting_read_char(void)
135{
136 return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
137}
138
139void semihosting_write_char(char character)
140{
141 semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character);
142}
143
144void semihosting_write_string(char *string)
145{
146 semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string);
147}
148
Ryan Harkincd529322014-02-10 17:17:04 +0000149long semihosting_system(char *command_line)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100150{
Dan Handleye2712bc2014-04-10 15:37:22 +0100151 smh_system_block_t system_block;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100152
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
Ryan Harkincd529322014-02-10 17:17:04 +0000160long semihosting_get_flen(const char *file_name)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100161{
Ryan Harkincd529322014-02-10 17:17:04 +0000162 long file_handle;
Ambroise Vincenta88a35d2019-02-14 09:48:21 +0000163 long length;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100164
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
Ryan Harkincd529322014-02-10 17:17:04 +0000177long semihosting_download_file(const char *file_name,
178 size_t buf_size,
Dan Handleya4cb68e2014-04-23 13:47:06 +0100179 uintptr_t buf)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100180{
Ryan Harkincd529322014-02-10 17:17:04 +0000181 long ret = -EINVAL;
182 size_t length;
183 long file_handle;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100184
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
215semihosting_fail:
216 semihosting_file_close(file_handle);
217 return ret;
218}