io_semihosting.c 4.5 KB
Newer Older
1
/*
2
 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
7
 */

#include <assert.h>
8
#include <io_driver.h>
9
#include <io_semihosting.h>
10
#include <io_storage.h>
11
#include <semihosting.h>
12
13
14
15



/* Identify the device type as semihosting */
16
static io_type_t device_type_sh(void)
17
18
19
20
21
22
23
{
	return IO_TYPE_SEMIHOSTING;
}


/* Semi-hosting functions, device info and handle */

24
25
static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
26
27
28
		io_entity_t *entity);
static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
static int sh_file_len(io_entity_t *entity, size_t *length);
29
static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
30
		size_t *length_read);
31
static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
32
		size_t length, size_t *length_written);
33
static int sh_file_close(io_entity_t *entity);
34

35
static const io_dev_connector_t sh_dev_connector = {
36
37
38
39
	.dev_open = sh_dev_open
};


40
static const io_dev_funcs_t sh_dev_funcs = {
41
42
43
44
45
46
47
48
49
50
51
52
	.type = device_type_sh,
	.open = sh_file_open,
	.seek = sh_file_seek,
	.size = sh_file_len,
	.read = sh_file_read,
	.write = sh_file_write,
	.close = sh_file_close,
	.dev_init = NULL,	/* NOP */
	.dev_close = NULL,	/* NOP */
};


53
54
/* No state associated with this device so structure can be const */
static const io_dev_info_t sh_dev_info = {
55
56
57
58
59
60
	.funcs = &sh_dev_funcs,
	.info = (uintptr_t)NULL
};


/* Open a connection to the semi-hosting device */
61
62
static int sh_dev_open(const uintptr_t dev_spec __unused,
		io_dev_info_t **dev_info)
63
64
{
	assert(dev_info != NULL);
65
	*dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
66
	return 0;
67
68
69
70
}


/* Open a file on the semi-hosting device */
71
static int sh_file_open(io_dev_info_t *dev_info __unused,
72
		const uintptr_t spec, io_entity_t *entity)
73
{
74
	int result = -ENOENT;
dp-arm's avatar
dp-arm committed
75
	long sh_result;
76
	const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
77
78
79
80
81
82
83

	assert(file_spec != NULL);
	assert(entity != NULL);

	sh_result = semihosting_file_open(file_spec->path, file_spec->mode);

	if (sh_result > 0) {
84
		entity->info = (uintptr_t)sh_result;
85
		result = 0;
86
87
88
89
90
91
	}
	return result;
}


/* Seek to a particular file offset on the semi-hosting device */
92
static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
93
{
94
	long file_handle, sh_result;
95
96
97

	assert(entity != NULL);

98
	file_handle = (long)entity->info;
99
100
101

	sh_result = semihosting_file_seek(file_handle, offset);

102
	return (sh_result == 0) ? 0 : -ENOENT;
103
104
105
106
}


/* Return the size of a file on the semi-hosting device */
107
static int sh_file_len(io_entity_t *entity, size_t *length)
108
{
109
	int result = -ENOENT;
110
111
112
113

	assert(entity != NULL);
	assert(length != NULL);

114
115
	long sh_handle = (long)entity->info;
	long sh_result = semihosting_file_length(sh_handle);
116
117

	if (sh_result >= 0) {
118
		result = 0;
119
120
121
122
123
124
125
126
		*length = (size_t)sh_result;
	}

	return result;
}


/* Read data from a file on the semi-hosting device */
127
static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
128
129
		size_t *length_read)
{
130
	int result = -ENOENT;
dp-arm's avatar
dp-arm committed
131
	long sh_result;
132
133
	size_t bytes = length;
	long file_handle;
134
135

	assert(entity != NULL);
136
	assert(buffer != (uintptr_t)NULL);
137
138
	assert(length_read != NULL);

139
	file_handle = (long)entity->info;
140
141
142
143
144

	sh_result = semihosting_file_read(file_handle, &bytes, buffer);

	if (sh_result >= 0) {
		*length_read = (bytes != length) ? bytes : length;
145
146
		result = 0;
	}
147
148
149
150
151
152

	return result;
}


/* Write data to a file on the semi-hosting device */
153
static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
154
155
		size_t length, size_t *length_written)
{
dp-arm's avatar
dp-arm committed
156
	long sh_result;
157
158
	long file_handle;
	size_t bytes = length;
159
160

	assert(entity != NULL);
161
	assert(buffer != (uintptr_t)NULL);
162
163
	assert(length_written != NULL);

164
	file_handle = (long)entity->info;
165
166
167

	sh_result = semihosting_file_write(file_handle, &bytes, buffer);

168
	*length_written = length - bytes;
169

170
	return (sh_result == 0) ? 0 : -ENOENT;
171
172
173
174
}


/* Close a file on the semi-hosting device */
175
static int sh_file_close(io_entity_t *entity)
176
{
dp-arm's avatar
dp-arm committed
177
	long sh_result;
178
	long file_handle;
179
180
181

	assert(entity != NULL);

182
	file_handle = (long)entity->info;
183
184
185

	sh_result = semihosting_file_close(file_handle);

186
	return (sh_result >= 0) ? 0 : -ENOENT;
187
188
189
190
191
192
}


/* Exported functions */

/* Register the semi-hosting driver with the IO abstraction */
193
int register_io_dev_sh(const io_dev_connector_t **dev_con)
194
{
195
	int result;
196
197
198
	assert(dev_con != NULL);

	result = io_register_device(&sh_dev_info);
199
	if (result == 0)
200
201
202
203
		*dev_con = &sh_dev_connector;

	return result;
}