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