blob: f1dfa208af9ec598f1db9cc5296ff7c4c290aa7b [file] [log] [blame]
James Morrissey9d72b4e2014-02-10 17:04:32 +00001/*
2 * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
3 *
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>
Dan Handley714a0d22014-04-09 13:13:04 +01008#include <io_driver.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01009#include <io_storage.h>
Dan Handley714a0d22014-04-09 13:13:04 +010010#include <semihosting.h>
James Morrissey9d72b4e2014-02-10 17:04:32 +000011
12
13
14/* Identify the device type as semihosting */
Dan Handleye2712bc2014-04-10 15:37:22 +010015static io_type_t device_type_sh(void)
James Morrissey9d72b4e2014-02-10 17:04:32 +000016{
17 return IO_TYPE_SEMIHOSTING;
18}
19
20
21/* Semi-hosting functions, device info and handle */
22
Dan Handleya4cb68e2014-04-23 13:47:06 +010023static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
24static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010025 io_entity_t *entity);
26static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
27static int sh_file_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010028static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +000029 size_t *length_read);
Dan Handleya4cb68e2014-04-23 13:47:06 +010030static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
James Morrissey9d72b4e2014-02-10 17:04:32 +000031 size_t length, size_t *length_written);
Dan Handleye2712bc2014-04-10 15:37:22 +010032static int sh_file_close(io_entity_t *entity);
James Morrissey9d72b4e2014-02-10 17:04:32 +000033
Dan Handleya4cb68e2014-04-23 13:47:06 +010034static const io_dev_connector_t sh_dev_connector = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000035 .dev_open = sh_dev_open
36};
37
38
Dan Handleya4cb68e2014-04-23 13:47:06 +010039static const io_dev_funcs_t sh_dev_funcs = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000040 .type = device_type_sh,
41 .open = sh_file_open,
42 .seek = sh_file_seek,
43 .size = sh_file_len,
44 .read = sh_file_read,
45 .write = sh_file_write,
46 .close = sh_file_close,
47 .dev_init = NULL, /* NOP */
48 .dev_close = NULL, /* NOP */
49};
50
51
Dan Handleya4cb68e2014-04-23 13:47:06 +010052/* No state associated with this device so structure can be const */
53static const io_dev_info_t sh_dev_info = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000054 .funcs = &sh_dev_funcs,
55 .info = (uintptr_t)NULL
56};
57
58
59/* Open a connection to the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010060static int sh_dev_open(const uintptr_t dev_spec __unused,
61 io_dev_info_t **dev_info)
James Morrissey9d72b4e2014-02-10 17:04:32 +000062{
James Morrissey9d72b4e2014-02-10 17:04:32 +000063 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +010064 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
Juan Castillo6e762062015-11-02 10:47:01 +000065 return 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000066}
67
68
69/* Open a file on the semi-hosting device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080070static int sh_file_open(io_dev_info_t *dev_info __unused,
Dan Handleya4cb68e2014-04-23 13:47:06 +010071 const uintptr_t spec, io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +000072{
Juan Castillo6e762062015-11-02 10:47:01 +000073 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +000074 long sh_result;
Dan Handleya4cb68e2014-04-23 13:47:06 +010075 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
James Morrissey9d72b4e2014-02-10 17:04:32 +000076
77 assert(file_spec != NULL);
78 assert(entity != NULL);
79
80 sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
81
82 if (sh_result > 0) {
Ryan Harkincd529322014-02-10 17:17:04 +000083 entity->info = (uintptr_t)sh_result;
Juan Castillo6e762062015-11-02 10:47:01 +000084 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000085 }
86 return result;
87}
88
89
90/* Seek to a particular file offset on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +010091static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
James Morrissey9d72b4e2014-02-10 17:04:32 +000092{
Ryan Harkincd529322014-02-10 17:17:04 +000093 long file_handle, sh_result;
James Morrissey9d72b4e2014-02-10 17:04:32 +000094
95 assert(entity != NULL);
96
Ryan Harkincd529322014-02-10 17:17:04 +000097 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +000098
99 sh_result = semihosting_file_seek(file_handle, offset);
100
Juan Castillo6e762062015-11-02 10:47:01 +0000101 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000102}
103
104
105/* Return the size of a file on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100106static int sh_file_len(io_entity_t *entity, size_t *length)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000107{
Juan Castillo6e762062015-11-02 10:47:01 +0000108 int result = -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000109
110 assert(entity != NULL);
111 assert(length != NULL);
112
Ryan Harkincd529322014-02-10 17:17:04 +0000113 long sh_handle = (long)entity->info;
114 long sh_result = semihosting_file_length(sh_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000115
116 if (sh_result >= 0) {
Juan Castillo6e762062015-11-02 10:47:01 +0000117 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000118 *length = (size_t)sh_result;
119 }
120
121 return result;
122}
123
124
125/* Read data from a file on the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100126static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +0000127 size_t *length_read)
128{
Juan Castillo6e762062015-11-02 10:47:01 +0000129 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +0000130 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000131 size_t bytes = length;
132 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000133
134 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100135 assert(buffer != (uintptr_t)NULL);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000136 assert(length_read != NULL);
137
Ryan Harkincd529322014-02-10 17:17:04 +0000138 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000139
140 sh_result = semihosting_file_read(file_handle, &bytes, buffer);
141
142 if (sh_result >= 0) {
143 *length_read = (bytes != length) ? bytes : length;
Juan Castillo6e762062015-11-02 10:47:01 +0000144 result = 0;
145 }
James Morrissey9d72b4e2014-02-10 17:04:32 +0000146
147 return result;
148}
149
150
151/* Write data to a file on the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100152static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
James Morrissey9d72b4e2014-02-10 17:04:32 +0000153 size_t length, size_t *length_written)
154{
dp-arm8b6e3d32017-02-09 10:25:29 +0000155 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000156 long file_handle;
157 size_t bytes = length;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000158
159 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100160 assert(buffer != (uintptr_t)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}