blob: 1c2f84d545f11b73d8b41a96f0eb54f6ea89e7ee [file] [log] [blame]
James Morrissey9d72b4e2014-02-10 17:04:32 +00001/*
johpow0121031282020-07-01 17:09:57 -05002 * Copyright (c) 2014-2020, 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
johpow0121031282020-07-01 17:09:57 -050054static io_dev_info_t sh_dev_info = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000055 .funcs = &sh_dev_funcs,
56 .info = (uintptr_t)NULL
57};
58
59
60/* Open a connection to the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010061static int sh_dev_open(const uintptr_t dev_spec __unused,
62 io_dev_info_t **dev_info)
James Morrissey9d72b4e2014-02-10 17:04:32 +000063{
James Morrissey9d72b4e2014-02-10 17:04:32 +000064 assert(dev_info != NULL);
johpow0121031282020-07-01 17:09:57 -050065 *dev_info = &sh_dev_info;
Juan Castillo6e762062015-11-02 10:47:01 +000066 return 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000067}
68
69
70/* Open a file on the semi-hosting device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -080071static int sh_file_open(io_dev_info_t *dev_info __unused,
Dan Handleya4cb68e2014-04-23 13:47:06 +010072 const uintptr_t spec, io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +000073{
Juan Castillo6e762062015-11-02 10:47:01 +000074 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +000075 long sh_result;
Dan Handleya4cb68e2014-04-23 13:47:06 +010076 const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
James Morrissey9d72b4e2014-02-10 17:04:32 +000077
78 assert(file_spec != NULL);
79 assert(entity != NULL);
80
81 sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
82
83 if (sh_result > 0) {
Ryan Harkincd529322014-02-10 17:17:04 +000084 entity->info = (uintptr_t)sh_result;
Juan Castillo6e762062015-11-02 10:47:01 +000085 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +000086 }
87 return result;
88}
89
90
91/* Seek to a particular file offset on the semi-hosting device */
Yann Gautierf30cddc2019-04-16 11:35:19 +020092static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
James Morrissey9d72b4e2014-02-10 17:04:32 +000093{
Ryan Harkincd529322014-02-10 17:17:04 +000094 long file_handle, sh_result;
James Morrissey9d72b4e2014-02-10 17:04:32 +000095
96 assert(entity != NULL);
97
Ryan Harkincd529322014-02-10 17:17:04 +000098 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +000099
Yann Gautierf30cddc2019-04-16 11:35:19 +0200100 sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000101
Juan Castillo6e762062015-11-02 10:47:01 +0000102 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000103}
104
105
106/* Return the size of a file on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100107static int sh_file_len(io_entity_t *entity, size_t *length)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000108{
Juan Castillo6e762062015-11-02 10:47:01 +0000109 int result = -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000110
111 assert(entity != NULL);
112 assert(length != NULL);
113
Ryan Harkincd529322014-02-10 17:17:04 +0000114 long sh_handle = (long)entity->info;
115 long sh_result = semihosting_file_length(sh_handle);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000116
117 if (sh_result >= 0) {
Juan Castillo6e762062015-11-02 10:47:01 +0000118 result = 0;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000119 *length = (size_t)sh_result;
120 }
121
122 return result;
123}
124
125
126/* Read data from a file on the semi-hosting device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100127static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +0000128 size_t *length_read)
129{
Juan Castillo6e762062015-11-02 10:47:01 +0000130 int result = -ENOENT;
dp-arm8b6e3d32017-02-09 10:25:29 +0000131 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000132 size_t bytes = length;
133 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000134
135 assert(entity != 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);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000160 assert(length_written != NULL);
161
Ryan Harkincd529322014-02-10 17:17:04 +0000162 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000163
164 sh_result = semihosting_file_write(file_handle, &bytes, buffer);
165
Juan Castillo03fe10c2015-07-07 15:36:33 +0100166 *length_written = length - bytes;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000167
Juan Castillo6e762062015-11-02 10:47:01 +0000168 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000169}
170
171
172/* Close a file on the semi-hosting device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100173static int sh_file_close(io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000174{
dp-arm8b6e3d32017-02-09 10:25:29 +0000175 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000176 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000177
178 assert(entity != NULL);
179
Ryan Harkincd529322014-02-10 17:17:04 +0000180 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000181
182 sh_result = semihosting_file_close(file_handle);
183
Juan Castillo6e762062015-11-02 10:47:01 +0000184 return (sh_result >= 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000185}
186
187
188/* Exported functions */
189
190/* Register the semi-hosting driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100191int register_io_dev_sh(const io_dev_connector_t **dev_con)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000192{
Juan Castillo6e762062015-11-02 10:47:01 +0000193 int result;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000194 assert(dev_con != NULL);
195
196 result = io_register_device(&sh_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000197 if (result == 0)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000198 *dev_con = &sh_dev_connector;
199
200 return result;
201}