blob: 137915cc4d27dd70ca099bc6fe2a7ab70a6fc447 [file] [log] [blame]
Julian Hall93df76a2022-09-22 17:30:06 +01001/*
2 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stddef.h>
Julian Hall4a658ac2022-10-20 10:44:49 +01008#include <stdint.h>
Julian Hall93df76a2022-09-22 17:30:06 +01009#include <drivers/io/io_storage.h>
Julian Hall4a658ac2022-10-20 10:44:49 +010010#include "block_volume.h"
Julian Hall93df76a2022-09-22 17:30:06 +010011
12/* Concrete io_dev interface functions */
Julian Hall4a658ac2022-10-20 10:44:49 +010013static io_type_t block_volume_type(
Julian Hall93df76a2022-09-22 17:30:06 +010014 void);
Julian Hall4a658ac2022-10-20 10:44:49 +010015static int block_volume_open(
Julian Hall93df76a2022-09-22 17:30:06 +010016 io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity);
Julian Hall4a658ac2022-10-20 10:44:49 +010017static int block_volume_close(
Julian Hall93df76a2022-09-22 17:30:06 +010018 io_entity_t *entity);
Julian Hall4a658ac2022-10-20 10:44:49 +010019static int block_volume_seek(
Julian Hall93df76a2022-09-22 17:30:06 +010020 io_entity_t *entity, int mode, signed long long offset);
Julian Hall4a658ac2022-10-20 10:44:49 +010021static int block_volume_size(
Julian Hall93df76a2022-09-22 17:30:06 +010022 io_entity_t *entity, size_t *length);
Julian Hall4a658ac2022-10-20 10:44:49 +010023static int block_volume_read(
Julian Hall93df76a2022-09-22 17:30:06 +010024 io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read);
Julian Hall4a658ac2022-10-20 10:44:49 +010025static int block_volume_write(
Julian Hall93df76a2022-09-22 17:30:06 +010026 io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written);
27
Julian Hall4a658ac2022-10-20 10:44:49 +010028static const io_dev_funcs_t block_volume_dev_funcs = {
29 .type = block_volume_type,
30 .open = block_volume_open,
31 .seek = block_volume_seek,
32 .size = block_volume_size,
33 .read = block_volume_read,
34 .write = block_volume_write,
35 .close = block_volume_close,
Julian Hall93df76a2022-09-22 17:30:06 +010036 .dev_init = NULL,
37 .dev_close = NULL
38};
39
Julian Hall4a658ac2022-10-20 10:44:49 +010040/* Concrete volume functions that extend the io_dev interface */
41static int block_volume_erase(
42 uintptr_t context);
43static int block_volume_get_storage_ids(
44 uintptr_t context,
45 struct uuid_octets *partition_guid,
46 struct uuid_octets *parent_guid);
Julian Hall93df76a2022-09-22 17:30:06 +010047
Julian Hall4a658ac2022-10-20 10:44:49 +010048int block_volume_init(
49 struct block_volume *this_instance,
Julian Hall93df76a2022-09-22 17:30:06 +010050 struct block_store *block_store,
51 const struct uuid_octets *partition_guid,
Julian Hall4a658ac2022-10-20 10:44:49 +010052 struct volume **volume)
Julian Hall93df76a2022-09-22 17:30:06 +010053{
Julian Hall4a658ac2022-10-20 10:44:49 +010054 /* Initialize base volume structure */
55 volume_init(
56 &this_instance->base_volume,
57 &block_volume_dev_funcs,
58 (uintptr_t)this_instance);
59
60 /* Initialize block_volume specific attributes */
61 this_instance->base_volume.erase = block_volume_erase;
62 this_instance->base_volume.get_storage_ids = block_volume_get_storage_ids;
63
Julian Hall93df76a2022-09-22 17:30:06 +010064 this_instance->block_store = block_store;
65 this_instance->partition_guid = *partition_guid;
66
67 this_instance->file_pos = 0;
68 this_instance->size = 0;
69 this_instance->partition_handle = 0;
70
71 this_instance->partition_info.block_size = 0;
72 this_instance->partition_info.num_blocks = 0;
73
Julian Hall4a658ac2022-10-20 10:44:49 +010074 *volume = &this_instance->base_volume;
Julian Hall93df76a2022-09-22 17:30:06 +010075
76 return 0;
77}
78
Julian Hall4a658ac2022-10-20 10:44:49 +010079void block_volume_deinit(
80 struct block_volume *this_instance)
Julian Hall93df76a2022-09-22 17:30:06 +010081{
82 (void)this_instance;
83}
84
Julian Hall4a658ac2022-10-20 10:44:49 +010085void block_volume_set_partition_guid(
86 struct block_volume *this_instance,
Julian Hall93df76a2022-09-22 17:30:06 +010087 const struct uuid_octets *partition_guid)
88{
89 this_instance->partition_guid = *partition_guid;
90}
91
Julian Hall4a658ac2022-10-20 10:44:49 +010092static io_type_t block_volume_type(void)
Julian Hall93df76a2022-09-22 17:30:06 +010093{
94 return IO_TYPE_BLOCK;
95}
96
Julian Hall4a658ac2022-10-20 10:44:49 +010097static int block_volume_open(
Julian Hall93df76a2022-09-22 17:30:06 +010098 io_dev_info_t *dev_info,
99 const uintptr_t spec,
100 io_entity_t *entity)
101{
Julian Hall4a658ac2022-10-20 10:44:49 +0100102 struct block_volume *this_instance = (struct block_volume *)dev_info->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100103 psa_status_t psa_status = PSA_ERROR_BAD_STATE;
104
105 psa_status = block_store_get_partition_info(this_instance->block_store,
106 &this_instance->partition_guid,
107 &this_instance->partition_info);
108
109 if (psa_status == PSA_SUCCESS) {
110
111 this_instance->file_pos = 0;
112 this_instance->size =
113 this_instance->partition_info.block_size * this_instance->partition_info.num_blocks;
114
115 psa_status = block_store_open(this_instance->block_store, 0,
116 &this_instance->partition_guid,
117 &this_instance->partition_handle);
118
119 entity->info = (uintptr_t)this_instance;
120 }
121
122 return (psa_status == PSA_SUCCESS) ? 0 : -EPERM;
123}
124
Julian Hall4a658ac2022-10-20 10:44:49 +0100125static int block_volume_close(
Julian Hall93df76a2022-09-22 17:30:06 +0100126 io_entity_t *entity)
127{
Julian Hall4a658ac2022-10-20 10:44:49 +0100128 struct block_volume *this_instance = (struct block_volume *)entity->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100129
130 psa_status_t psa_status = block_store_close(this_instance->block_store, 0,
131 this_instance->partition_handle);
132
133 if (psa_status == PSA_SUCCESS) {
134
135 this_instance->file_pos = 0;
136 this_instance->size = 0;
137 }
138
139 return (psa_status == PSA_SUCCESS) ? 0 : -ENXIO;
140}
141
Julian Hall4a658ac2022-10-20 10:44:49 +0100142static int block_volume_seek(
Julian Hall93df76a2022-09-22 17:30:06 +0100143 io_entity_t *entity,
144 int mode,
145 signed long long offset)
146{
Julian Hall4a658ac2022-10-20 10:44:49 +0100147 struct block_volume *this_instance = (struct block_volume *)entity->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100148
149 switch (mode)
150 {
151 case IO_SEEK_SET:
152 {
153 if (offset <= this_instance->size)
154 this_instance->file_pos = (size_t)offset;
155 else
156 return -EINVAL;
157 break;
158 }
159 case IO_SEEK_CUR:
160 {
161 ssize_t target_pos = this_instance->file_pos + offset;
162 if ((target_pos >= 0) && (target_pos <= this_instance->size))
163 this_instance->file_pos = (size_t)target_pos;
164 else
165 return -EINVAL;
166 break;
167 }
168 default:
169 return -EINVAL;
170 }
171
172 return 0;
173}
174
Julian Hall4a658ac2022-10-20 10:44:49 +0100175static int block_volume_size(
Julian Hall93df76a2022-09-22 17:30:06 +0100176 io_entity_t *entity,
177 size_t *length)
178{
Julian Hall4a658ac2022-10-20 10:44:49 +0100179 struct block_volume *this_instance = (struct block_volume *)entity->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100180 *length = this_instance->size;
181 return 0;
182}
183
Julian Hall4a658ac2022-10-20 10:44:49 +0100184static int block_volume_read(
Julian Hall93df76a2022-09-22 17:30:06 +0100185 io_entity_t *entity,
186 uintptr_t buffer,
187 size_t length,
188 size_t *length_read)
189{
Julian Hall4a658ac2022-10-20 10:44:49 +0100190 struct block_volume *this_instance = (struct block_volume *)entity->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100191 size_t bytes_read = 0;
192 *length_read = 0;
193
194 if (!this_instance->partition_info.block_size)
195 return -EIO;
196
197 while ((bytes_read < length) && (this_instance->file_pos < this_instance->size)) {
198
199 uint32_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
200 size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
201
202 size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
203 size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
204
205 size_t bytes_remaining = length - bytes_read;
206 if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
207
208 size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
209 bytes_remaining : bytes_remaining_in_block;
210 size_t actual_len = 0;
211
212 psa_status_t psa_status = block_store_read(
213 this_instance->block_store, 0,
214 this_instance->partition_handle,
215 lba, offset,
216 requested_len,
217 (uint8_t*)(buffer + bytes_read),
218 &actual_len);
219
220 if (psa_status != PSA_SUCCESS)
221 return -EIO;
222
223 bytes_read += actual_len;
224 this_instance->file_pos += actual_len;
225 }
226
227 *length_read = bytes_read;
228 return 0;
229}
230
Julian Hall4a658ac2022-10-20 10:44:49 +0100231static int block_volume_write(
Julian Hall93df76a2022-09-22 17:30:06 +0100232 io_entity_t *entity,
233 const uintptr_t buffer,
234 size_t length,
235 size_t *length_written)
236{
Julian Hall4a658ac2022-10-20 10:44:49 +0100237 struct block_volume *this_instance = (struct block_volume *)entity->info;
Julian Hall93df76a2022-09-22 17:30:06 +0100238 size_t bytes_written = 0;
239 *length_written = 0;
240
241 if (!this_instance->partition_info.block_size)
242 return -EIO;
243
244 while ((bytes_written < length) && (this_instance->file_pos < this_instance->size)) {
245
246 uint32_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
247 size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
248
249 size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
250 size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
251
252 size_t bytes_remaining = length - bytes_written;
253 if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
254
255 size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
256 bytes_remaining : bytes_remaining_in_block;
257 size_t actual_len = 0;
258
259 psa_status_t psa_status = block_store_write(
260 this_instance->block_store, 0,
261 this_instance->partition_handle,
262 lba, offset,
263 (uint8_t*)(buffer + bytes_written),
264 requested_len,
265 &actual_len);
266
267 if (psa_status != PSA_SUCCESS)
268 return -EIO;
269
270 bytes_written += actual_len;
271 this_instance->file_pos += actual_len;
272 }
273
274 *length_written = bytes_written;
275 return 0;
276}
Julian Hall4a658ac2022-10-20 10:44:49 +0100277
278static int block_volume_erase(uintptr_t context)
279{
280 struct block_volume *this_instance = (struct block_volume *)context;
281
282 /* Erase the entire open partition. Note that a block_store will clip
283 * the number of blocks to erase to the size of the partition so erasing
284 * a large number of blocks is a safe way to erase the entire partition.
285 */
286 psa_status_t psa_status = block_store_erase(
287 this_instance->block_store, 0,
288 this_instance->partition_handle,
289 0, UINT32_MAX);
290
291 if (psa_status != PSA_SUCCESS)
292 return -EIO;
293
294 return 0;
295}
296
297static int block_volume_get_storage_ids(
298 uintptr_t context,
299 struct uuid_octets *partition_guid,
300 struct uuid_octets *parent_guid)
301{
302 struct block_volume *this_instance = (struct block_volume *)context;
303 struct storage_partition_info partition_info;
304
305 psa_status_t psa_status = block_store_get_partition_info(this_instance->block_store,
306 &this_instance->partition_guid,
307 &partition_info);
308
309 if (psa_status == PSA_SUCCESS) {
310
311 if (partition_guid)
312 *partition_guid = partition_info.partition_guid;
313
314 if (parent_guid)
315 *parent_guid = partition_info.parent_guid;
316
317 return 0;
318 }
319
320 return -EINVAL;
321}