blob: 4abf44f7d2e21b0b4c4a62f5227dd6b033883695 [file] [log] [blame]
James Morrissey9d72b4e2014-02-10 17:04:32 +00001/*
Roberto Vargas7fabe1a2018-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-arm82cb2c12017-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 Handley35e98e52014-04-09 13:13:04 +01008#include <io_driver.h>
Roberto Vargas7fabe1a2018-02-12 12:36:17 +00009#include <io_semihosting.h>
Dan Handley97043ac2014-04-09 13:14:54 +010010#include <io_storage.h>
Dan Handley35e98e52014-04-09 13:13:04 +010011#include <semihosting.h>
James Morrissey9d72b4e2014-02-10 17:04:32 +000012
13
14
15/* Identify the device type as semihosting */
Dan Handleyfb037bf2014-04-10 15:37:22 +010016static io_type_t device_type_sh(void)
James Morrissey9d72b4e2014-02-10 17:04:32 +000017{
18 return IO_TYPE_SEMIHOSTING;
19}
20
21
22/* Semi-hosting functions, device info and handle */
23
Dan Handley625de1d2014-04-23 13:47:06 +010024static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
25static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleyfb037bf2014-04-10 15:37:22 +010026 io_entity_t *entity);
27static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
28static int sh_file_len(io_entity_t *entity, size_t *length);
Dan Handley625de1d2014-04-23 13:47:06 +010029static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
James Morrissey9d72b4e2014-02-10 17:04:32 +000030 size_t *length_read);
Dan Handley625de1d2014-04-23 13:47:06 +010031static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
James Morrissey9d72b4e2014-02-10 17:04:32 +000032 size_t length, size_t *length_written);
Dan Handleyfb037bf2014-04-10 15:37:22 +010033static int sh_file_close(io_entity_t *entity);
James Morrissey9d72b4e2014-02-10 17:04:32 +000034
Dan Handley625de1d2014-04-23 13:47:06 +010035static const io_dev_connector_t sh_dev_connector = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000036 .dev_open = sh_dev_open
37};
38
39
Dan Handley625de1d2014-04-23 13:47:06 +010040static const io_dev_funcs_t sh_dev_funcs = {
James Morrissey9d72b4e2014-02-10 17:04:32 +000041 .type = device_type_sh,
42 .open = sh_file_open,
43 .seek = sh_file_seek,
44 .size = sh_file_len,
45 .read = sh_file_read,
46 .write = sh_file_write,
47 .close = sh_file_close,
48 .dev_init = NULL, /* NOP */
49 .dev_close = NULL, /* NOP */
50};
51
52
Dan Handley625de1d2014-04-23 13:47:06 +010053/* No state associated with this device so structure can be const */
54static const 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 Handley625de1d2014-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);
Dan Handley625de1d2014-04-23 13:47:06 +010065 *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
Juan Castilloe098e242015-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 Brinkmann65cd2992016-01-14 10:11:05 -080071static int sh_file_open(io_dev_info_t *dev_info __unused,
Dan Handley625de1d2014-04-23 13:47:06 +010072 const uintptr_t spec, io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +000073{
Juan Castilloe098e242015-11-02 10:47:01 +000074 int result = -ENOENT;
dp-armdae695a2017-02-09 10:25:29 +000075 long sh_result;
Dan Handley625de1d2014-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 Castilloe098e242015-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 */
Dan Handleyfb037bf2014-04-10 15:37:22 +010092static int sh_file_seek(io_entity_t *entity, int mode, ssize_t 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
100 sh_result = semihosting_file_seek(file_handle, offset);
101
Juan Castilloe098e242015-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 Handleyfb037bf2014-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 Castilloe098e242015-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 Castilloe098e242015-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 Handley625de1d2014-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 Castilloe098e242015-11-02 10:47:01 +0000130 int result = -ENOENT;
dp-armdae695a2017-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);
Dan Handley625de1d2014-04-23 13:47:06 +0100136 assert(buffer != (uintptr_t)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 Castilloe098e242015-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 Handley625de1d2014-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-armdae695a2017-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);
Dan Handley625de1d2014-04-23 13:47:06 +0100161 assert(buffer != (uintptr_t)NULL);
James Morrissey9d72b4e2014-02-10 17:04:32 +0000162 assert(length_written != NULL);
163
Ryan Harkincd529322014-02-10 17:17:04 +0000164 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000165
166 sh_result = semihosting_file_write(file_handle, &bytes, buffer);
167
Juan Castillo31833af2015-07-07 15:36:33 +0100168 *length_written = length - bytes;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000169
Juan Castilloe098e242015-11-02 10:47:01 +0000170 return (sh_result == 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000171}
172
173
174/* Close a file on the semi-hosting device */
Dan Handleyfb037bf2014-04-10 15:37:22 +0100175static int sh_file_close(io_entity_t *entity)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000176{
dp-armdae695a2017-02-09 10:25:29 +0000177 long sh_result;
Ryan Harkincd529322014-02-10 17:17:04 +0000178 long file_handle;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000179
180 assert(entity != NULL);
181
Ryan Harkincd529322014-02-10 17:17:04 +0000182 file_handle = (long)entity->info;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000183
184 sh_result = semihosting_file_close(file_handle);
185
Juan Castilloe098e242015-11-02 10:47:01 +0000186 return (sh_result >= 0) ? 0 : -ENOENT;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000187}
188
189
190/* Exported functions */
191
192/* Register the semi-hosting driver with the IO abstraction */
Dan Handley625de1d2014-04-23 13:47:06 +0100193int register_io_dev_sh(const io_dev_connector_t **dev_con)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000194{
Juan Castilloe098e242015-11-02 10:47:01 +0000195 int result;
James Morrissey9d72b4e2014-02-10 17:04:32 +0000196 assert(dev_con != NULL);
197
198 result = io_register_device(&sh_dev_info);
Juan Castilloe098e242015-11-02 10:47:01 +0000199 if (result == 0)
James Morrissey9d72b4e2014-02-10 17:04:32 +0000200 *dev_con = &sh_dev_connector;
201
202 return result;
203}