blob: 4ceddc6cc08ba0680f96fbf195766c94483bc824 [file] [log] [blame]
James Morrissey9d72b4e2014-02-10 17:04:32 +00001/*
Roberto Vargas05712702018-02-12 12:36:17 +00002 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
James Morrissey9d72b4e2014-02-10 17:04:32 +00003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
James Morrissey9d72b4e2014-02-10 17:04:32 +00005 */
6
7#include <assert.h>
James Morrissey9d72b4e2014-02-10 17:04:32 +00008
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009#include <platform_def.h>
James Morrissey9d72b4e2014-02-10 17:04:32 +000010
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <drivers/io/io_driver.h>
12#include <drivers/io/io_semihosting.h>
13#include <drivers/io/io_storage.h>
14#include <lib/semihosting.h>
James Morrissey9d72b4e2014-02-10 17:04:32 +000015
16/* Identify the device type as semihosting */
Dan Handleye2712bc2014-04-10 15:37:22 +010017static io_type_t device_type_sh(void)
James Morrissey9d72b4e2014-02-10 17:04:32 +000018{
19 return IO_TYPE_SEMIHOSTING;
20}
21
22
23/* Semi-hosting functions, device info and handle */
24
Dan Handleya4cb68e2014-04-23 13:47:06 +010025static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
26static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010027 io_entity_t *entity);
Yann Gautierf30cddc2019-04-16 11:35:19 +020028static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset);
Dan Handleye2712bc2014-04-10 15:37:22 +010029static int sh_file_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010030static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +000031 size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010032static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
James Morrissey9d72b4e2014-02-10 17:04:32 +000033 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010034static int sh_file_close(io_entity_t *entity);
James Morrissey9d72b4e2014-02-10 17:04:32 +000035
Dan Handleya4cb68e2014-04-23 13:47:06 +010036static const io_dev_connector_t sh_dev_connector = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000037 .dev_open = sh_dev_open
38};
39
40
Dan Handleya4cb68e2014-04-23 13:47:06 +010041static const io_dev_funcs_t sh_dev_funcs = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000042 .type = device_type_sh,
43 .open = sh_file_open,
44 .seek = sh_file_seek,
45 .size = sh_file_len,
46 .read = sh_file_read,
47 .write = sh_file_write,
48 .close = sh_file_close,
49 .dev_init = NULL, /* NOP */
50 .dev_close = NULL, /* NOP */
51};
52
53
Dan Handleya4cb68e2014-04-23 13:47:06 +010054/* No state associated with this device so structure can be const */
55static const io_dev_info_t sh_dev_info = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000056 .funcs = &sh_dev_funcs,
57 .info = (uintptr_t)NULL
58};
59
60
61/* Open a connection to the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010062static int sh_dev_open(const uintptr_t dev_spec __unused,
63 io_dev_info_t **dev_info)
James Morrissey9d72b4e2014-02-10 17:04:32 +000064{
James Morrissey9d72b4e2014-02-10 17:04:32 +000065 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010066 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
Juan Castillo6e762062015-11-02 10:47:01 +000067 return 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000068}
69
70
71/* Open a file on the semi-hosting device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080072static int sh_file_open(io_dev_info_t *dev_info __unused,
Dan Handleya4cb68e2014-04-23 13:47:06 +010073 const uintptr_t spec, io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +000074{
Juan Castillo6e762062015-11-02 10:47:01 +000075 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +000076 long sh_result;
Dan Handleya4cb68e2014-04-23 13:47:06 +010077 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
James Morrissey9d72b4e2014-02-10 17:04:32 +000078
79 assert(file_spec != NULL);
80 assert(entity != NULL);
81
82 sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
83
84 if (sh_result > 0) {
Ryan Harkincd529322014-02-10 17:17:04 +000085 entity->info = (uintptr_t)sh_result;
Juan Castillo6e762062015-11-02 10:47:01 +000086 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000087 }
88 return result;
89}
90
91
92/* Seek to a particular file offset on the semi-hosting device */
Yann Gautierf30cddc2019-04-16 11:35:19 +020093static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
James Morrissey9d72b4e2014-02-10 17:04:32 +000094{
Ryan Harkincd529322014-02-10 17:17:04 +000095 long file_handle, sh_result;
James Morrissey9d72b4e2014-02-10 17:04:32 +000096
97 assert(entity != NULL);
98
Ryan Harkincd529322014-02-10 17:17:04 +000099 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000100
Yann Gautierf30cddc2019-04-16 11:35:19 +0200101 sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000102
Juan Castillo6e762062015-11-02 10:47:01 +0000103 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000104}
105
106
107/* Return the size of a file on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100108static int sh_file_len(io_entity_t *entity, size_t *length)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000109{
Juan Castillo6e762062015-11-02 10:47:01 +0000110 int result = -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000111
112 assert(entity != NULL);
113 assert(length != NULL);
114
Ryan Harkincd529322014-02-10 17:17:04 +0000115 long sh_handle = (long)entity->info;
116 long sh_result = semihosting_file_length(sh_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000117
118 if (sh_result >= 0) {
Juan Castillo6e762062015-11-02 10:47:01 +0000119 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000120 *length = (size_t)sh_result;
121 }
122
123 return result;
124}
125
126
127/* Read data from a file on the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100128static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +0000129 size_t *length_read)
130{
Juan Castillo6e762062015-11-02 10:47:01 +0000131 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +0000132 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000133 size_t bytes = length;
134 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000135
136 assert(entity != NULL);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000137 assert(length_read != NULL);
138
Ryan Harkincd529322014-02-10 17:17:04 +0000139 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000140
141 sh_result = semihosting_file_read(file_handle, &bytes, buffer);
142
143 if (sh_result >= 0) {
144 *length_read = (bytes != length) ? bytes : length;
Juan Castillo6e762062015-11-02 10:47:01 +0000145 result = 0;
146 }
James Morrissey9d72b4e2014-02-10 17:04:32 +0000147
148 return result;
149}
150
151
152/* Write data to a file on the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100153static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
James Morrissey9d72b4e2014-02-10 17:04:32 +0000154 size_t length, size_t *length_written)
155{
dp-arm8b6e3d32017-02-09 10:25:29 +0000156 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000157 long file_handle;
158 size_t bytes = length;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000159
160 assert(entity != NULL);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000161 assert(length_written != NULL);
162
Ryan Harkincd529322014-02-10 17:17:04 +0000163 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000164
165 sh_result = semihosting_file_write(file_handle, &bytes, buffer);
166
Juan Castillo03fe10c2015-07-07 15:36:33 +0100167 *length_written = length - bytes;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000168
Juan Castillo6e762062015-11-02 10:47:01 +0000169 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000170}
171
172
173/* Close a file on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100174static int sh_file_close(io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000175{
dp-arm8b6e3d32017-02-09 10:25:29 +0000176 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000177 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000178
179 assert(entity != NULL);
180
Ryan Harkincd529322014-02-10 17:17:04 +0000181 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000182
183 sh_result = semihosting_file_close(file_handle);
184
Juan Castillo6e762062015-11-02 10:47:01 +0000185 return (sh_result >= 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000186}
187
188
189/* Exported functions */
190
191/* Register the semi-hosting driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100192int register_io_dev_sh(const io_dev_connector_t **dev_con)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000193{
Juan Castillo6e762062015-11-02 10:47:01 +0000194 int result;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000195 assert(dev_con != NULL);
196
197 result = io_register_device(&sh_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000198 if (result == 0)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000199 *dev_con = &sh_dev_connector;
200
201 return result;
202}