xref: /arm-trusted-firmware/drivers/io/io_semihosting.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <platform_def.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <drivers/io/io_driver.h>
12*91f16700Schasinglulu #include <drivers/io/io_semihosting.h>
13*91f16700Schasinglulu #include <drivers/io/io_storage.h>
14*91f16700Schasinglulu #include <lib/semihosting.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu /* Identify the device type as semihosting */
17*91f16700Schasinglulu static io_type_t device_type_sh(void)
18*91f16700Schasinglulu {
19*91f16700Schasinglulu 	return IO_TYPE_SEMIHOSTING;
20*91f16700Schasinglulu }
21*91f16700Schasinglulu 
22*91f16700Schasinglulu 
23*91f16700Schasinglulu /* Semi-hosting functions, device info and handle */
24*91f16700Schasinglulu 
25*91f16700Schasinglulu static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
26*91f16700Schasinglulu static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
27*91f16700Schasinglulu 		io_entity_t *entity);
28*91f16700Schasinglulu static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset);
29*91f16700Schasinglulu static int sh_file_len(io_entity_t *entity, size_t *length);
30*91f16700Schasinglulu static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
31*91f16700Schasinglulu 		size_t *length_read);
32*91f16700Schasinglulu static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
33*91f16700Schasinglulu 		size_t length, size_t *length_written);
34*91f16700Schasinglulu static int sh_file_close(io_entity_t *entity);
35*91f16700Schasinglulu 
36*91f16700Schasinglulu static const io_dev_connector_t sh_dev_connector = {
37*91f16700Schasinglulu 	.dev_open = sh_dev_open
38*91f16700Schasinglulu };
39*91f16700Schasinglulu 
40*91f16700Schasinglulu 
41*91f16700Schasinglulu static const io_dev_funcs_t sh_dev_funcs = {
42*91f16700Schasinglulu 	.type = device_type_sh,
43*91f16700Schasinglulu 	.open = sh_file_open,
44*91f16700Schasinglulu 	.seek = sh_file_seek,
45*91f16700Schasinglulu 	.size = sh_file_len,
46*91f16700Schasinglulu 	.read = sh_file_read,
47*91f16700Schasinglulu 	.write = sh_file_write,
48*91f16700Schasinglulu 	.close = sh_file_close,
49*91f16700Schasinglulu 	.dev_init = NULL,	/* NOP */
50*91f16700Schasinglulu 	.dev_close = NULL,	/* NOP */
51*91f16700Schasinglulu };
52*91f16700Schasinglulu 
53*91f16700Schasinglulu 
54*91f16700Schasinglulu static io_dev_info_t sh_dev_info = {
55*91f16700Schasinglulu 	.funcs = &sh_dev_funcs,
56*91f16700Schasinglulu 	.info = (uintptr_t)NULL
57*91f16700Schasinglulu };
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 
60*91f16700Schasinglulu /* Open a connection to the semi-hosting device */
61*91f16700Schasinglulu static int sh_dev_open(const uintptr_t dev_spec __unused,
62*91f16700Schasinglulu 		io_dev_info_t **dev_info)
63*91f16700Schasinglulu {
64*91f16700Schasinglulu 	assert(dev_info != NULL);
65*91f16700Schasinglulu 	*dev_info = &sh_dev_info;
66*91f16700Schasinglulu 	return 0;
67*91f16700Schasinglulu }
68*91f16700Schasinglulu 
69*91f16700Schasinglulu 
70*91f16700Schasinglulu /* Open a file on the semi-hosting device */
71*91f16700Schasinglulu static int sh_file_open(io_dev_info_t *dev_info __unused,
72*91f16700Schasinglulu 		const uintptr_t spec, io_entity_t *entity)
73*91f16700Schasinglulu {
74*91f16700Schasinglulu 	int result = -ENOENT;
75*91f16700Schasinglulu 	long sh_result;
76*91f16700Schasinglulu 	const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	assert(file_spec != NULL);
79*91f16700Schasinglulu 	assert(entity != NULL);
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
82*91f16700Schasinglulu 
83*91f16700Schasinglulu 	if (sh_result > 0) {
84*91f16700Schasinglulu 		entity->info = (uintptr_t)sh_result;
85*91f16700Schasinglulu 		result = 0;
86*91f16700Schasinglulu 	}
87*91f16700Schasinglulu 	return result;
88*91f16700Schasinglulu }
89*91f16700Schasinglulu 
90*91f16700Schasinglulu 
91*91f16700Schasinglulu /* Seek to a particular file offset on the semi-hosting device */
92*91f16700Schasinglulu static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
93*91f16700Schasinglulu {
94*91f16700Schasinglulu 	long file_handle, sh_result;
95*91f16700Schasinglulu 
96*91f16700Schasinglulu 	assert(entity != NULL);
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	file_handle = (long)entity->info;
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
101*91f16700Schasinglulu 
102*91f16700Schasinglulu 	return (sh_result == 0) ? 0 : -ENOENT;
103*91f16700Schasinglulu }
104*91f16700Schasinglulu 
105*91f16700Schasinglulu 
106*91f16700Schasinglulu /* Return the size of a file on the semi-hosting device */
107*91f16700Schasinglulu static int sh_file_len(io_entity_t *entity, size_t *length)
108*91f16700Schasinglulu {
109*91f16700Schasinglulu 	int result = -ENOENT;
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	assert(entity != NULL);
112*91f16700Schasinglulu 	assert(length != NULL);
113*91f16700Schasinglulu 
114*91f16700Schasinglulu 	long sh_handle = (long)entity->info;
115*91f16700Schasinglulu 	long sh_result = semihosting_file_length(sh_handle);
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	if (sh_result >= 0) {
118*91f16700Schasinglulu 		result = 0;
119*91f16700Schasinglulu 		*length = (size_t)sh_result;
120*91f16700Schasinglulu 	}
121*91f16700Schasinglulu 
122*91f16700Schasinglulu 	return result;
123*91f16700Schasinglulu }
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 
126*91f16700Schasinglulu /* Read data from a file on the semi-hosting device */
127*91f16700Schasinglulu static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
128*91f16700Schasinglulu 		size_t *length_read)
129*91f16700Schasinglulu {
130*91f16700Schasinglulu 	int result = -ENOENT;
131*91f16700Schasinglulu 	long sh_result;
132*91f16700Schasinglulu 	size_t bytes = length;
133*91f16700Schasinglulu 	long file_handle;
134*91f16700Schasinglulu 
135*91f16700Schasinglulu 	assert(entity != NULL);
136*91f16700Schasinglulu 	assert(length_read != NULL);
137*91f16700Schasinglulu 
138*91f16700Schasinglulu 	file_handle = (long)entity->info;
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 	sh_result = semihosting_file_read(file_handle, &bytes, buffer);
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	if (sh_result >= 0) {
143*91f16700Schasinglulu 		*length_read = (bytes != length) ? bytes : length;
144*91f16700Schasinglulu 		result = 0;
145*91f16700Schasinglulu 	}
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 	return result;
148*91f16700Schasinglulu }
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 
151*91f16700Schasinglulu /* Write data to a file on the semi-hosting device */
152*91f16700Schasinglulu static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
153*91f16700Schasinglulu 		size_t length, size_t *length_written)
154*91f16700Schasinglulu {
155*91f16700Schasinglulu 	long sh_result;
156*91f16700Schasinglulu 	long file_handle;
157*91f16700Schasinglulu 	size_t bytes = length;
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	assert(entity != NULL);
160*91f16700Schasinglulu 	assert(length_written != NULL);
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	file_handle = (long)entity->info;
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	sh_result = semihosting_file_write(file_handle, &bytes, buffer);
165*91f16700Schasinglulu 
166*91f16700Schasinglulu 	*length_written = length - bytes;
167*91f16700Schasinglulu 
168*91f16700Schasinglulu 	return (sh_result == 0) ? 0 : -ENOENT;
169*91f16700Schasinglulu }
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 
172*91f16700Schasinglulu /* Close a file on the semi-hosting device */
173*91f16700Schasinglulu static int sh_file_close(io_entity_t *entity)
174*91f16700Schasinglulu {
175*91f16700Schasinglulu 	long sh_result;
176*91f16700Schasinglulu 	long file_handle;
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 	assert(entity != NULL);
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	file_handle = (long)entity->info;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	sh_result = semihosting_file_close(file_handle);
183*91f16700Schasinglulu 
184*91f16700Schasinglulu 	return (sh_result >= 0) ? 0 : -ENOENT;
185*91f16700Schasinglulu }
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 
188*91f16700Schasinglulu /* Exported functions */
189*91f16700Schasinglulu 
190*91f16700Schasinglulu /* Register the semi-hosting driver with the IO abstraction */
191*91f16700Schasinglulu int register_io_dev_sh(const io_dev_connector_t **dev_con)
192*91f16700Schasinglulu {
193*91f16700Schasinglulu 	int result;
194*91f16700Schasinglulu 	assert(dev_con != NULL);
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	result = io_register_device(&sh_dev_info);
197*91f16700Schasinglulu 	if (result == 0)
198*91f16700Schasinglulu 		*dev_con = &sh_dev_connector;
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	return result;
201*91f16700Schasinglulu }
202